百度基於 Prometheus 的大規模線上業務監控實踐

語言: CN / TW / HK

Prometheus 在雲原生監控領域已經成為事實的標準。在常見的實踐案例中,更多是介紹如何做基礎的監控能力對接,很少介紹如何將 Prometheus 大規模的應用於生產環境的案例。而在現實場景中,大型網際網路公司 / 金融行業場景的大規模、高可用、高時效性、高精確度等要求,會對現有的聯邦或分散式儲存 Prometheus 解決方案帶來挑戰。

本文將會介紹,百度雲原生團隊是如何針對金融行業的場景需求,結合百度內的應用實踐經驗,構建基於 Prometheus 的大規模線上業務交易監控能力。

Prometheus 的叢集化方案分析

Prometheus 最大的優勢在於 PromQL,它提供了靈活的資料分析查詢能力,結合 Grafana 提供的儀表盤查詢,可以滿足指標監控的大部分需求。

而面向大型網際網路公司、金融行業等大規模業務監控的場景,原生的 Prometheus 單例項模式無法直接滿足需求,需要一種面向生產環境的叢集化高可用方案來進行支撐。

Prometheus 常見的叢集化高可用思路包括兩種:

一種是 Prometheus 聯邦叢集方案:

  1. Prometheus 聯邦叢集方案,是基於 Prometheus 單體模式的一種補充。可以讓一系列 Prometheus 的單體分別採集不同的目標,然後將資料統一彙總到中央的 Prometheus 叢集服務中。

  2. 在這種該方案中,中央的 Prometheus 仍然為單體模式,實際的儲存能力仍然會受到單機的限制。所以在構建聯邦模式時,需要根據資料量,對第一層的 Prometheus 所採集到的資料進行一些聚合計算,將減少後的資料傳輸到中央 Prometheus 中。故這種方案只能適用於最終需要分析的資料量偏少的場景。

  3. 同時該方案本身的維護成本頗高,需要對叢集中的每一個 Prometheus 分片採集配置、預計算配置進行管理,如要訪問除中央 Prometheus 叢集中的資料,還需記錄每一個 Prometheus 分片的訪問路由。

另一種是 Prometheus 遠端儲存方案:

  1. 遠端儲存可以提供相比單體 Prometheus,突破了單機的資源限制,能夠提供更大規模和更長時間的儲存能力。

  2. 通過這種方式,整體叢集的管理會更加簡單,只需要對 Prometheus 設定分片採集,統一將資料匯入遠端儲存即可,配置管理成本也會降低許多。

基於以上分析,可以判斷出在大規模的業務監控場景下,一種基於遠端儲存的 Prometheus 方案是必須的。但對於遠端儲存,仍然有如下問題需要解決:

  1. 遠端儲存本身仍然有容量的上限限制, 針對資料儲存時長、效能等要求,並不可能無限擴容。

  2. 儲存的資料量越大,查詢分析的壓力也就會越大, 一些涉及聚合計算曲線較多的查詢、預計算規則 (Record Rule)、報警規則 (Alert Rule) 所帶來的大量查詢,仍然會將整個叢集拖垮。

我們從兩個角度,來構建出一套解決方案:

  1. 減少指標量級: 借鑑 Prometheus 聯邦的思路,從採集層做預聚合,來減少指標量級,這個需要從業務角度來進行分析,如何針對交易量型別的指標,縮減指標量級。

  2. 提升架構效能: 從架構實現角度,如何解決單純遠端儲存無法解決的大規模資料分析和報警檢測的需求。

如何降低指標量級?

在落地實施過程中,團隊對業界的各種 Prometheus 叢集方案進行了驗證,但很不幸,在真實的量級及效能要求之下,基本處於完敗狀態。

接連碰壁之後,我們決定換一種思路:先減少資料量級,先通過一些方法把指標量降低到架構上能夠承載的程度。

經過觀察發現,業務中核心要監控的是交易量的指標,這部分指標占全部指標量的 99% 以上。之所以量級這麼大,有幾方面原因:

  1. 負責執行交易動作的模組下包含的例項數量多,每個模組下例項數量能達到幾千的級別。

  2. 指標下的維度多。一個交易請求指標,包含了分資料中心、交易型別、狀態碼、請求介面、請求來源等十餘個維度。這樣單個例項產出的指標量級就將達到數十萬量級。

