欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot結(jié)合prometheus自定義埋點(diǎn)方式

 更新時(shí)間:2024年12月12日 09:56:44   作者:小豹子的技術(shù)筆記  
文章介紹了如何使用Spring Actuator、Prometheus和Grafana進(jìn)行度量統(tǒng)計(jì)收集、數(shù)據(jù)收集和數(shù)據(jù)展示,以監(jiān)控生成環(huán)境機(jī)器的性能指標(biāo)和業(yè)務(wù)數(shù)據(jù)指標(biāo)

快速入門

spring-actuator做度量統(tǒng)計(jì)收集,使用Prometheus(普羅米修斯)進(jìn)行數(shù)據(jù)收集,Grafana(增強(qiáng)ui)進(jìn)行數(shù)據(jù)展示,用于監(jiān)控生成環(huán)境機(jī)器的性能指標(biāo)和業(yè)務(wù)數(shù)據(jù)指標(biāo)。

一般,我們叫這樣的操作為”埋點(diǎn)”。SpringBoot中的依賴spring-actuator中集成的度量統(tǒng)計(jì)API使用的框架是Micrometer,官網(wǎng)是https://Micrometer.io。

Micrometer提供的度量類庫(kù)

Meter是指一組用于收集應(yīng)用中的度量數(shù)據(jù)的接口,Meter單詞可以翻譯為”米”或者”千分尺”,但是顯然聽起來都不是很合理,因此下文直接叫Meter,理解它為度量接口即可。

Meter是由MeterRegistry創(chuàng)建和保存的,可以理解MeterRegistry是Meter的工廠和緩存中心,一般而言每個(gè)JVM應(yīng)用在使用Micrometer的時(shí)候必須創(chuàng)建一個(gè)MeterRegistry的具體實(shí)現(xiàn)。

Micrometer中,Meter的具體類型包括:Timer,Counter,Gauge,DistributionSummary,LongTaskTimer,F(xiàn)unctionCounter,F(xiàn)unctionTimer和TimeGauge。

下面分節(jié)詳細(xì)介紹這些類型的使用方法和實(shí)戰(zhàn)使用場(chǎng)景。而一個(gè)Meter具體類型需要通過名字和Tag(這里指的是Micrometer提供的Tag接口)作為它的唯一標(biāo)識(shí),這樣做的好處是可以使用名字進(jìn)行標(biāo)記,通過不同的Tag去區(qū)分多種維度進(jìn)行數(shù)據(jù)統(tǒng)計(jì)。

MeterRegistry

MeterRegistry在Micrometer是一個(gè)抽象類,主要實(shí)現(xiàn)包括:

  • SimpleMeterRegistry:每個(gè)Meter的最新數(shù)據(jù)可以收集到SimpleMeterRegistry實(shí)例中,但是這些數(shù)據(jù)不會(huì)發(fā)布到其他系統(tǒng),也就是數(shù)據(jù)是位于應(yīng)用的內(nèi)存中的。
  • CompositeMeterRegistry:多個(gè)MeterRegistry聚合,內(nèi)部維護(hù)了一個(gè)MeterRegistry的列表。
  • 全局的MeterRegistry:工廠類io.micrometer.core.instrument.Metrics中持有一個(gè)靜態(tài)final的CompositeMeterRegistry實(shí)例globalRegistry。

當(dāng)然,使用者也可以自行繼承MeterRegistry去實(shí)現(xiàn)自定義的MeterRegistry。

SimpleMeterRegistry適合做調(diào)試的時(shí)候使用,它的簡(jiǎn)單使用方式如下:

MeterRegistry registry = new SimpleMeterRegistry(); 
Counter counter = registry.counter("counter");
counter.increment();

CompositeMeterRegistry實(shí)例初始化的時(shí)候,內(nèi)部持有的MeterRegistry列表是空的,如果此時(shí)用它新增一個(gè)Meter實(shí)例,Meter實(shí)例的操作是無效的

CompositeMeterRegistry composite = new CompositeMeterRegistry();

Counter compositeCounter = composite.counter("counter");
compositeCounter.increment(); // <- 實(shí)際上這一步操作是無效的,但是不會(huì)報(bào)錯(cuò)

