Grafana 系列文章(九):開源雲原生日誌解決方案 Loki 簡介

東風微鳴發表於2023-02-06

簡介

Grafana Labs 簡介

Grafana 是用於時序資料的事實上的儀表盤解決方案。它支援近百個資料來源。
Grafana Labs 想從一個儀表盤解決方案轉變成一個可觀察性 (observability) 平臺,成為你需要對系統進行除錯時的首選之地。

完整的可觀察性

可觀察性。關於這意味著什麼,有很多的定義。可觀察性就是對你的系統以及它們的行為和表現的可見性。典型的是這種模式,即可觀察性可以分成三個部分(或支柱):指標 (Metrics)、日誌 (Logs) 和跟蹤 (Traces);每個部分都相互補充,幫助你快速找出問題所在。

下面是在 Grafana Labs 部落格和演講中反覆出現的一張圖:

今天的現實:不同的系統,不同的資料

Slack 向我發出警告,說有問題,我就開啟 Grafana 上服務的相關儀表盤。如果我發現某個皮膚或圖表有異常,我會在 Prometheus 的使用者介面中開啟查詢,進行更深入的研究。例如,如果我發現其中一個服務丟擲了 500 個錯誤,我會嘗試找出是否是某個特定的處理程式/路由丟擲了這個錯誤,或者是否所有的例項都丟擲了這個錯誤,等等。

接下來,一旦我有了一個模糊的心理模型,知道什麼地方出了問題,我就會看一下日誌(比如在 splunk 上)。在 Loki 之前,我習慣於使用 kubectl 來獲取相關的日誌,看看錯誤是什麼,以及我是否可以做些什麼。這對錯誤來說很有效,但有時我會因為高延遲而放棄。之後,我從 traces (比如 AppD) 中得到更多的資訊,關於什麼是慢的,哪個方法/操作/功能是慢的。或者使用 Jaeger 來獲得追蹤資訊。

雖然它們並不總是直接告訴我哪裡出了問題,但它們通常讓我足夠近距離地檢視程式碼並找出哪裡出了問題。然後,我可以擴充套件服務(如果服務超載)或部署修復。

Loki 專案背景

Prometheus 工作得很好,Jaeger 也漸入佳境,而 kubectl 也很不錯。標籤 (label) 模型很強大,足以讓我找到出錯服務的根源。如果我發現 ingester 服務在出錯,我會做:kubectl --namespace prod logs -l name=ingester | grep XXX,以獲得相關的日誌,並透過它們進行 grep。

如果我發現某個特定的例項出錯了,或者我想跟蹤某個服務的日誌,我必須使用單獨的 pod 來跟蹤,因為 kubectl 不允許你根據標籤選擇器來跟蹤。這並不理想,但對於大多數的使用情況來說是可行的。

只要 pod 沒有崩潰或者沒有被替換,這就可以了。如果 pod 或節點被終止了,日誌就會永遠丟失。另外,kubectl 只儲存最近的日誌,所以當我們想要前一天或更早的日誌時,我們是盲目的。此外,不得不從 Grafana 跳到 CLI 再跳回來的做法並不理想。我們需要一個能減少上下文切換的解決方案,而我們探索的許多解決方案都非常昂貴,或者不能很好地擴充套件。

這是意料之中的事,因為它們比 select + grep 做得更多,而這正是我們所需要的。在看了現有的解決方案後,Grafana Labs 決定建立自己的。

Loki

由於對任何開源的解決方案都不滿意,Grafana Labs 開始與人交談,發現很多人都有同樣的問題。事實上,Grafana Labs 已經意識到,即使在今天,很多開發人員仍然在 SSH 和 grep/tail 機器上的日誌。他們所使用的解決方案要麼太貴,要麼不夠穩定。事實上,人們被要求減少日誌,Grafana Labs 認為這是一種反模式的日誌。Grafana Labs 認為可以建立一些 Grafana Labs 內部和更廣泛的開源社群可以使用的東西。Grafana Labs 有一個主要目標:

  • 保持簡單。只支援 grep!

這條來自@alicegoldfuss 的推文並不是支援 Loki,只是為了說明 Loki 試圖解決的問題

Grafana Labs 還瞄準了其他目標:

  • 日誌應該是便宜的。不應要求任何人少記錄日誌。
  • 易於操作和擴充套件
  • 指標 (Metrics)、日誌 (Logs)(以及後來的追蹤 (traces))需要一起工作

最後一點很重要。Grafana Labs 已經從 Prometheus 收集了指標的後設資料,所以想利用這些後設資料進行日誌關聯。例如,Prometheus 用 namespace、service name、例項 IP 等來標記每個指標。當收到警報時,使用後設資料來找出尋找日誌的位置。如果設法用同樣的後設資料來標記日誌,我們就可以在度量和日誌之間無縫切換。你可以在 這裡 看到 Grafana Labs 寫的內部設計文件。下面是 Loki 的演示影片連結:

