Prometheus 源碼解讀(一)

  • 2019 年 10 月 24 日
  • 筆記

Prometheus 源碼解讀(一)

Prometheus 是雲原生監控領域的事實標準,越來越多的開源項目開始支援 Prometheus 監控數據格式。從本篇開始,我將和大家一起閱讀分析 Prometheus 源碼。學習 Prometheus 的設計理念,了解 Prometheus 的局限性與不足。本系列分八個板塊逐一拆解 Prometheus 源碼。本文基於 Prometheus v2.13.0。

  • 工作原理與架構
  • 時序資料庫模組(TSDB)
  • 配置文件載入模組(Configuration Reloader)
  • 服務發現模組(Service Discovery Manager)
  • 數據抓取模組(Scrape Manager)
  • RES API 模組(Web Handler)
  • 查詢引擎(Query Engine & PromQL)
  • 性能與優劣勢總結

1. Prometheus 介紹

Prometheus 是基於時序資料庫(Time Series Database, TSDB)的監控告警系統。Prometheus 在 2016 年加入 CNCF 基金會,成為繼 Kubernetes 後第二個畢業項目,其火熱程度可見一斑。相比於傳統的監控方案,Prometheus 有以下幾個優勢:

  • 高效的存儲引擎

Prometheus 將監控指標以時序數列的格式存儲在時序資料庫 TSDB 中。相比於傳統的關係型資料庫,時序資料庫便於對已有數據進行聚合;在高並發的情況下,讀寫性能也遠高於關係型資料庫。Prometheus 2.0 版本重構了底層時序存儲引擎。目前,單個 Prometheus 伺服器可以做到每秒存儲百萬條指標數據,同時佔用磁碟空間也很小

  • 強大的查詢能力:PromQL

Prometheus 有獨立的 PromQL 查詢語言,另外還提供了很多內置的基於時間的處理函數,降低數據聚合的難度

Prometheus Console

  • 面向服務的架構

Prometheus 採用拉模型收集時序數據,數據拉取行為是由服務端來決定的。服務端可以通過某種服務發現機制來自動發現監控對象。而對於推模型的監控系統,客戶端需要負責在服務端上進行註冊及監控數據推送,這在微服務架構里實現起來比較難的。當大量客戶端向服務的主動推送數據時,服務端的壓力較大

Prometheus Console

  • 與 Kubernetes 天然集成

Kubernetes 本身的指標也是以 Prometheus 格式暴露出來的

  • 逐步完善的生態

OpenMetrics:Prometheus 的數據格式逐漸成為一種標準。OpenMetrics 正在從 Prometheus 的數據格式中分離出來,逐漸成為監控數據格式的國際標準

Thanos:支援數據存儲的可伸縮,彌補 Prometheus 數據持久化方面的不足Prometheus

Prometheus Operator:簡化 Prometheus 配置管理

2. 架構分析

圖的左邊開始是監控數據源。任何應用服務想要接入 Prometheus,都需要提供 HTTP 介面(通常是 x.x.x.x/metrics 地址),並暴露 Prometheus 格式的監控數據。Prometheus Server 通過 HTTP 協議周期性抓取監控目標的監控數據、打時間戳、存儲到本地。Prometheus 提供了 Client 庫幫助開發人員在自己的應用中集成符合 Prometheus 格式標準的監控指標。

而對於不適合直接在程式碼中集成 Client 庫的場景,比如應用來自第三方、不是由自己維護,應用不支援 HTTP 協議,那就需要為這些場景單獨編寫 Exporter 程式。Exporter 作為代理,把監控數據暴露出來。比如 Mysql Exporter,Node Exporter。

Prometheus 將採集到的數據存儲在本地時序資料庫中,但缺少數據副本。這也是 Prometheus 自身在數據持久化方面做的不足的地方。但這些存儲問題都有其他的解決方案,Prometheus 支援 remote write 方式將數據存儲到遠端。

Prometheus 支援通過 Kubernetes、靜態文本、Consul、DNS 等多種服務發現方式來獲取抓取目標(targets)。最後,用戶編寫 PromQL 語句查詢數據並進行可視化。

Prometheus架構

3. 核心組件

Prometheus 的功能由多個互相協作的組件共同完成。這些組件也即本文開頭所列出的模組,比如 Service Discovery Manager。我們後續會逐一介紹。Prometheus 源碼入口 main() 函數 完成參數初始化工作,並依次啟動各依賴組件。