SimpleMeterRegistry simple = new SimpleMeterRegistry();
composite.add(simple);  // <- 向CompositeMeterRegistry實(shí)例中添加SimpleMeterRegistry實(shí)例

compositeCounter.increment();  // <-計(jì)數(shù)成功

全局的MeterRegistry的使用方式更加簡(jiǎn)單便捷,因?yàn)橐磺兄恍枰僮鞴S類Metrics的靜態(tài)方法:

Metrics.addRegistry(new SimpleMeterRegistry());
Counter counter = Metrics.counter("counter", "tag-1", "tag-2");
counter.increment();

Tag與Meter的命名

Micrometer中,Meter的命名約定使用英文逗號(hào)(dot,也就是”.”)分隔單詞。但是對(duì)于不同的監(jiān)控系統(tǒng),對(duì)命名的規(guī)約可能并不相同,如果命名規(guī)約不一致,在做監(jiān)控系統(tǒng)遷移或者切換的時(shí)候,可能會(huì)對(duì)新的系統(tǒng)造成破壞。

Micrometer中使用英文逗號(hào)分隔單詞的命名規(guī)則,再通過底層的命名轉(zhuǎn)換接口NamingConvention進(jìn)行轉(zhuǎn)換,最終可以適配不同的監(jiān)控系統(tǒng),同時(shí)可以消除監(jiān)控系統(tǒng)不允許的特殊字符的名稱和標(biāo)記等。開發(fā)者也可以覆蓋NamingConvention實(shí)現(xiàn)自定義的命名轉(zhuǎn)換規(guī)則:

registry.config().namingConvention(myCustomNamingConvention);

在Micrometer中,對(duì)一些主流的監(jiān)控系統(tǒng)或者存儲(chǔ)系統(tǒng)的命名規(guī)則提供了默認(rèn)的轉(zhuǎn)換方式,例如當(dāng)我們使用下面的命名時(shí)候:

MeterRegistry registry = ...
registry.timer("http.server.requests");

對(duì)于不同的監(jiān)控系統(tǒng)或者存儲(chǔ)系統(tǒng),命名會(huì)自動(dòng)轉(zhuǎn)換如下:

  • Prometheus - http_server_requests_duration_seconds。
  • Atlas - httpServerRequests。
  • Graphite - http.server.requests。
  • InfluxDB - http_server_requests。

其實(shí)NamingConvention已經(jīng)提供了5種默認(rèn)的轉(zhuǎn)換規(guī)則:dot、snakeCase、camelCase、upperCamelCase和slashes。

另外:

Tag(標(biāo)簽)是Micrometer的一個(gè)重要的功能,嚴(yán)格來說,一個(gè)度量框架只有實(shí)現(xiàn)了標(biāo)簽的功能,才能真正地多維度進(jìn)行度量數(shù)據(jù)收集。

Tag的命名一般需要是有意義的,所謂有意義就是可以根據(jù)Tag的命名可以推斷出它指向的數(shù)據(jù)到底代表什么維度或者什么類型的度量指標(biāo)。

假設(shè)我們需要監(jiān)控?cái)?shù)據(jù)庫(kù)的調(diào)用和Http請(qǐng)求調(diào)用統(tǒng)計(jì),一般推薦的做法是:

MeterRegistry registry = ...
registry.counter("database.calls", "db", "users")
registry.counter("http.requests", "uri", "/api/users")

有兩點(diǎn)需要注意:

1、Tag的值必須不為null。

2、Micrometer中,Tag必須成對(duì)出現(xiàn),也就是Tag必須設(shè)置為偶數(shù)個(gè),實(shí)際上它們以Key=Value的形式存在,具體可以看io.micrometer.core.instrument.Tag接口。

Meter的命名和Meter的Tag相互結(jié)合,以命名為軸心,以Tag為多維度要素,可以使度量數(shù)據(jù)的維度更加豐富,便于統(tǒng)計(jì)和分析。

Meters

前面提到Meter主要包括:Timer,Counter,Gauge,DistributionSummary,LongTaskTimer,F(xiàn)unctionCounter,F(xiàn)unctionTimer和TimeGauge。

