最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot使用Prometheus采集自定義指標(biāo)數(shù)據(jù)的方法詳解

 更新時(shí)間:2024年10月11日 11:20:09   作者:BasicLab基礎(chǔ)架構(gòu)實(shí)驗(yàn)室  
隨著微服務(wù)在生產(chǎn)環(huán)境大規(guī)模部署和應(yīng)用,隨之而來(lái)也帶來(lái)了新的問(wèn)題,其中比較關(guān)鍵的就是關(guān)于微服務(wù)的運(yùn)維和監(jiān)控,本文將結(jié)合微服務(wù)運(yùn)維監(jiān)控中的指標(biāo)監(jiān)控進(jìn)行詳細(xì)的說(shuō)明,需要的朋友可以參考下

一、我們需要什么指標(biāo)

對(duì)于DDD、TDD等,大家比較熟悉了,但是對(duì)于MDD可能就比較陌生了。MDD是Metrics-Driven Development的縮寫,主張開發(fā)過(guò)程由指標(biāo)驅(qū)動(dòng),通過(guò)實(shí)用指標(biāo)來(lái)驅(qū)動(dòng)快速、精確和細(xì)粒度的軟件迭代。MDD可使所有可以測(cè)量的東西都得到量化和優(yōu)化,進(jìn)而為整個(gè)開發(fā)過(guò)程帶來(lái)可見性,幫助相關(guān)人員快速、準(zhǔn)確地作出決策,并在發(fā)生錯(cuò)誤時(shí)立即發(fā)現(xiàn)問(wèn)題并修復(fù)。依照MDD的理念,在需求階段就應(yīng)該考慮關(guān)鍵指標(biāo),在應(yīng)用上線后通過(guò)指標(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非常簡(jiǎn)單,首先引入maven依賴:

io.micrometer
micrometer-registry-prometheus
1.7.3
        
        
io.github.mweirauch
micrometer-jvm-extras
0.2.2

然后,在application.properties中將prometheus的endpoint放出來(lái)。

management:
  endpoints:
    web:
      exposure:
        include: info,health,prometheus

接下來(lái)就可以進(jìn)行指標(biāo)埋點(diǎn)了,Prometheus的四種指標(biāo)類型此處不再贅述,請(qǐng)自行學(xué)習(xí)。一般指標(biāo)埋點(diǎn)代碼實(shí)現(xiàn)上有兩種形式:AOP、侵入式,建議盡量使用AOP記錄指標(biāo),對(duì)于無(wú)法使用aop的場(chǎng)景就只能侵入代碼了。常用的AOP方式有:

  • @Aspect(通用)
  • HandlerInterceptor (SpringMVC的攔截器)
  • ClientHttpRequestInterceptor (RestTemplate的攔截器)
  • DubboFilter (dubbo接口)

我們選擇通用的@Aspect,結(jié)合自定義指標(biāo)注解來(lái)實(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);
            }
        });
    }
}

代碼很容易,沒(méi)什么可說(shuō)明的,接下來(lái)就是在需要記監(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)。

三、高級(jí)指標(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è)通過(guò)histogram_quantile函數(shù)對(duì)buckets進(jìn)行實(shí)時(shí)計(jì)算得出。注意:histogram采用了線性插值法,buckets的劃分對(duì)誤差的影響比較大,需合理設(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)文章

  • 實(shí)例講解Java中動(dòng)態(tài)代理和反射機(jī)制

    實(shí)例講解Java中動(dòng)態(tài)代理和反射機(jī)制

    在本篇文章里小編給各位分享了關(guān)于Java中動(dòng)態(tài)代理和反射機(jī)制的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們學(xué)習(xí)下。
    2019-01-01
  • java Nio使用NioSocket客戶端與服務(wù)端交互實(shí)現(xiàn)方式

    java Nio使用NioSocket客戶端與服務(wù)端交互實(shí)現(xiàn)方式

    這篇文章主要介紹了java Nio使用 NioSocket 客戶端與服務(wù)端交互實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • java實(shí)現(xiàn)系統(tǒng)多級(jí)文件夾復(fù)制

    java實(shí)現(xiàn)系統(tǒng)多級(jí)文件夾復(fù)制

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)系統(tǒng)多級(jí)文件夾復(fù)制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Maven中optional和scope元素的使用弄明白了嗎

    Maven中optional和scope元素的使用弄明白了嗎

    這篇文章主要介紹了Maven中optional和scope元素的使用弄明白了嗎,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java Lambda表達(dá)式實(shí)例解析原理

    Java Lambda表達(dá)式實(shí)例解析原理

    日常開發(fā)中,我們很多時(shí)候需要用到Java?8的Lambda表達(dá)式,它允許把函數(shù)作為一個(gè)方法的參數(shù),讓我們的代碼更優(yōu)雅、更簡(jiǎn)潔。所以整理了一波工作中常用的Lambda表達(dá)式。看完一定會(huì)有幫助的
    2023-03-03
  • Java在Word中插入上標(biāo)和下標(biāo)的實(shí)現(xiàn)方法

    Java在Word中插入上標(biāo)和下標(biāo)的實(shí)現(xiàn)方法

    在某些情況下,你可能需要在Microsoft?Word中插入上標(biāo)和下標(biāo)。例如,當(dāng)你正在創(chuàng)建一個(gè)涉及科學(xué)公式的學(xué)術(shù)文件時(shí),在這篇文章中,你將學(xué)習(xí)如何使用Spire.Doc?for?Java庫(kù)在Word文檔中插入上標(biāo)和下標(biāo),需要的朋友可以參考下
    2022-10-10
  • Java中默認(rèn)的訪問(wèn)權(quán)限作用域解析

    Java中默認(rèn)的訪問(wèn)權(quán)限作用域解析

    這篇文章主要介紹了Java中默認(rèn)的訪問(wèn)權(quán)限作用域,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringBoot中請(qǐng)求入?yún)㈩愋娃D(zhuǎn)換的6種玩法

    SpringBoot中請(qǐng)求入?yún)㈩愋娃D(zhuǎn)換的6種玩法

    做 Spring Boot Web 開發(fā)的小伙伴,想必都做過(guò)請(qǐng)求入?yún)㈩愋娃D(zhuǎn)換吧,本文將和大家詳細(xì)介紹一下SpringBoot參數(shù)類型轉(zhuǎn)換的6種玩法,希望對(duì)大家有所幫助
    2026-02-02
  • Spring MVC的web.xml配置詳解

    Spring MVC的web.xml配置詳解

    這篇文章主要介紹了Spring MVC的web.xml配置詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java中將一個(gè)列表拆分為多個(gè)較小列表的三種不同方法

    Java中將一個(gè)列表拆分為多個(gè)較小列表的三種不同方法

    有時(shí)候我們需要將大集合按指定的數(shù)量分割成若干個(gè)小集合,這篇文章主要給大家介紹了關(guān)于Java中將一個(gè)列表拆分為多個(gè)較小列表的三種不同方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09

最新評(píng)論

容城县| 英超| 正阳县| 花莲市| 子洲县| 鱼台县| 巩留县| 六安市| 西林县| 保山市| 高碑店市| 常德市| 紫阳县| 乐陵市| 旺苍县| 娄底市| 叙永县| 北海市| 施秉县| 玛沁县| 绿春县| 道孚县| 那坡县| 垣曲县| 无极县| 赞皇县| 仙居县| 阳高县| 安塞县| 东兰县| 普兰店市| 台安县| 两当县| 监利县| 如东县| 平陆县| 息烽县| 望江县| 卓尼县| 台东县| 顺义区|