Micrometer:Spring Boot 2 新的應用指標收集器

工程 | Jon Schneider | 2018 年 3 月 16 日 | ...

目錄

它是什麼?

Micrometer 是一個維度優先(dimensional-first)的指標收集外觀(facade),旨在透過一個供應商中立的 API 來幫助你對程式碼進行計時、計數和測量。透過 classpath 和配置,你可以選擇一個或多個監控系統來匯出你的指標資料。想象一下,它就像 SLF4J,但用於指標!

Micrometer 是 Spring Boot 2 的 Actuator 中包含的指標收集工具。透過新增額外的依賴,它也已被反向移植到 Spring Boot 1.5、1.4 和 1.3 版本。

Micrometer 在 Spring Boot 1 中已有的計數器(counters)和測量器(gauges)基礎上添加了更豐富的儀表元語(meter primitives)。例如,一個 Micrometer Timer(計時器)能夠生成與吞吐量、總時間、近期樣本的最大延遲、預計算的分位數、分位數直方圖以及 SLA 邊界計數相關的時序資料。

An Kibana-rendered timer

儘管專注於維度指標,Micrometer 仍然可以對映到分層名稱,以繼續支援像 Ganglia 這樣的舊式監控解決方案或像 JMX 這樣範圍較窄的工具。向 Micrometer 的轉變源於更好地服務於一系列維度監控系統(如 Prometheus、Datadog、Wavefront、SignalFx、Influx 等)的需求。Spring 的一個優勢是透過抽象實現選擇自由。透過與 Micrometer 整合,Spring Boot 使你今天能夠選擇使用一個或多個監控系統,並且隨著需求的改變,將來可以改變選擇,而無需重寫你的自定義指標檢測程式碼。

在決定開發“又一個”指標收集庫之前,我們認真研究了現有或新興的維度收集器。但當我們研究如何匯出到越來越多的監控系統時,名稱和資料結構的重要性變得顯而易見。Micrometer 構建了命名規範化、時間單位基礎縮放以及對直方圖資料等結構的專有表示式支援等概念,這些對於使指標在每個目標系統中發揮作用至關重要。在此過程中,我們還添加了儀表過濾功能,讓你能夠更好地控制上游依賴項的檢測。

提示

要了解更多關於 Micrometer 的功能,請參閱其參考文件,特別是概念部分

我能從中獲得什麼開箱即用的功能?

Spring Boot 2 自動配置了相當多的指標,包括:

  • JVM,報告以下利用情況:

    • 各種記憶體和緩衝池

    • 垃圾回收相關統計資訊

    • 執行緒利用率

    • 載入/解除安裝的類數量

  • CPU 使用率

  • Spring MVC 和 WebFlux 請求延遲

  • RestTemplate 延遲

  • 快取利用率

  • 資料來源利用率,包括 HikariCP 連線池指標

  • RabbitMQ 連線工廠

  • 檔案描述符使用情況

  • Logback:記錄每個級別記錄到 Logback 的事件數量

  • 執行時間:報告一個測量器表示執行時間,以及一個固定測量器表示應用程式的絕對啟動時間

  • Tomcat 使用情況

其中許多指標在 Spring Boot 1 中曾以某種形式存在,但在 Spring Boot 2 中增加了更多細節和標籤,得到了豐富。

Micrometer 支援哪些監控系統?

Micrometer 提供了一個供應商中立的指標收集 API(根植於 io.micrometer.core.instrument.MeterRegistry)以及各種監控系統的實現,包括:

  • Netflix Atlas

  • CloudWatch

  • Datadog

  • Ganglia

  • Graphite

  • InfluxDB

  • JMX

  • New Relic

  • Prometheus

  • SignalFx

  • StatsD(Etsy、dogstatsd、Telegraf 和專有格式)

  • Wavefront

對其他系統的支援正在進行中或計劃在定於 2018 年中旬釋出的 1.1.0 版本中實現,包括:

  • AppOptics

  • Azure Application Insights

  • Dynatrace

  • Elasticsearch

  • StackDriver