下面逐一分析它們的作用和個(gè)人理解的實(shí)際使用場(chǎng)景(應(yīng)該說是生產(chǎn)環(huán)境)。

Counter

Counter是一種比較簡(jiǎn)單的Meter,它是一種單值的度量類型,或者說是一個(gè)單值計(jì)數(shù)器。Counter接口允許使用者使用一個(gè)固定值(必須為正數(shù))進(jìn)行計(jì)數(shù)。

準(zhǔn)確來說:Counter就是一個(gè)增量為正數(shù)的單值計(jì)數(shù)器。

使用場(chǎng)景:

Counter的作用是記錄XXX的總量或者計(jì)數(shù)值,適用于一些增長(zhǎng)類型的統(tǒng)計(jì),例如下單、支付次數(shù)、Http請(qǐng)求總量記錄等等,通過Tag可以區(qū)分不同的場(chǎng)景,對(duì)于下單,可以使用不同的Tag標(biāo)記不同的業(yè)務(wù)來源或者是按日期劃分,對(duì)于Http請(qǐng)求總量記錄,可以使用Tag區(qū)分不同的URL?!驹鲩L(zhǎng)無上限】

Timer

Timer(計(jì)時(shí)器)適用于記錄耗時(shí)比較短的事件的執(zhí)行時(shí)間,通過時(shí)間分布展示事件的序列和發(fā)生頻率。所有的Timer的實(shí)現(xiàn)至少記錄了發(fā)生的事件的數(shù)量和這些事件的總耗時(shí),從而生成一個(gè)時(shí)間序列。

Timer的基本單位基于服務(wù)端的指標(biāo)而定,但是實(shí)際上我們不需要過于關(guān)注Timer的基本單位,因?yàn)镸icrometer在存儲(chǔ)生成的時(shí)間序列的時(shí)候會(huì)自動(dòng)選擇適當(dāng)?shù)幕締挝弧?/p>

比較常用和方便的方法是幾個(gè)函數(shù)式接口入?yún)⒌姆椒ǎ?/p>

Timer timer = ...
timer.record(() -> dontCareAboutReturnValue());
timer.recordCallable(() -> returnValue());

Runnable r = timer.wrap(() -> dontCareAboutReturnValue());
Callable c = timer.wrap(() -> returnValue());

使用場(chǎng)景:

根據(jù)個(gè)人經(jīng)驗(yàn)和實(shí)踐,總結(jié)如下:

  • 記錄指定方法的執(zhí)行時(shí)間用于展示。
  • 記錄一些任務(wù)的執(zhí)行時(shí)間,從而確定某些數(shù)據(jù)來源的速率,例如消息隊(duì)列消息的消費(fèi)速率等。

這里舉個(gè)實(shí)際的例子,要對(duì)系統(tǒng)做一個(gè)功能,記錄指定方法的執(zhí)行時(shí)間,還是用下單方法做例子:

        Metrics.addRegistry(new SimpleMeterRegistry());

        Timer timer = Metrics.timer("timer", "createOrder", "cost");
        timer.record(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
            System.out.println("下單成功了。。。。。");
                }
        );

在實(shí)際生產(chǎn)環(huán)境中,可以通過spring-aop把記錄方法耗時(shí)的邏輯抽象到一個(gè)切面中,這樣就能減少不必要的冗余的模板代碼。

另外,Timer的使用還可以基于它的內(nèi)部類Timer.Sample,通過start和stop兩個(gè)方法記錄兩者之間的邏輯的執(zhí)行耗時(shí)。例如:

SimpleMeterRegistry registry = new SimpleMeterRegistry();
Timer.Sample sample = Timer.start(registry);
// 業(yè)務(wù)邏輯處理

sample.stop(registry.timer("my.timer", "response", "200"));

Gauge

Gauge(儀表)是獲取當(dāng)前度量記錄值的句柄,也就是它表示一個(gè)可以任意上下浮動(dòng)的單數(shù)值度量Meter。Gauge通常用于變動(dòng)的測(cè)量值,測(cè)量值用ToDoubleFunction參數(shù)的返回值設(shè)置,如當(dāng)前的內(nèi)存使用情況,同時(shí)也可以測(cè)量上下移動(dòng)的”計(jì)數(shù)”,比如隊(duì)列中的消息數(shù)量。

