如何用 LogQL 在幾秒內查詢 TB 級的日誌

LogQL 在很大程度上受 Prometheus 的 PromQL 啓發。但是,當涉及到在過濾海量日誌時,我們就像面臨在大海撈針一樣複雜。LogQL 是 Loki 特有的語句,在本文中,我們將提供 LogQL 的快速過濾器查詢技巧,這些查詢可以在幾秒鐘內過濾掉數 TB 的數據。

在 Loki 中,我們可以使用三種類型的過濾器:

Label matchers

Label matchers(標籤匹配器)是你的第一道防線,是大幅減少你搜索的日誌數量(例如,從 100TB 到 1TB)的最好方法。當然,這意味着你需要在的日誌採集端上有良好的標籤定義規範。基本上,標籤應該定義的類型包括,工作負載、集羣、命名空間和容器等,這樣你就可以在多個不同的維度上對數據進行切分。比如說

一個有效的經驗法則是:你至少需要一個=匹配器(例如,{cluster="us-central1"})。否則,你將不得不提取整個索引數據。

但有一個例外。如果匹配器包含一個或多個字元,比如{container=~"promtail|agent"},同時只有一個單一的 regex 匹配器,Loki 可以自行優化查詢

下面就是一些實用的樣例:

好例子:

{cluster="us-central1"}

{container="istio"}

{cluster="us-central1"container=~"agent|promtail"}

壞例子:

{job=~".*/queue"}

{namespace!~"dev-.*"}

Line filters

Line filters(行過濾器)是您的第二個好朋友,因爲它們執行過程超級快。它允許你過濾包含 (|=) 或不包含 (!=) 字符串的日誌,你也可以使用正則來匹配 (|~) 或不匹配 (!~) 日誌,但你應該把它們放在標籤匹配器之後

現在,當我們將這些過濾器連起來使用時,要注意過濾器的順序。先用那些能過濾最多日誌的過濾器,然後再使用正則,它比=!=慢。

但有一個例外。|~ "error|fatal "可以被 Loki 優化掉 實際上這兩個字符串被 loki 自動過濾掉了,所以不會執行正則匹配

一個好的方法是先添加一個符合你要找的東西的過濾器,例如,|= "err"。然後再添加越來越多的不等式來過濾你不想要的東西,直到最終得到類似於下面這樣的結果

|= "err" != "timeout" != "cancelled" |"failed.*" != "memcached"

現在,如果你意識到你的大部分錯誤來自 memcached,那麼就把它移到第一個位置

!= "memcached" |= "err" != "timeout" != "cancelled" |"failed.*"

這樣一來,後續過濾器的執行次數就會減少。

除此之外,行過濾器也很適合查找 IP、TraceID、UUID 等類型的日誌。比如下面這個也一個很好的查詢方式

{namespace="prod"} |= "traceID=2e2er8923100"

如果你想讓這個 traceID 的所有日誌都符合某個 regex,可以在 ID 過濾器後面加上|~ "/api/v.+/query",這樣就不會對 prod 命名空間的每個 pod 中去添加查詢。

Label filters

Label filters(標籤過濾器)提供了更復雜的計算功能(duration,numerical 等),但是它們通常需要先提取標籤,然後再將標籤值轉換爲另一種類型。這意味着它們通常是最慢的,因此我們應該最後使用它們

實際上我們可以在不提取標籤的情況下使用標籤過濾器(使用|json|logfmt等解析器)。標籤過濾器也可以在索引標籤上工作。例如,{job="ingress/nginx"}。| status_code >= 400 and cluster="us-central2"可以正常工作,但你真正應該問自己的是,你是否需要將 status_code 作爲索引標籤。一般來說,你不應該,但你可以考慮提取 status_code 作爲標籤,這可以將大批量的流(每秒超過一千行)分解成獨立的流。

儘管| json| logfmt解析器很快,但是解析| regex卻很慢。這就是爲什麼在使用解析器時,我總是在它前面加上一個行過濾器。例如,在我的 Go 應用程序(包括 Loki)中,我的所有日誌均支持顯示文件名和行號(此處爲caller=metrics.go:83)

level=info ts=2020-12-07T21:03:22.885781801Z caller=metrics.go:83 org_id=29 traceID=4078dafcbc079822 latency=slow query="{cluster=\"ops-tools1\",job=\"loki-ops/querier\"} != \"logging.go\" != \"metrics.go\" |= \"recover\"" query_type=filter range_type=range length=168h0m1s step=5m0s duration=54.82511258s status=200 throughput=8.3GB total_bytes=454GB

因此,當我們想過濾緩慢的請求時,應該先對記錄文件和行號進行過濾,然後再進行解析,最後再將提取的標籤進行比較。

{namespace="loki-ops",container="query-frontend"} 
|= "caller=metrics.go:83" 
| logfmt 
| throughput > 1GB and duration > 10s and org_id=29

結論

這三個過濾器(Label matchers,Line filters 和 Label filters)就像一個管道,將逐步處理日誌。我們應該嘗試在每個步驟上儘可能減少操作,因爲對於每個行,每個後續步驟執行的速度都可能更慢。

關注公衆號【雲原生小白】,回覆「入羣」加入 Loki 學習羣

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/EU_RgbOX2yjtVQTzas1tsA