首先,main 函數解析命令行參數(詳見附錄 A),並讀取配置文件資訊(由 –config.file 參數提供)。Prometheus 特別區分了命令行參數配置(flag-based configuration)和文件配置(file-based configuration)。前者用於簡單的設置,並且不支援熱更新,修改需要啟停 Prometheus Server 一次;後者支援熱更新。

main 函數完成初始化、啟動所有的組件。這些組件包括:Termination Handler、Service Discovery Manager、Web Handler 等。各組件是獨立的 Go Routine 在運行,之間又通過各種方式相互協調,包括使用 Channel、引用對象 Reference、傳遞 Context(Context 包的使用可以參考作者的 《Golang Context 包詳解》一文)。

這些 Go Routine 的協作使用了 oklog/run 框架。oklog/run 是一套基於 Actor 設計模式的 Go Routine 編排框架,實現了多個 Go Routine 作為統一整體運行並有序依次退出。這在很多開源項目中都有使用,進一步了解可參考作者的另一篇文章《Go routine 編排框架:oklog/run 包》

Prometheus核心組件

4. 參考文檔

「K8S 技術落地實踐」Prometheus 在 K8S 上的監控實踐 來自本文作者在杭州容器 Meetup 的分享

Prometheus Internal architecture

附錄 A:Prometheus 啟動參數

  • web:Prometheus 伺服器 HTTP 連接參數,REST API 啟用相關參數,Prometheus Console 網頁配置
  • storage:TSDB 相關配置
  • query:查詢執行相關配置
參數名 解釋
config.file 配置文件的位置,包含抓取監控對象列表(用於服務發現)和 recording rules 文件位置
web.listen-address Prometheus server 端監聽請求(API 請求、Dashboard 介面)的地址和埠,默認本地埠 9090
web.read-timeout 設置 Prometheus server 讀取客戶端請求的超時時間。以此來避免客戶端因超慢的寫操作,長時間佔用鏈接資源。ReadTimeout 覆蓋了從連接請求被接受到請求報文被完全讀取的時間。默認 5m
web.max-connections 最大連接數,默認 512
web.external-url 設置 Prometheus 對外的 URL。需要設置外部訪問的 Prometheus 通常因為啟用了反向代理。如果 external-url 包含路徑,則 Prometheus 所有對外的介面,都會帶上該路徑作為前綴。eg. http://<host>:<port>/<path>/api/v1/query?query=up
web.route-prefix 用於替換 external-url 的路徑前綴,eg. http://<host>:<port>/<route-prefix>/api/v1/query?query=up
web.user-assets 網頁靜態 asset 文件夾路徑
web.enable-lifecycle 開啟後,可以實現通過請求 /-/reload 熱載入更新配置,默認 false
web.enable-admin-api 開啟後,允許使用一些管理員級別的 api,包括刪除時間序列等,/api/v1/admin/tsdb/delete_series。默認 false
web.console.templates Prometheus Console 網站模板文件夾路徑
web.console.libraries Prometheus Console 使用的庫路徑
web.page-title Console 頁面標題
web.cors.origin 設置 Prometheus 服務端允許的域,用正則表達式表示。eg. https?://(domain*).com
storage.tsdb.path 監控數據存儲路徑,默認 data/
storage.tsdb.min-block-duration 設置數據塊最小時間跨度,默認 2h 的數據量。監控數據是按塊(block)存儲,每一個塊中包含該時間窗口內的所有樣本數據(data chunks)
storage.tsdb.max-block-duration 設置數據塊最大時間跨度,默認為最大保留時間的 10%
storage.tsdb.wal-segment-size 設置 WAL 分段存儲每個分段的大小。默認 128MB
storage.tsdb.retention.time 監控數據最大保留時間,默認 15d
storage.tsdb.no-lockfile 不在數據存儲目錄中創建文件鎖
storage.tsdb.wal-compression 開啟後,會對 WAL 文件進行壓縮(成本是帶來 CPU 開銷)。默認 false
storage.remote.flush-deadline
storage.remote.read-sample-limit 一次最多從遠端存儲中讀取取樣數據量,默認 5e7 條,0 表示無限制
storage.remote.read-concurrent-limit 最大並發讀,默認 10 個請求,0 表示無限制
rules.alert.for-outage-tolerance
rules.alert.for-grace-period
rules.alert.resend-delay
alertmanager.notification-queue-capacity
alertmanager.timeout
query.lookback-delta 在計算 PromQL 表達式結果時,最大回看時間
query.timeout 查詢超時時間
query.max-concurrency 最大並發處理查詢請求數,默認 20 個請求
query.max-samples 能載入到記憶體中最大取樣數據量,默認 5e7 條