官網(wǎng)文檔中提到Gauge的典型使用場(chǎng)景是用于測(cè)量集合或映射的大小或運(yùn)行狀態(tài)中的線程數(shù)。Gauge一般用于監(jiān)測(cè)有自然上界的事件或者任務(wù),而Counter一般使用于無自然上界的事件或者任務(wù)的監(jiān)測(cè),所以像Http請(qǐng)求總量計(jì)數(shù)應(yīng)該使用Counter而非Gauge。

使用場(chǎng)景:

根據(jù)個(gè)人經(jīng)驗(yàn)和實(shí)踐,總結(jié)如下:

  • 有自然(物理)上界的浮動(dòng)值的監(jiān)測(cè),例如物理內(nèi)存、集合、映射、數(shù)值等。
  • 有邏輯上界的浮動(dòng)值的監(jiān)測(cè),例如積壓的消息、(線程池中)積壓的任務(wù)等,其實(shí)本質(zhì)也是集合或者映射的監(jiān)測(cè)。

DistributionSummary

Summary(摘要)主要用于跟蹤事件的分布,在Micrometer中,對(duì)應(yīng)的類是DistributionSummary(分發(fā)摘要)。它的使用方式和Timer十分相似,但是它的記錄值并不依賴于時(shí)間單位。

使用場(chǎng)景:

根據(jù)個(gè)人經(jīng)驗(yàn)和實(shí)踐,總結(jié)如下:

1、不依賴于時(shí)間單位的記錄值的測(cè)量,例如服務(wù)器有效負(fù)載值,緩存的命中率等。

直方圖和百分?jǐn)?shù)配置

直方圖和百分?jǐn)?shù)配置適用于Summary和Timer,這部分相對(duì)復(fù)雜,等研究透了再補(bǔ)充。

Histogram類型總共上報(bào)5種數(shù)據(jù):count、sum,最大值、最小值、bucket

平均耗時(shí)可以通過 sum/count來計(jì)算

所以,用Histogram類型,可以一個(gè)指標(biāo)多個(gè)維度來使用。

完整的類型介紹:Metric Types | client_java

基于SpirngBoot、Prometheus、Grafana集成

集成了Micrometer框架的JVM應(yīng)用使用到Micrometer的API收集的度量數(shù)據(jù)位于內(nèi)存之中,因此,需要額外的存儲(chǔ)系統(tǒng)去存儲(chǔ)這些度量數(shù)據(jù),需要有監(jiān)控系統(tǒng)負(fù)責(zé)統(tǒng)一收集和處理這些數(shù)據(jù),還需要有一些UI工具去展示數(shù)據(jù),一般大佬只喜歡看炫酷的圖表或者動(dòng)畫。

常見的存儲(chǔ)系統(tǒng)就是時(shí)序數(shù)據(jù)庫(kù),主流的有Influx、Datadog等。比較主流的監(jiān)控系統(tǒng)(主要是用于數(shù)據(jù)收集和處理)就是Prometheus(一般叫普羅米修斯,下面就這樣叫吧)。而展示的UI目前相對(duì)用得比較多的就是Grafana。

另外,Prometheus已經(jīng)內(nèi)置了一個(gè)時(shí)序數(shù)據(jù)庫(kù)的實(shí)現(xiàn),因此,在做一套相對(duì)完善的度量數(shù)據(jù)監(jiān)控的系統(tǒng)只需要依賴目標(biāo)JVM應(yīng)用,Prometheus組件和Grafana組件即可。

SpirngBoot中使用Micrometer

SpringBoot中的spring-boot-starter-actuator依賴已經(jīng)集成了對(duì)Micrometer的支持,其中的metrics端點(diǎn)的很多功能就是通過Micrometer實(shí)現(xiàn)的,prometheus端點(diǎn)默認(rèn)也是開啟支持的,實(shí)際上actuator依賴的spring-boot-actuator-autoconfigure中集成了對(duì)很多框架的開箱即用的API。