減少指標量級,核心需要分析業務對於這些指標是如何進行使用的。在故障定位場景中,一般故障更容易出現在兩個角度:

  1. 單個程序例項導致的問題,不管是由於灰度的部署還是單個例項的資源不足等異常,都會體現在單例項的異常上,這時候更多的會在例項級別增加單個例項錯誤數、錯誤率、響應時間的的報警。

  2. 業務導致的問題,有些異常會出現在某種交易或某個介面上。這種異常一般是該模組全域性產生的問題,較少出現的單個例項上某種交易的異常。

指標降維

根據以上分析,我們決定對原有指標進行“降維打擊”,即減少指標包含的 Label,對相同 Label 的資料進行合併,減少最終資料量級。

根據業務的故障報警與定位的需求,對原有指標進行聚合計算,派生出如下指標:

  1. 將原有的例項與業務指標的全叉乘組合,轉換為兩種資料,即例項級指標和業務級匯聚指標。核心針對這兩種指標進行長期儲存和報警。

  2. 而對於例項叉乘業務的原始指標,根據實際的需求,在部分細節問題定位時仍然會有用,設計其進行短期儲存。

通過以上縮減思路,可以將需要長期儲存和實時報警的資料量下壓幾個量級。

架構實現上,採用 Prometheus 作為採集端,對原始指標進行全量採集,同時保留少量儲存,來儲存原始指標資料。同時對指標進行加工,降維縮減量級後,傳輸到遠端儲存服務中。

聚合運算元的選擇

業務交易量的指標型別,為 Histogram 型別,用於統計每一個模組處理交易請求的數量、響應時間,以及獲得分位值資料。

Histogram 型別包含如下指標:

  • _count:表示增加的次數,如交易量的次數,Counter 型別。

  • _sum:表示增加的總耗時,如交易的總耗時,Counter 型別。

  • _bucket:表示在不同耗時分桶區間內,增加的次數,如在 0-500ms 內的交易量次數。同樣為 Counter 型別。

在做降維計算時,我們一開始想到了使用 sum 聚合函式。則根據之前所講的聚合思路,分別聚合到例項級和業務級,可以寫出如下的聚合規則:

以上規則正確嗎?

答案是否定的,對 Counter 資料的直接求 sum 會導致最終資料錯誤。

原因在於 Counter 指標的特殊性:

  1. Counter 指標是一個遞增值,會記錄從服務啟動到現在的總量

  2. 當出現服務重啟時,Counter 指標會從 0 開始重新計數

這種特別的設計,也帶來了特別的使用方法:

  1. 由於 Counter 持續遞增的特徵,直接使用 Counter 指標沒有意義,需要使用運算元獲得前後兩個值的差值。如 Prometheus 中提供了 increase、rate、irate、delta 等運算元,專用於處理 Counter 型別的資料。

  2. 由於 Counter 值在服務重啟時會重新從 0 計數,會導致資料不再遞增,此事如果做差值計算,會出現負值的情況。Prometheus 的上述運算元對這種情況進行了特殊處理,當發現前後點差值為負數,會認為該資料出現了重置,則會使用後一個點的值減去 0,作為該點的實際增量。

基於以上特徵,當我們直接使用 sum 運算元將多個例項的曲線加和後,其中一個例項的重啟,就會導致整體的資料出現後值小於前值的情況,基於 Prometheus 運算元實現原理,斷崖部分會使用後者值直接減去 0,遠比實際值要高很多,出現突增。

那麼如何解決這個問題?

我們選擇 繞過 Counter 指標。在聚合計算時,首先將 Counter 指標進行差值計算,轉換為 Gauge 資料,獲得週期內的增量,然後對這個 Gauge 資料進行 sum 聚合。就可以避免 increase、rate 等運算元的特殊行為。

具體更換後運算元如下(以採集週期為 5s 舉例):

  1. 其中內層用於將 Counter 指標轉換為按照週期的 Gauge 增量指標:

  • rate 表示求週期內的增長速率,由於 rate 等運算元,必須包含兩個點來進行計算,在 5s 採集週期下,填入 10s 的視窗來保證這個條件。

  • *5 表示將速率轉換為 5s 週期內的變化量。

  1. 外層的 sum,表示對內層產生的 Gauge 指標進行聚合。

則正確的計算任務修改為如下規則:

自動擴充套件的分片採集

使用一個 Prometheus 叢集來滿足對業務所有服務 Exporter 的監控,這就涉及如何做分片管理。

