SpringBoot 使用Prometheus采集自定義指標(biāo)數(shù)據(jù)的方案
我們在k8s集群成功搭建了Prometheus服務(wù)。今天,我們將在springboot2.x中使用prometheus記錄指標(biāo)。
一、我們需要什么指標(biāo)
對于DDD、TDD等,大家比較熟悉了,但是對于MDD可能就比較陌生了。MDD是Metrics-Driven Development的縮寫,主張開發(fā)過程由指標(biāo)驅(qū)動(dòng),通過實(shí)用指標(biāo)來驅(qū)動(dòng)快速、精確和細(xì)粒度的軟件迭代。MDD可使所有可以測量的東西都得到量化和優(yōu)化,進(jìn)而為整個(gè)開發(fā)過程帶來可見性,幫助相關(guān)人員快速、準(zhǔn)確地作出決策,并在發(fā)生錯(cuò)誤時(shí)立即發(fā)現(xiàn)問題并修復(fù)。依照MDD的理念,在需求階段就應(yīng)該考慮關(guān)鍵指標(biāo),在應(yīng)用上線后通過指標(biāo)了解現(xiàn)狀并持續(xù)優(yōu)化。有一些基于指標(biāo)的方法論,建議大家了解一下:
- Google的四大黃金指標(biāo):延遲Latency、流量Traffic、錯(cuò)誤Errors、飽和度Saturation
- Netflix的USE方法:使用率Utilization、飽和度Saturation、錯(cuò)誤Error
- WeaveCloud的RED方法:速率Rate、錯(cuò)誤Errors、耗時(shí)Duration
二、在SrpingBoot中引入prometheus
SpringBoot2.x集成Prometheus非常簡單,首先引入maven依賴:
io.micrometer micrometer-registry-prometheus 1.7.3 io.github.mweirauch micrometer-jvm-extras 0.2.2
然后,在application.properties中將prometheus的endpoint放出來。
management: endpoints: web: exposure: include: info,health,prometheus
接下來就可以進(jìn)行指標(biāo)埋點(diǎn)了,Prometheus的四種指標(biāo)類型此處不再贅述,請自行學(xué)習(xí)。一般指標(biāo)埋點(diǎn)代碼實(shí)現(xiàn)上有兩種形式:AOP、侵入式,建議盡量使用AOP記錄指標(biāo),對于無法使用aop的場景就只能侵入代碼了。常用的AOP方式有:
- @Aspect(通用)
- HandlerInterceptor (SpringMVC的攔截器)
- ClientHttpRequestInterceptor (RestTemplate的攔截器)
- DubboFilter (dubbo接口)
我們選擇通用的@Aspect,結(jié)合自定義指標(biāo)注解來實(shí)現(xiàn)。首先自定義指標(biāo)注解:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MethodMetrics { String name() default ""; String desc() default ""; String[] tags() default {}; //是否記錄時(shí)間間隔 boolean withoutDuration() default false; }
然后是切面實(shí)現(xiàn):
@Aspect public class PrometheusAnnotationAspect { @Autowired private MeterRegistry meterRegistry; @Pointcut("@annotation(com.smac.prometheus.annotation.MethodMetrics)") public void pointcut() {} @Around(value = "pointcut()") public Object process(ProceedingJoinPoint joinPoint) throws Throwable { Method targetMethod = ((MethodSignature) joinPoint.getSignature()).getMethod(); Method currentMethod = ClassUtils.getUserClass(joinPoint.getTarget().getClass()).getDeclaredMethod(targetMethod.getName(), targetMethod.getParameterTypes()); if (currentMethod.isAnnotationPresent(MethodMetrics.class)) { MethodMetrics methodMetrics = currentMethod.getAnnotation(MethodMetrics.class); return processMetric(joinPoint, currentMethod, methodMetrics); } else { return joinPoint.proceed(); } } private Object processMetric(ProceedingJoinPoint joinPoint, Method currentMethod, MethodMetrics methodMetrics) { String name = methodMetrics.name(); if (!StringUtils.hasText(name)) { name = currentMethod.getName(); } String desc = methodMetrics.desc(); if (!StringUtils.hasText(desc)) { desc = currentMethod.getName(); } //不需要記錄時(shí)間 if (methodMetrics.withoutDuration()) { Counter counter = Counter.builder(name).tags(methodMetrics.tags()).description(desc).register(meterRegistry); try { return joinPoint.proceed(); } catch (Throwable e) { throw new IllegalStateException(e); } finally { counter.increment(); } } //需要記錄時(shí)間(默認(rèn)) Timer timer = Timer.builder(name).tags(methodMetrics.tags()).description(desc).register(meterRegistry); return timer.record(() -> { try { return joinPoint.proceed(); } catch (Throwable e) { throw new IllegalStateException(e); } }); } }
代碼很容易,沒什么可說明的,接下來就是在需要記監(jiān)控的地方加上這個(gè)注解就行,比如:
@MethodMetrics(name="sms_send",tags = {"vendor","aliyun"}) public void send(String mobile, SendMessage message) throws Exception { ... }
至此,aop形式的指標(biāo)實(shí)現(xiàn)方式就完成了。如果是侵入式的話,直接使用meterRegistry就行:
meterRegistry.counter("sms.send","vendor","aliyun").increment();
啟動(dòng)服務(wù),打開http://localhost:8080/actuator/prometheus查看指標(biāo)。
三、高級指標(biāo)之分位數(shù)
分位數(shù)(P50/P90/P95/P99)是我們常用的一個(gè)性能指標(biāo),Prometheus提供了兩種解決方案:
client側(cè)計(jì)算方案
summery類型,設(shè)置percentiles,在本地計(jì)算出Pxx,作為指標(biāo)的一個(gè)tag被直接收集。
Timer timer = Timer.builder("sms.send").publishPercentiles(0.5, 0.9, 0.95,0.99).register(meterRegistry); timer.record(costTime, TimeUnit.MILLISECONDS);
會(huì)出現(xiàn)四個(gè)帶quantile的指標(biāo),如圖:
server側(cè)計(jì)算方案
開啟histogram,將所有樣本放入buckets中,在server側(cè)通過histogram_quantile函數(shù)對buckets進(jìn)行實(shí)時(shí)計(jì)算得出。注意:histogram采用了線性插值法,buckets的劃分對誤差的影響比較大,需合理設(shè)置。
Timer timer = Timer.builder("sms.send") .publishPercentileHistogram(true) .serviceLevelObjectives(Duration.ofMillis(10),Duration.ofMillis(20),Duration.ofMillis(50)) .minimumExpectedValue(Duration.ofMillis(1)) .maximumExpectedValue(Duration.ofMillis(100)) .register(meterRegistry); timer.record(costTime, TimeUnit.MILLISECONDS);
會(huì)出現(xiàn)一堆xxxx_bucket的指標(biāo),如圖:
然后,使用
histogram_quantile(0.95, rate(sms_send_seconds_bucket[5m]))
就可以看到P95的指標(biāo)了,如圖:
結(jié)論:
方案1適用于單機(jī)或只關(guān)心本地運(yùn)行情況的指標(biāo),比如gc時(shí)間、定時(shí)任務(wù)執(zhí)行時(shí)間、本地緩存更新時(shí)間等;
方案2則適用于分布式環(huán)境下的整體運(yùn)行情況的指標(biāo),比如搜索接口的響應(yīng)時(shí)間、第三方接口的響應(yīng)時(shí)間等。
到此這篇關(guān)于SpringBoot 使用Prometheus采集自定義指標(biāo)數(shù)據(jù)的文章就介紹到這了,更多相關(guān)SpringBoot采集自定義指標(biāo)數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot使用Prometheus采集自定義指標(biāo)數(shù)據(jù)的方法詳解
- Springboot搭建JVM監(jiān)控(Springboot + Prometheus + Grafana)
- springboot2.X整合prometheus監(jiān)控的實(shí)例講解
- SpringBoot+Prometheus+Grafana實(shí)現(xiàn)應(yīng)用監(jiān)控和報(bào)警的詳細(xì)步驟
- Prometheus 入門教程之SpringBoot 實(shí)現(xiàn)自定義指標(biāo)監(jiān)控
- springboot集成普羅米修斯(Prometheus)的方法
- 使用Prometheus+Grafana的方法監(jiān)控Springboot應(yīng)用教程詳解
- springboot整合prometheus實(shí)現(xiàn)資源監(jiān)控的詳細(xì)步驟
相關(guān)文章
SpringCloud?@RefreshScope刷新機(jī)制淺析
RefeshScope這個(gè)注解想必大家都用過,在微服務(wù)配置中心的場景下經(jīng)常出現(xiàn),他可以用來刷新Bean中的屬性配置,那大家對他的實(shí)現(xiàn)原理了解嗎?它為什么可以做到動(dòng)態(tài)刷新呢2023-03-03關(guān)于SpringBoot集成Lettuce連接Redis的方法和案例
這篇文章主要介紹了關(guān)于SpringBoot集成Lettuce連接Redis的方法和案例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04

Spring Cloud Ribbon客戶端詳細(xì)介紹

Spring Boot結(jié)合IDEA自帶Maven插件如何快速切換profile

解決SpringBoot返回結(jié)果如果為null或空值不顯示處理問題

Java代碼實(shí)現(xiàn)Map和Object互轉(zhuǎn)及Map和Json互轉(zhuǎn)