其中prometheus包中集成了對(duì)Prometheus的支持,使得使用了actuator可以輕易地讓項(xiàng)目暴露出prometheus端點(diǎn),作為Prometheus收集數(shù)據(jù)的客戶端,Prometheus(服務(wù)端軟件)可以通過此端點(diǎn)收集應(yīng)用中Micrometer的度量數(shù)據(jù)。

我們先引入spring-boot-starter-actuator和spring-boot-starter-web,實(shí)現(xiàn)一個(gè)Counter和Timer作為示例。依賴:

 <!-- Micrometer core dependecy -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

注意多看spring官方文檔關(guān)于Actuator的詳細(xì)描述,在SpringBoot-2.x之后,配置Web端點(diǎn)暴露的權(quán)限控制和1.x有很大的不同。

總結(jié)一下就是:除了shutdown端點(diǎn)之外,其他端點(diǎn)默認(rèn)都是開啟支持的這里僅僅是開啟支持,并不是暴露為Web端點(diǎn),端點(diǎn)必須暴露為Web端點(diǎn)才能被訪問,禁用或者開啟端點(diǎn)支持的配置方式如下:

management.endpoint.${端點(diǎn)ID}.enabled=true/false可以查

暴露監(jiān)控端點(diǎn)為Web端點(diǎn)的配置是:

management.endpoints.web.exposure.include=info,health,metrics,prometheus

management.endpoints.web.exposure.exclude用于指定不暴露為Web端點(diǎn)的監(jiān)控端點(diǎn),指定多個(gè)的時(shí)候用英文逗號(hào)分隔

management.endpoints.web.exposure.include默認(rèn)指定的只有info和health兩個(gè)端點(diǎn),我們可以直接指定暴露所有的端點(diǎn):management.endpoints.web.exposure.include=*,如果采用YAML配置,記得要加單引號(hào)’‘。

暴露所有Web監(jiān)控端點(diǎn)是一件比較危險(xiǎn)的事情,如果需要在生產(chǎn)環(huán)境這樣做,請(qǐng)務(wù)必先確認(rèn)http://{host}:{management.port}不能通過公網(wǎng)訪問(也就是監(jiān)控端點(diǎn)訪問的端口只能通過內(nèi)網(wǎng)訪問,這樣可以方便后面說到的Prometheus服務(wù)端通過此端口收集數(shù)據(jù))。

由于引入了springboot-actuator依賴,會(huì)在spring容器啟動(dòng)時(shí)自動(dòng)注入prometheus Registry實(shí)例

這樣就可以在spring boot框架中直接使用上報(bào)API了,如

 Metrics.counter("order.count", "order.channel", "huawei").increment();

 Timer timer = Metrics.timer("method.cost.time", "method.name", "hello");
 timer.record(3, TimeUnit.SECONDS);

最好參考一下Prometheus的官方文檔,稍微學(xué)習(xí)一下它的查詢語言PromQL的使用方式,一個(gè)面板可以支持多個(gè)PromQL查詢。

提供一個(gè)例子:

public final class MeterRegistryCenter {

    private static final Logger logger = LoggerFactory.getLogger(MeterRegistryCenter.class);

    private static CompositeMeterRegistry METER_REGISTRY = null;

    static {
        try {
            METER_REGISTRY = Metrics.globalRegistry;
        } catch (Throwable t) {
            logger.warn("Metrics init failed :", t);
        }
    }

    public static Counter counter(String name, Iterable<Tag> tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.counter(name, tags);
        }
        return null;
    }

    public static Counter counter(String name, String... tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.counter(name, tags);
        }
        return null;
    }

    public static <T extends Number> T gauge(String name, Iterable<Tag> tags, T number) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.gauge(name, tags, number);
        }
        return null;
    }

    public static Timer timer(String name, Iterable<Tag> tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.timer(name, tags);
        }
        return null;
    }

    public static Timer timer(String name, String... tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.timer(name, tags);
        }
        return null;
    }

    public static DistributionSummary summary(String name, Iterable<Tag> tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.summary(name, tags);
        }
        return null;
    }

    public static DistributionSummary summary(String name, String... tags) {
        if (METER_REGISTRY != null) {
            return METER_REGISTRY.summary(name, tags);
        }
        return null;
    }
}
public final class MetricsMonitor {