?️Loki 演示影片

架構

根據 Grafana Labs 建立和執行 Cortex 的經驗--作為服務執行的 Prometheus 的水平可擴充套件的分散式版本--想出了以下架構:

Loki 架構

指標和日誌之間的後設資料匹配對我們來說至關重要,Grafana Labs 最初決定只針對 Kubernetes。想法是在每個節點上執行一個日誌收集代理,用它來收集日誌,與 kubernetes 的 API 對話,為日誌找出正確的後設資料,並將它們傳送到一箇中央服務,可以用它來顯示在 Grafana 內收集的日誌。

該代理支援與 Prometheus 相同的配置(relabelling rules),以確保後設資料的匹配。我們稱這個代理為 promtail。

深入 Loki —— 可擴充套件的日誌收集引擎:

Loki 內部架構

寫入路徑和讀取路徑(查詢)是相互脫鉤的,分開說明:

Loki 寫入路徑

Distributor(分發器)

一旦 promtail 收集併傳送日誌到 Loki,Distributor 是第一個接收日誌的元件。現在,Loki 可能每秒收到數百萬條寫,我們不想在它們進來時就把它們寫到資料庫中。那會搞宕任何資料庫。需要在資料進入時對其進行批處理和壓縮。

Grafana Labs 透過構建壓縮的資料塊 (chunks),透過 gzip 壓縮日誌來實現這一點。ingester(採集器) 元件是一個有狀態元件,負責構建塊,然後再重新整理塊。Loki 有多個 ingester,屬於每個流的日誌應該總是在同一個 ingester 中結束,因為所有相關條目都在同一個塊中結束。透過構建一個 ingester 環 (ring) 並使用一致性雜湊來做到這一點。當有條目進入時,分 Distributor 對日誌的標籤進行雜湊處理,然後根據雜湊值查詢將條目傳送到哪個 ingester。

Loki Distributor 元件

此外,為了實現冗餘和彈性,Loki 將其複製了 n 次(預設為 3 次)。

Ingester(採集器)

現在,Ingester 將接收條目並開始構建塊。

Loki Ingester 構建 chunks

這基本上是對日誌進行 gzip 處理並追加。一旦塊 "填滿 "了,我們就把它刷到資料庫中。我們為塊(ObjectStorage)和索引使用不同的資料庫,因為它們儲存的資料型別是不同的。

Loki Ingester 構建好 chunks, 將 index 刷到索引庫,將 chunks 刷到 chunks 庫

刷完一個塊後,Ingester 會建立一個新的空塊,並將新條目新增到該塊中。

Querier(查詢器)

讀取路徑非常簡單,由 Querier 來完成大部分繁重的工作。給定一個時間範圍和標籤選擇器,它檢視索引以找出匹配的塊,並透過它們進行搜尋,給你結果。它還與 ingesters 對話,以獲得尚未被刷到庫中的最新資料。

請注意,在 2019 年版本中,對於每個查詢,一個 Ingester 為你搜尋所有相關的日誌。Grafana Labs 已經在 Cortex 中使用前端實現了查詢並行化,同樣的方法可以擴充套件到 Loki,以提供分散式的 grep,這將使大型查詢變得足夠迅速。

Loki Querier 元件

可伸縮性

  1. Loki 把塊的資料放到物件儲存中,這樣就可以擴充套件了。
  2. Loki 把索引放到 Cassandra/Bigtable/DynamoDB 或 Loki 內建的 index db 中,這也是可以擴充套件的。
  3. Distributors 和 Queriers 是無狀態元件,可以橫向擴充套件。

說到 ingester,它是一個有狀態的元件,但 Loki 已經將完整的分片和重新分片的生命週期納入其中。當 rollout 工作完成後,或者當 ingester 被擴大或縮小時,環形拓撲結構會發生變化,ingester 會重新分配它們的塊,以匹配新的拓撲結構。這主要是取自 Cortex 的程式碼,它已經在生產中執行了 5 年多。

總結

Loki: like Prometheus, but for logs.

Loki 是一個水平可擴充套件、高可用、多租戶的日誌聚合系統,其靈感來自於 Prometheus。它被設計成非常具有成本效益和易於操作。它不對日誌的內容進行索引,而是為每個日誌流提供一組標籤。

Grafana 系列文章

Grafana 系列文章

三人行, 必有我師; 知識共享, 天下為公. 本文由東風微鳴技術部落格 EWhisper.cn 編寫.

相關文章