應對方法是建設獨立的 Prometheus 採集分片管理服務,Prom-Scheduler 與 Prom-Agent 服務:

  • Prom-Scheduler 負責基於採集任務,進行任務分配。同時通過定期的對採集端點進行探測,獲得 Exporter 產出的指標量級,根據 Exporter 的指標量級進行任務負載均衡。

  • Prom-Agent 則與 Prometheus 採集服務一同部署,負責管理該分片 Prometheus 的採集配置。

整個 Prometheus 採集服務使用 Kubernetes 進行部署,在資源情況允許的情況下,通過對採集指標量級的監控,實現自動的採集服務擴縮容。

根據上文所述的預聚合需求,針對不同場景拆分了兩個 Prometheus 採集叢集,應用不同的自動分配演算法來滿足不同場景的自動伸縮監控需求。

交易服務 Prometheus 採集叢集:

  • 針對包含業務指標的服務監控,採用按 App 自動分片採集,同一個 App 所屬的例項 Exporter 分配在同一組 Prometheus 採集服務上

  • 同一個 App 的指標能夠基於預計算規則儘量減少量級。

對於非交易服務 Prometheus 採集叢集:

  • 通過計算每個 Exporter 產生的指標數量,負載均衡到 Prometheus 叢集中,實現分片採集。

  • 其中 Exporter 的指標量級,通過定期對目標端點進行探測,來獲取指標量級的變化。

流式計算的引入

通過指標降維的方案實現了指標的減量,但不幸的是,減量後的指標量級,仍然超過了遠端儲存服務能夠承載的上限。尤其是儲存服務上的計算規則 (Record Rule) 和報警規則 (Alert Rule) 由於涉及資料量大,常處於超時狀態。

因此我們引入了 Flink 構建流式計算服務,承接原有由儲存服務支援的預計算和報警閾值檢測能力,降低對於儲存的查詢時計算壓力。

基於流式計算的特徵,業務所提出的計算、報警低延遲的需求也同樣得到了滿足。

整體架構方案如下圖所示:

採集服務:

  1. 使用 Prometheus 作為採集服務,額外增加自動分片管理能力,實現對業務模組、中介軟體等 Exporter 進行自動發現與資料採集。

  2. 同時如上文所述,該部分同時會進行業務指標進行降維計算,使得傳送到監控資料通路的資料進行。

轉發服務:

  1. Prometheus 資料傳送到 Adaptor 服務,Adaptor 服務負責將 Prometheus 傳送的資料,轉發到 Kafka 對應的 topic 中。Flink 流式計算服務及儲存服務可以從 Kafka 中訂閱所需的資料。

  2. 轉發服務同時構建了高可用資料去重的方案,該部分會在後續的文章中具體進行介紹。

流式計算服務:

  1. 基於 Flink 構建的流式計算服務,負責執行使用者配置的 Record Rule 和 Alert Rule,將計算結果寫回 Kafka。

  2. 在 Flink 運算元的實現中,通過對原有的 Prometheus 運算元針對流式計算進行並行化重寫,實現了流式計算算力的提升。

儲存服務:

  1. 遠端儲存服務使用了百度自研的時序資料儲存方案,遠端儲存服務實現了 Prometheus remote-write 介面與 Kafka 訂閱兩種模式,滿足不同場景的資料接入需求。

  2. 查詢層,實現了與 Prometheus 相容的 PromQL 查詢引擎與介面實現。能夠無縫對接 Grafana 等查詢服務。

  3. 同時基於 Prometheus 的資料模型,增加了資料多層級降取樣等特徵,來滿足長時間儲存需求。

報警服務:

  1. 報警服務採用了百度自研的報警事件及通告管理服務,相比原生 Prometheus 中 AlertManager 偏薄弱的基礎告警通知能力,自研的 Alert Service 對告警通知、告警處置、告警渠道管理,及 AIOps 故障分析定位能力進一步增強。滿足使用者告警處理需求。

結    語

在本文中,我們初步介紹了針對大規模的業務監控場景,百度雲原生團隊基於 Prometheus 技術方案進行的一些探索。包括基於 Prometheus 進行指標降維、Prometheus 的自動分片採集、以及基於 Flink 流式計算構建的預計算與報警規則替代方案。

在後續的系列文章中,我們將對該場景進一步進行分析,從資料採集、計算、儲存和報警等各環節技術細節出發,繼續探討如何基於 Prometheus 構建高效能、低延遲、高可用的監控系統,敬請期待。