    private static final Logger logger = LoggerFactory.getLogger(MetricsMonitor.class);

    private static final String DEFAULT_APP_ID = "unknown";
    private static final String DEFAULT_SDK_LANG = "unknown";
    private static final String DEFAULT_IDC = "unknown";
    private static final String DEFAULT_URL_PATH = "unknown";

    private static final String APOLLO_QUERY_CONFIG_SOURCE_METER = "apollo_query_config_source";
    private static final String APOLLO_URL_REQUEST_METER = "apollo_url_request";

    public static Counter getQueryConfigSourceCounter(String appId, String sdkLang, String idc) {
        if (StringUtils.isBlank(appId)) {
            appId = DEFAULT_APP_ID;
        }

        if (StringUtils.isBlank(sdkLang)) {
            sdkLang = DEFAULT_SDK_LANG;
        }

        if (StringUtils.isBlank(idc)) {
            idc = DEFAULT_IDC;
        }

        return ApolloMeterRegistryCenter.counter(APOLLO_QUERY_CONFIG_SOURCE_METER, "appId", appId, "sdkLang", sdkLang, "idc", idc);
    }

    public static Counter getUrlRequestCounter(String url) {
        if (StringUtils.isBlank(url)) {
            url = DEFAULT_URL_PATH;
        }

        return ApolloMeterRegistryCenter.counter(APOLLO_URL_REQUEST_METER, "url", url);
    }

    public static void recordQueryConfigSource(String appId, String sdkLang, String idc) {
        try {
            Counter counter = getQueryConfigSourceCounter(appId, sdkLang, idc);
            if (!Objects.isNull(counter)) {
                counter.increment();
            }
        } catch (Throwable t) {
            logger.warn("recordQueryConfigSource failed,msg: " + t.getMessage());
        }
    }

    public static void recordUrlRequest(String url) {
        try {
            Counter counter = getUrlRequestCounter(url);
            if (!Objects.isNull(counter)) {
                counter.increment();
            }
        } catch (Throwable t) {
            logger.warn("recordUrlRequest failed,msg: " + t.getMessage());
        }
    }

}

使用push Gateway方式上報(bào)數(shù)據(jù)

Prometheus是一款開源的監(jiān)控和報(bào)警系統(tǒng),而Pushgateway是Prometheus的一個(gè)組件,用于接收短期的指標(biāo)數(shù)據(jù)。

在某些情況下,我們可能需要通過Java代碼將指標(biāo)數(shù)據(jù)推送到Prometheus Pushgateway中。

github: GitHub - prometheus/client_java: Prometheus instrumentation library for JVM applications

各種模式的接入方式文檔地址:Quickstart | client_java

一個(gè)例子:

1、maven引入依賴

<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-core</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-exporter-pushgateway</artifactId>
    <version>1.3.0</version>
</dependency>

2、編寫service

import io.prometheus.metrics.core.metrics.Counter;
import io.prometheus.metrics.exporter.pushgateway.PushGateway;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class MeterService implements InitializingBean {

    @Value("${metrics.pushgateway.address:127.0.0.1:9091}")
    private String prometheusPushGateWayAddress;

    private static final String PROMETHEUS_JOB_NAME = "test_metrics";

    private PushGateway prometheusPushGateWay;

    private final ScheduledExecutorService reportSchedule = Executors.newSingleThreadScheduledExecutor();

    private Counter testCounter;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 1.定義push Gateway
        PrometheusRegistry registry = new PrometheusRegistry();
        prometheusPushGateWay =
                PushGateway.builder()
                        .address(prometheusPushGateWayAddress)
                        .job(PROMETHEUS_JOB_NAME)
                        .registry(registry)
                        .build();

        // 2.定義各種業(yè)務(wù)指標(biāo)
        testCounter = Counter.builder().name("test_01_metrics_total").labelNames("region", "code").register(registry);

        // 3.定期推送數(shù)據(jù)到prometheus server
        reportSchedule.scheduleAtFixedRate(() -> {
            try {
                if (!Objects.isNull(prometheusPushGateWay)) {
                    prometheusPushGateWay.pushAdd();
                    log.info("push data success");
                }
            } catch (Exception e) {
                log.error("pushGateway push failed!", e);
            }
        }, 60, 60, TimeUnit.SECONDS);
    }

    public void report(String region, String code) {
        testCounter.labelValues(region, code).inc();
    }
}

