Loki 是 Grafana Labs 在 2018 年開源的 Log Aggregation System,主打輕量、易用、成本低,並且具備高可用與水平擴展能力。它從 Prometheus 借鑑了不少設計理念:對時間與標籤建立索引、推出類 PromQL 的查詢語言 LogQL,讓熟悉 Metrics 工作流的使用者能無痛接手 Logs 場景。
Loki 主要負責接收 Log、把資料寫入物件儲存(Object Storage),再透過 API 供 Grafana 查詢。資料的「進來」這一段則交給多種收集工具負責,包括官方專屬的 Promtail、後續章節會介紹的 Fluent Bit 與 Vector,以及專為 Docker Container 設計、不需另外安裝 Agent 的 Loki Docker Driver。
核心概念#
Label#
Loki 沿用 Prometheus 的 Label 概念,透過標籤索引(Label Indexing)讓使用者以 Label Selector 撈出特定 Log Stream。Label 是 Key-Value 結構,例如 app=nginx、level=INFO、host=web01。
收集端負責標上這些標籤:以 Loki Docker Driver 為例,會自動加上 compose_service、container_name、compose_project、filename 等;如果改用 Promtail、Fluent Bit、Vector,則需要在工具自己的設定中明確定義。
標籤設計不當會直接讓 Loki 效能崩盤。官方文件 Label best practices 的核心建議是:避免使用基數過高(high cardinality)的欄位作為 Label,例如 User ID、Trace ID、HTTP Status Code,否則索引會迅速膨脹。動態值請改用查詢時的解析器(Parser)動態生成 Label,而不是在寫入時就固化下來。
LogQL#
LogQL 是 Loki 的查詢語言,語法與 PromQL 高度相似,並可透過 |(Pipe)串接多個處理階段,操作邏輯接近 Linux Pipeline。
Log Selector#
每一條 LogQL 查詢都至少要選一個 Label,包在 {} 內:
{job="analyze"}多個 Label 條件以 , 串連:
{job="analyze", service="loki"}可用的比較符號包含 =、!=,以及搭配正規表示式的 =~、!~,例如 {name=~"mysql.+"}。
文字內容篩選#
Label 選定 Log Stream 後,可以用四種運算子做內容篩選:
|=:包含指定字串。!=:不包含指定字串。|~:符合指定的正規表示式。!~:不符合指定的正規表示式。
{job="analyze"} |= "Logs"
{job="analyze"} != "Logs"
{job="analyze"} |~ "info|error"
{job="analyze"} !~ "info|error"實務上單筆 Log 通常還需要前後文,Grafana Explore 提供 Show Context 功能,可以展開該筆事件的相鄰 Log,協助釐清問題脈絡。
Log Parser#
針對半結構化或結構化 Log,LogQL 提供解析器(Parser)將內容拆解成可查詢的欄位,常見的有 logfmt、json、regexp、pattern。解析後就可以像查資料庫欄位一樣使用:
{job="analyze"} | logfmt | level = "info"若覺得原始格式不易閱讀,也可以用 line_format 重新拼出顯示版本:
{job="analyze"} | logfmt | line_format "Level:{{.level}} Log:{{.msg}}"pattern 解析器則特別適合具有固定欄位順序的訪問日誌,例如 Nginx Access Log。透過 <name> 命名欄位、<_> 略過欄位的方式比寫正規表示式直觀許多:
{job="analyze"} | pattern "<_> - <_> <_> \"<method> <url> <protocol>\" <status> <_> <_> \"<_>\" <_>" | status >= 200 and status < 300查詢效能技巧#
Loki 標榜查詢快,但實際速度仍取決於使用者怎麼寫 LogQL。官方部落格曾整理出幾項實用建議:
- Label 選擇盡量精確:搭配多個 Label 一起使用,例如
{job="analyze", service="loki"},先把資料量壓小再做後續處理。 - 善用 Line Filter:用多組
|=串接,例如{job="analyze"} |= "/api/" |= "requests",比寫一條複雜的正規表示式更快。 - 縮小時間範圍:實務查詢很少需要動輒幾天的窗口,縮短時間範圍能顯著降低掃描成本。
- 先過濾再解析:先以文字篩掉不需要的 Log,再丟進
logfmt、json等較重的 Parser。
儲存設計#
Loki 只對時間與 Label 建索引,而不像 Elasticsearch 對所有欄位建立倒排索引,因此索引體積非常小,官方曾舉例「10TB 的 Log,索引大約只需 20MB」。剩餘的內容則經過壓縮存放,再寫入物件儲存。
支援的物件儲存包含 AWS S3、Google Cloud Storage、Azure Blob Storage,以及 S3 相容服務如 MinIO,能進一步降低長期保存的成本。
Loki Docker Driver#
Loki Docker Driver 利用 Docker 的 Logging Driver 機制,把 Container 的 STDOUT/STDERR 直接送進 Loki,本質上可以視為一個特化版的 Promtail。它會自動帶上 compose_service、container_name、compose_project、filename、host、source 等 Label,讓使用者一上手就能用熟悉的 Compose 詞彙做查詢,特別適合作為入門 Loki 的第一站。
與 Prometheus 的淵源#
Loki 大量沿用 Prometheus 概念並非偶然。它由 Tom Wilkie 與 David Kaltschmidt 發起,兩人皆曾在 Weaveworks 參與 Cortex 與 Prometheus 相關工作,後來共同創立 Kausal,在 2018 年被 Grafana Labs 收購後,Loki 才以獨立產品亮相。
小結#
歷經數年發展,Loki 已是穩定成熟的 Log Aggregation System:對 Prometheus 使用者極其友善、生態系(Promtail、Fluent Bit、Vector)齊全、儲存成本低廉,連 Red Hat 的 OpenShift 都提供 Loki Operator。當你下次需要替系統挑一套 Log 後端時,Loki 很可能會是預設候選之一。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10330843