Spring Boot 2 配置了一個複合 MeterRegistry,可以向其中新增任意數量的登錄檔實現,從而允許你將指標傳送到多個監控系統。透過 MeterRegistryCustomizer,你可以一次性定製整個登錄檔集合,或者專門定製單個實現。例如,一種常見的配置是 (1) 將指標匯出到 Prometheus 和 CloudWatch,(2) 為流向兩者的指標新增一組通用標籤(例如,主機和應用程式標識標籤),以及 (3) 只將一小部分指標列入 CloudWatch 的白名單。

指標和追蹤的區別

透過指標(metrics),我們特指那一類資訊,它允許你從整體上(跨單個應用的多個元件、叢集中的多個例項、不同環境或區域中執行的叢集等)理解系統的效能。

值得注意的是,這不包括用於理解單個請求在經過一系列服務時,各個元件對其總延遲貢獻的資訊;這是分散式追蹤收集器(如 Spring Cloud Sleuth、Zipkin 的 Brave 等)的職責。

分散式追蹤系統提供關於子系統延遲的詳細資訊,但為了擴充套件性通常會進行取樣(例如,Spring Cloud Sleuth 預設傳送 10% 的樣本)。指標資料通常是預先聚合的,因此自然缺乏關聯資訊,但也不會進行取樣。因此,對於在一分鐘間隔內有 10 萬個請求,其中包含與服務 A 的互動,並可能根據輸入包含與服務 B 的互動的情況:

  1. 指標資料會告訴你,總體而言,服務 A 的觀察吞吐量為 10 萬請求,服務 B 的觀察吞吐量為 6 萬請求。此外,在那一分鐘內,服務 A 的最大總體平均延遲為 100ms,服務 B 的最大總體平均延遲為 50ms。它還會提供該時間段內的最大延遲和其他分佈統計資訊。

  2. 分散式追蹤系統會告訴你,對於某個特定請求(但不是所有請求的總集,因為記住正在進行取樣),服務 A 花費了 50ms,服務 B 花費了 90ms。

你可能可以從指標資料合理地推斷出,在最差使用者體驗中花費的時間大約一半在 A 服務中,一半在 B 服務中,但你無法確定,因為你看到的是聚合資料,完全有可能在最差情況下,所有 100ms 都花在了服務 A 中,而服務 B 根本沒有被呼叫。

反之,從追蹤資料中你無法推斷出某個時間間隔內的吞吐量或最差的使用者體驗。

維度的重要性

Spring Boot 1 的指標介面本質上是分層的。這意味著釋出的指標完全由其名稱標識。所以你可能會有一個名為 jvm.memory.used 的指標。

當你檢視單個應用程式例項的指標時,這似乎很合適。但是,如果你有 10 個例項都將 jvm.memory.used 釋出到同一個監控系統怎麼辦?如果某個例項的記憶體消耗意外飆升,我們如何區分它們?

通常的答案是修改名稱,例如透過在名稱中新增字首或字尾。因此我們可以將名稱更改為 ${HOST}.jvm.memory.used,其中用 ${HOST} 替換主機名。重新部署所有 10 個例項後,我們現在可以確定哪個例項正面臨記憶體壓力。在典型的分層監控系統中,我們可以透過某種方式使用萬用字元來計算所有例項的總記憶體使用量,例如:

*.jvm.memory.used

現在假設我們在 3 個部署區域中,每個區域都有 10 個應用程式例項。此外,我們希望按區域分析應用程式的平均或最大記憶體佔用。現在,如果我們為指標名稱新增額外的分割槽字首(使其看起來像 ${REGION}.${HOST}.jvm.memory.used),我們就會破壞現有的查詢。我們可以更新查詢來計算所有例項的總記憶體使用量,例如:

*.*.jvm.memory.used

不幸的是,這會使我們無法看到現有基礎設施的資料,直到所有例項都使用新的字首重新部署完畢。這只是分層命名方法的一個侷限性的例子。

我們已經提到,Micometer 是一個維度優先(dimensional-first)的指標收集器。在 Micrometer 中,同樣的指標會使用標籤(tag,也稱為維度 dimension)進行記錄,例如:

Gauge.builder("jvm.memory.used", ..)
  .tag("host", "MYHOST")
  .tag("region", "us-east-1")
  .register(registry);

維度監控系統自然會彙總所有標籤下的 jvm.memory.used 指標,直到你進一步細化查詢一個或多個標籤。在維度監控系統中,查詢會首先選擇名稱(jvm.memory.used),然後允許按標籤進行後續過濾。在我們上面的場景中,如果之前有一個基於主機記憶體消耗飆升的圖表/警報,然後後來添加了區域標籤,那麼基於主機的查詢將繼續不間斷地工作,同時新的包含區域資訊的指標也在你的基礎設施中推廣。

儀表過濾器

儀表過濾器允許你控制儀表的註冊方式和時間以及它們發出的統計資訊型別。儀表過濾器主要有三個基本功能:

  • 拒絕(或接受)儀表的註冊。

  • 轉換儀表 ID(例如,更改名稱、新增或刪除標籤、更改描述或基本單位)。

  • 配置某些儀表型別的分佈統計資訊(例如,計時器和分佈摘要的分位數、直方圖、SLA)。

Spring Boot 2 將一系列屬性繫結到一個開箱即用的儀表過濾器,允許你透過屬性控制指標的發出。例如:

management.metrics.enable.jvm=false
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.sla.http.server.requests=1ms,5ms

上述配置關閉了所有以“jvm”為字首的指標,為 Spring Boot 自動配置的 http 伺服器請求指標釋出分位數直方圖,併發送小於等於 1ms 和 5ms SLA 邊界的請求計數,這樣你就可以準確地看到有多少請求符合你的預期。SLA 分佈配置也是使你能夠視覺化更復雜測量指標(如 Apdex 分數)的核心功能。

你可以在根級別完全切換指標的啟用狀態,只為你想要的一小部分指標生成白名單。假設你只想要 JVM 指標,而不需要其他指標,可以這樣配置:

management.metrics.enable.all=false
management.metrics.enable.jvm=true

/actuator/metrics 端點在 Spring Boot 2 中為何改變

在 Spring Boot 1 中提供一個列出所有指標的單個 REST 端點是很簡單的,因為我們只有計數器和測量器,並且它們都是分層的。更復雜的型別如計時器(timers)代表多個時間序列(它們至少包含一個計數、一個最大值和一個總和)。此外,我們的指標變成了維度的。很快就清楚了,無法在一個單一的載荷中輸出所有這些資訊。即使對於一個維度計數器,我們是否要顯示每個標籤組合的聚合資料?為了簡潔起見,將其扁平化為分層名稱,就會變成這樣:

http.server.requests.method.GET.response.200.uri./foo=100
http.server.requests.method.GET.response.500.uri./foo=1
http.server.requests.method.GET.response.200.uri./bar=5
http.server.requests.method.GET.response.400.uri./foo=1

# and now the aggregates...
http.server.requests.method.GET=107
http.server.requests.method.GET.response.200=105
http.server.requests.method.GET.uri./foo=101
http.server.requests.response.200.uri./foo=100
http.server.requests.response.500.uri./foo=1
http.server.requests.response.200.uri./bar=5
...

正如你所見,這很快就變得難以維護。例如,如果你想基於 MeterRegistry 的內容構建一個自定義 UI,並且你知道你的 UI 只關心按 URI 劃分的 http 吞吐量,而忽略方法、狀態等資訊,那麼輸出可以大幅精簡。對於這類情況,我們建議建立一個元件,只向你的 UI 提供所需的資料。將 MeterRegistry 注入到你的元件中,並使用它的 findget 方法搜尋你需要暴露的指標。然後以適合你用途的格式對其進行序列化。

參與其中

你可以在 slack.micrometer.io 的 Slack、Twitter 上的 @micrometerio 以及 Github 上獲得 Micrometer 支援。如有問題、建議或困擾,請隨時聯絡我們!

訂閱 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助你快速提升。

瞭解更多

獲得支援

Tanzu Spring 透過一項簡單的訂閱,為 OpenJDK™、Spring 和 Apache Tomcat® 提供支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群的所有即將舉行的活動。

檢視全部