3、在業(yè)務(wù)埋點(diǎn)調(diào)用即可。數(shù)據(jù)將會(huì)上報(bào)到prometheus,然后通過配置grafana報(bào)表即可。

特別注意:使用push Gateway方式上報(bào)數(shù)據(jù),tag一定要加上機(jī)器的IP,否則服務(wù)端區(qū)分不出是哪個(gè)機(jī)器的上報(bào),導(dǎo)致數(shù)據(jù)不準(zhǔn)。

維度問題,注意不要發(fā)散,如果發(fā)散的影響有:

  • 導(dǎo)致promethues服務(wù)端的cpu、mem等都會(huì)有一定的壓力
  • grafana查詢會(huì)變慢,導(dǎo)致有時(shí)候結(jié)果查詢不出來
  • 程序調(diào)用pushAdd函數(shù)也有出現(xiàn)超時(shí)(數(shù)據(jù)量太多)

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java并發(fā)編程之同步容器

    Java并發(fā)編程之同步容器

    這篇文章主要介紹了Java并發(fā)編程之同步容器,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • 使用maven命令實(shí)現(xiàn)下載依賴jar

    使用maven命令實(shí)現(xiàn)下載依賴jar

    這篇文章主要介紹了使用maven命令實(shí)現(xiàn)下載依賴jar方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Struts2實(shí)現(xiàn)文件上傳功能

    Struts2實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了Struts2實(shí)現(xiàn)文件上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • SpringAOP四種通知類型+環(huán)繞通知說明

    SpringAOP四種通知類型+環(huán)繞通知說明

    這篇文章主要介紹了SpringAOP四種通知類型+環(huán)繞通知說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解Spring Boot Profiles 配置和使用

    詳解Spring Boot Profiles 配置和使用

    本篇文章主要介紹了詳解Spring Boot Profiles 配置和使用,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-06-06
  • java編程實(shí)現(xiàn)根據(jù)EXCEL列名求其索引的方法

    java編程實(shí)現(xiàn)根據(jù)EXCEL列名求其索引的方法

    這篇文章主要介紹了java編程實(shí)現(xiàn)根據(jù)EXCEL列名求其索引的方法,涉及Java元素遍歷與數(shù)學(xué)運(yùn)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • 解析Spring事件發(fā)布與監(jiān)聽機(jī)制

    解析Spring事件發(fā)布與監(jiān)聽機(jī)制

    本篇文章給大家介紹Spring事件發(fā)布與監(jiān)聽機(jī)制,通過 ApplicationEvent 事件類和 ApplicationListener 監(jiān)聽器接口,可以實(shí)現(xiàn) ApplicationContext 事件發(fā)布與處理,需要的朋友參考下吧
    2021-06-06
  • Spring中的事務(wù)管理及實(shí)現(xiàn)方式解析

    Spring中的事務(wù)管理及實(shí)現(xiàn)方式解析

    這篇文章主要介紹了Spring中的事務(wù)管理及實(shí)現(xiàn)方式解析,Spring事務(wù)管理基于底層數(shù)據(jù)庫(kù)本身的事務(wù)處理機(jī)制,數(shù)據(jù)庫(kù)事務(wù)的基礎(chǔ),是掌握Spring事務(wù)管理的基礎(chǔ),這篇總結(jié)下Spring事務(wù),需要的朋友可以參考下
    2024-01-01
  • scala中的隱式類型轉(zhuǎn)換的實(shí)現(xiàn)

    scala中的隱式類型轉(zhuǎn)換的實(shí)現(xiàn)

    這篇文章主要介紹了scala中的隱式類型轉(zhuǎn)換的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • JPA?使用criteria簡(jiǎn)單查詢工具類方式

    JPA?使用criteria簡(jiǎn)單查詢工具類方式

    這篇文章主要介紹了JPA?使用criteria簡(jiǎn)單查詢工具類方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論