Spring Boot 整合 Prometheus

Micrometer簡介

Micrometer 為 Java 平臺上的效能資料收集提供了一個通用的 API,應用程式只需要使用 Micrometer 的通用 API 來收集效能指標即可。Micrometer 會負責完成與不同監控系統的適配工作。這就使得切換監控系統變得很容易。Micrometer 還支援推送資料到多個不同的監控系統。Micrometer類似日誌系統中SLF4J。

Micrometer中有兩個最核心的概念,分別是是計量器(Meter)和計量器登錄檔(MeterRegistry),下面來分別看下這兩個概念。

計量器(Meter)

Meter用來收集效能指標資料(Metris),總共有四種類型的Meter,分別是Counter,Gauge,Timer,Summary。

每個Meter都有自己的名稱,同時Meter可以指定一系列的tag。tag是以key-value的形式出現,這樣我們就可以根據tag對指標進行過濾。除了每個Meter獨有的標籤外,也可以透過MeterRegistry新增通用的tag。

MeterRegistry。Config config = simpleMeterRegistry。config(); config。commonTags(“tag1”,“value1”,“tag2”,“value2”);

Counter

Counter只允許增加值,Counter所表示的計數值是double型別,預設情況下增加的值是1。0

@Autowiredprivate SimpleMeterRegistry simpleMeterRegistry;@Beanpublic Counter counter1(){ return Counter。builder(“test。count1”)。register(simpleMeterRegistry);}@Beanpublic Counter counter2(){ return simpleMeterRegistry。counter(“test。count2”);}@Testpublic void test(){ counter1。increment();}

Gauge

Cauge是表示單個的變化的值,例如溫度,氣壓。與Counter的區別在於,Gauge的值不總是增加的

public void guage(){ Gauge。builder(“guaua1”, this::getValue)。register(simpleMeterRegistry);}public double getValue(){ return ThreadLocalRandom。current()。nextDouble();}

Gauge物件一旦被建立,就不能手動對其中的值進行修改

。在每次取樣時,Gauge 會返回當前值

Timer

Timer通常用來記錄事件的持續時間。Timer會記錄兩類的資料,事件的數量和總的持續時間。Timer提供了不同方式來記錄持續時間。第一種方式是使用record()方法來記錄Runnable和Callable物件的執行時間,第二種方式是使用Timer。Sample來儲存計時狀態

public void record(){ Timer timer = simpleMeterRegistry。timer(“record”); timer。record(() -> { try { Thread。sleep(3000); }catch (Exception e){ e。printStackTrace(); } });}public void sample(){ Timer。Sample sample = Timer。start(); new Thread(()->{ try { Thread。sleep(3000); }catch (Exception e){ e。printStackTrace(); } sample。stop(simpleMeterRegistry。timer(“sample”)); });}

summary

summary用來記錄指標的分佈,summary根據每個指標的值,把值分配到對應的bucket中。Micrometer預設的bucket的值從1到Long。MAX_VALUE,可以透過minimumExpectedValue和maximumExpectedValue來控制bucket的範圍,如果指標的值較小,還可以透過scale來設定一個值對數值進行放大

public void summary(){ DistributionSummary summary = DistributionSummary。builder(“summary”) 。maximumExpectedValue(10L) 。minimumExpectedValue(1L) 。publishPercentiles(0。5, 0。75, 0。9) 。register(simpleMeterRegistry); summary。record(1。0); summary。record(5。0); summary。record(4。5); summary。record(3。0); System。out。println(summary。takeSnapshot());}

計量器登錄檔(MeterRegistry)

MeterRegistry負責建立和維護Meter。每一個監控系統有自己獨有的registry

Spring Boot 整合 Prometheus

其中SimpleMeterRegistry是一個基於記憶體的登錄檔,它不支援匯出資料到監控系統,主要用來進行本地開發和測試。

Micrometer支援多個不同的監控系統,透過CompositeMeterRegistry可以把多個計量器登錄檔組合起來,從而允許同時釋出資料到多個監控系統中。

public void compositeRegistry(){ CompositeMeterRegistry compositeMeterRegistry = new CompositeMeterRegistry(); compositeMeterRegistry。add(new SimpleMeterRegistry()); compositeMeterRegistry。add(new SimpleMeterRegistry(new SimpleConfig() { @Override public String get(String s) { return null; } //增加字首 @Override public String prefix() { return “simple”; } },Clock。SYSTEM)); Counter counter = compositeMeterRegistry。counter(“test”); counter。increment(); }

Micrometer本身提供了一個靜態的全域性登錄檔Metrics。golbalRegistry。這個登錄檔一個組合登錄檔,使用Metrics類中的靜態方法建立的計量器,都會被新增到這個全域性登錄檔中

public void globalRegistry(){ Metrics。addRegistry(simpleMeterRegistry); Counter global = Metrics。counter(“global”); global。increment();}

SpringBoot Actuator

上述介紹了Micrometer的一些簡單使用,從Spring Boot2。0開始,Micrometer就是Spring Boot預設提供的效能指標收集庫。SpringBoot Actuator提供了對Micrometer的自動配置。在專案中引入SpringBoot Actuator,

org。springframework。boot spring-boot-starter-actuator

並在配置檔案中,增加如下配置

Actuator可對外預設的服務,*表示顯示所有management。endpoints。web。exposure。include=*

啟動專案,訪問http://8080/actuator,就可以看到Actuator提供的所有監控

{ “_links”: { “self”: { “href”: “http://localhost:8080/actuator”, “templated”: false }, “auditevents”: { “href”: “http://localhost:8080/actuator/auditevents”, “templated”: false }, “beans”: { “href”: “http://localhost:8080/actuator/beans”, “templated”: false }, “caches-cache”: { “href”: “http://localhost:8080/actuator/caches/{cache}”, “templated”: true }, “caches”: { “href”: “http://localhost:8080/actuator/caches”, “templated”: false }, “health”: { “href”: “http://localhost:8080/actuator/health”, “templated”: false }, “health-component”: { “href”: “http://localhost:8080/actuator/health/{component}”, “templated”: true }, “health-component-instance”: { “href”: “http://localhost:8080/actuator/health/{component}/{instance}”, “templated”: true }, “conditions”: { “href”: “http://localhost:8080/actuator/conditions”, “templated”: false }, “configprops”: { “href”: “http://localhost:8080/actuator/configprops”, “templated”: false }, “env”: { “href”: “http://localhost:8080/actuator/env”, “templated”: false }, “env-toMatch”: { “href”: “http://localhost:8080/actuator/env/{toMatch}”, “templated”: true }, “info”: { “href”: “http://localhost:8080/actuator/info”, “templated”: false }, “loggers”: { “href”: “http://localhost:8080/actuator/loggers”, “templated”: false }, “loggers-name”: { “href”: “http://localhost:8080/actuator/loggers/{name}”, “templated”: true }, “heapdump”: { “href”: “http://localhost:8080/actuator/heapdump”, “templated”: false }, “threaddump”: { “href”: “http://localhost:8080/actuator/threaddump”, “templated”: false }, “prometheus”: { “href”: “http://localhost:8080/actuator/prometheus”, “templated”: false }, “metrics”: { “href”: “http://localhost:8080/actuator/metrics”, “templated”: false }, “metrics-requiredMetricName”: { “href”: “http://localhost:8080/actuator/metrics/{requiredMetricName}”, “templated”: true }, “scheduledtasks”: { “href”: “http://localhost:8080/actuator/scheduledtasks”, “templated”: false }, “httptrace”: { “href”: “http://localhost:8080/actuator/httptrace”, “templated”: false }, “mappings”: { “href”: “http://localhost:8080/actuator/mappings”, “templated”: false } }}

訪問http://localhost:8080/actuator/metrics,可以看到Actuator預設收集的監控指標,包括JVM相關指標(記憶體使用,垃圾收集),tomcat相關指標,資料庫連線池還是系統相關指標

{ “names”: [ “jvm。memory。max”, “jvm。threads。states”, “process。files。max”, “jvm。gc。memory。promoted”, “system。load。average。1m”, “jvm。memory。used”, “jvm。gc。max。data。size”, “jvm。gc。pause”, “jvm。memory。committed”, “system。cpu。count”, “logback。events”, “tomcat。global。sent”, “jvm。buffer。memory。used”, “tomcat。sessions。created”, “jvm。threads。daemon”, “system。cpu。usage”, “jvm。gc。memory。allocated”, “tomcat。global。request。max”, “tomcat。global。request”, “tomcat。sessions。expired”, “jvm。threads。live”, “jvm。threads。peak”, “tomcat。global。received”, “process。uptime”, “tomcat。sessions。rejected”, “process。cpu。usage”, “http。server。requests”, “tomcat。threads。config。max”, “jvm。classes。loaded”, “jvm。classes。unloaded”, “tomcat。global。error”, “tomcat。sessions。active。current”, “tomcat。sessions。alive。max”, “jvm。gc。live。data。size”, “tomcat。threads。current”, “process。files。open”, “jvm。buffer。count”, “jvm。buffer。total。capacity”, “tomcat。sessions。active。max”, “tomcat。threads。busy”, “process。start。time” ]}

我們可以透過以下連結來檢視具體某個指標

http://localhost:8080/actuator/metrics/metricName

其中metricName為需要檢視指標的名稱,例如檢視jvm記憶體

http://localhost:8080/actuator/metrics/jvm。memory。used

從上圖中我們可以看到jvm。memory。used有兩個tag,area和id,area指定記憶體位置(堆記憶體和非堆記憶體),id指定記憶體分類,我們可以指定tag來檢視更細緻的指標

http://localhost:8080/actuator/metrics/jvm。memory。used?tag=area:heaphttp://localhost:8080/actuator/metrics/jvm。memory。used?tag=area:heap&tag=id:PS%20Eden%20Space

Prometheus

Micrometer支援Prometheus,Micrometer提供PrometheusMeterRegistry登錄檔,用於將指標轉為Prometheus格式的指標。首先需要在pom檔案引入依賴

io。micrometer micrometer-registry-prometheus

其次在配置檔案中,配置暴露Prometheus,並允許將指標匯入到Prometheus中

management。endpoint。prometheus。enabled=truemanagement。metrics。export。prometheus。enabled=true

專案啟動後,我們訪問http://localhost:8080/actuator/prometheus,可以看到指標以變成Prometheus格式的指標

可以安裝Prometheus來採集這些指標

docker run -d -p 9090:9090 -v ~/Documents/config/prometheus。yml:/etc/prometheus/prometheus。yml prom/prometheus

其中prometheus。yml配置了採集地址及路徑

scrape_configs: - job_name: prometheus-test metrics_path: /actuator/prometheus static_configs: - targets: [‘172。16。22。50:8080’]

172。16。22。50是我本機的地址,你們可以修改為自己的ip地址即可,訪問http://localhost:9090/targets可以看到Prometheus採集配置

自定義Metric

我們可以利用Prometheus client自定義metric

package com。wbl。spingbootdemo。prometheus;import io。prometheus。client。CollectorRegistry;import io。prometheus。client。Counter;import org。springframework。beans。factory。annotation。Autowired;import org。springframework。stereotype。Service;import javax。annotation。PostConstruct;/** * @author wbl * @date 2019-09-29 */@Servicepublic class PrometheusMeter { @Autowired private CollectorRegistry collectorRegistry; // 定義name為prometheus_counter的counter public Counter prometheusCounter(){ return Counter。build()。name(“prometheus_counter”)。help(“prometheus counter test”) 。register(collectorRegistry); } @PostConstruct public void init(){ Counter counter = prometheusCounter(); new Thread(()-> { while (true){ counter。inc(); try { Thread。sleep(5000); } catch (InterruptedException e) { e。printStackTrace(); } } })。start(); }}

啟動專案之後,可以在Prometheus查詢頁面看到剛剛定義的指標prometheus_counter

總結

Micrometer整合了多個監控系統,包括Prometheus。Micrometer利用Meter收集資料,利用不同的MeterRegistry與不同的監控系統整合

SpringBoot Actuator集成了Micrometer,定義了許多預設的metric,可以在http://localhost:8080/actuator/metrics檢視

SpringBoot Actuator可以透過Micrometer將採集的指標匯入到Prometheus中

參考文獻

Micrometer

Quick Guide to Micrometer

Instrumenting And Monitoring Spring Boot 2 Applications

自定義Metrics:讓Prometheus監控你的應用程式

使用 Micrometer 記錄 Java 應用效能指標

https://bloodhunter。github。io/2019/09/27/spring-boot-zheng-he-prometheus/