Spring Boot 使用 Micrometer 集成 Prometheus 監控 Java 應用性能


轉載自:https://cloud.tencent.com/developer/article/1508319

文章目錄1、Micrometer 介紹2、環境、軟件准備3、Spring Boot 工程集成 Micrometer4、配置 Prometheus 監控應用指標5、配置 Grafana Dashboard 展示監控項6、自定義監控指標並展示到 Grafana6.1、監控某幾個 API 請求次數6.2、監控所有 API 請求次數6.3、監控實時在線人數

1、Micrometer 介紹

Micrometer 為 Java 平台上的性能數據收集提供了一個通用的 API,它提供了多種度量指標類型(Timers、Guauges、Counters等),同時支持接入不同的監控系統,例如 Influxdb、Graphite、Prometheus 等。我們可以通過 Micrometer 收集 Java 性能數據,配合 Prometheus 監控系統實時獲取數據,並最終在 Grafana 上展示出來,從而很容易實現應用的監控。

Micrometer 中有兩個最核心的概念,分別是計量器(Meter)和計量器注冊表(MeterRegistry)。計量器用來收集不同類型的性能指標信息,Micrometer 提供了如下幾種不同類型的計量器:

  • 計數器(Counter): 表示收集的數據是按照某個趨勢(增加/減少)一直變化的,也是最常用的一種計量器,例如接口請求總數、請求錯誤總數、隊列數量變化等。
  • 計量儀(Gauge): 表示搜集的瞬時的數據,可以任意變化的,例如常用的 CPU Load、Mem 使用量、Network 使用量、實時在線人數統計等,
  • 計時器(Timer): 用來記錄事件的持續時間,這個用的比較少。
  • 分布概要(Distribution summary): 用來記錄事件的分布情況,表示一段時間范圍內對數據進行采樣,可以用於統計網絡請求平均延遲、請求延遲占比等。

2、環境、軟件准備

本次演示環境,我是在本機 MAC OS 上操作,以下是安裝的軟件及版本:

  • Docker: 18.06.3-ce
  • Oracle VirtualBox: 6.0.8 r130520 (Qt5.6.3)
  • Linux: 7.6.1810
  • Prometheus: v2.11.1
  • Grafana: v6.3.4

注意:這里為了快速方便啟動 Prometheus、Grafana 服務,我使用 Docker 方式啟動,所以本機需要安裝好 Docker 環境,這里忽略 Docker 的安裝過程,着重介紹一下 Spring Boot 項目如何使用 Micrometer 來監控 Java 應用性能,並集成到 Prometheus 最終使用 Grafana Dashboard 展示出來。

3、Spring Boot 工程集成 Micrometer

我們一般說 Spring Boot 集成 Micrometer 值得時 Spring 2.x 版本,因為在該版本 spring-boot-actuator 使用了 Micrometer 來實現監控,而在 Spring Boot 1.5x 中可以通過micrometer-spring-legacy 來使用 micrometer,顯然在 2.x 版本有更高的集成度,使用起來也非常方便了。那么創建一個 Spring Boot 2.1.4.RELEASE 版本的工程 springboot2-promethues,首先添加依賴如下:

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>
	<dependency>
		<groupId>io.micrometer</groupId>
		<artifactId>micrometer-registry-prometheus</artifactId>
		<version>1.1.4</version>
	</dependency>

這里引入了 io.micrometermicrometer-registry-prometheus 依賴以及 spring-boot-starter-actuator 依賴,因為該包對 Prometheus 進行了封裝,可以很方便的集成到 Spring Boot 工程中。

其次在 application.properties 中配置如下:

server.port=8088
spring.application.name=springboot2-prometheus
management.endpoints.web.exposure.include=*
management.metrics.tags.application=${spring.application.name}

這里 management.endpoints.web.exposure.include=* 配置為開啟 Actuator 服務,因為Spring Boot Actuator 會自動配置一個 URL 為 /actuator/Prometheus 的 HTTP 服務來供 Prometheus 抓取數據,不過默認該服務是關閉的,該配置將打開所有的 Actuator 服務。management.metrics.tags.application 配置會將該工程應用名稱添加到計量器注冊表的 tag 中去,方便后邊 Prometheus 根據應用名稱來區分不同的服務。

然后在工程啟動主類中添加 Bean 如下來監控 JVM 性能指標信息:

@SpringBootApplication
public class Springboot2PrometheusApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot2PrometheusApplication.class, args);
    }

    @Bean
    MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${spring.application.name}") String applicationName){
        return registry -> registry.config().commonTags("application", applicationName);
    }
}

最后,啟動服務,瀏覽器訪問 http://127.0.0.1:8088/actuator/prometheus 就可以看到應用的 一系列不同類型 metrics 信息,例如 http_server_requests_seconds summaryjvm_memory_used_bytes gaugejvm_gc_memory_promoted_bytes_total counter 等等。

img

4、配置 Prometheus 監控應用指標

Prometheus 的安裝配置可參考之前文章 Prometheus 監控報警系統 AlertManager 之郵件告警,寫的很詳細,這里就不在詳細說明了,修改 prometheus.yml 配置,在上篇文章配置示例基礎上,添加上邊啟動的服務地址來執行監控。

$ vim prommetheus.yml
......
- job_name: 'application'
    scrape_interval: 5s
    metrics_path: '/actuator/prometheus'
    file_sd_configs:
      - files: ['/usr/local/prometheus/groups/applicationgroups/*.json']

這里依然采用 file_sd_configs 方式動態服務發現,新建 <local_dir>/groups/applicationgroups/application.json 文件如下:

$ vim groups/applicationgroups/application.json
[
    {
        "targets": [
            "192.168.1.124:8088"
        ],
        "labels": {
            "instance": "springboot2-prometheus",
            "service": "springboot2-prometheus-service"
        }
    }
]

這里 192.168.1.124:8088 就是上邊本地啟動的服務地址,也就是 Prometheus 要監控的服務地址,同時添加一些與應用相關的標簽,方便后期執行 PromSQL 查詢語句區分。最后重啟 Prometheus 服務,查看 Prometheus UI 界面確認 Target 是否添加成功。

img

在 Graph 頁面執行一個簡單的查詢,也是獲取 springboot2-prometheus 服務的 JVM 性能指標值的。

5、配置 Grafana Dashboard 展示監控項

Prometheus 現在已經可以正常監控到應用 JVM 信息了,那么我們可以配置 Grafana Dashboard 來優雅直觀的展示出來這些監控值了。首先創建 Grafana 服務,這里為了方便,依舊采用 Docker 的方式啟動,啟動命令如下:

$ docker run -d -p 3000:3000 --name=grafana grafana/grafana

啟動完畢后,瀏覽器訪問 http://192.168.1.121:3000 即可,首次登錄使用 admin:admin 默認賬戶密碼登錄並修改密碼。登錄完畢,需要添加數據源,這里我們要添加的就是上邊 Prometheus 數據源,配置如下圖:

img

配置完畢,接下來需要導入對應的監控 JVM 的 Dashboard 模板,模板編號為 4701

img

導入完畢后,就可以看到 JVM (Micrometer) 各種類型指標監控圖形化以后的頁面。

6、自定義監控指標並展示到 Grafana

上邊是 spring-boot-actuator 集成了 Micrometer 來提供的默認監控項,覆蓋 JVM 各個層間的監控,配合 Grafana Dashboard 模板基本可以滿足我們日常對 Java 應用的監控。當然,它也支持自定義監控指標,實現各個方面的監控,例如統計訪問某一個 API 接口的請求數,統計實時在線人數、統計實時接口響應時間等功能,而這些都可以通過使用上邊的四種計量器來實現。接下來,來演示下如何自定義監控指標並展示到 Grafana 上。

6.1、監控某幾個 API 請求次數

我們繼續在 springboot2-promethues 工程上添加 IndexController.java,來實現分別統計訪問 index 及 core 接口請求次數,代碼如下:

@RestController
@RequestMapping("/v1")
public class IndexController {

    @Autowired
    MeterRegistry registry;

    private Counter counter_core;
    private Counter counter_index;

    @PostConstruct
    private void init(){
        counter_core = registry.counter("app_requests_method_count", "method", "IndexController.core");
        counter_index = registry.counter("app_requests_method_count", "method", "IndexController.index");
    }

    @RequestMapping(value = "/index")
    public Object index(){
        try{
            counter_index.increment();
        } catch (Exception e) {
            return e;
        }
        return counter_index.count() + " index of springboot2-prometheus.";
    }

    @RequestMapping(value = "/core")
    public Object coreUrl(){
        try{
            counter_core.increment();
        } catch (Exception e) {
            return e;
        }
        return counter_core.count() + " coreUrl Monitor by Prometheus.";
    }
}

說明一下,這里是一個簡單的 RestController 接口,使用了 Counter 計量器來統計訪問 /v1/index/v1/core 接口訪問量。因為訪問數會持續的增加,所以這里使用 Counter 比較合適。啟動服務,我們來分別訪問一下這兩個接口,為了更好的配合下邊演示,可以多訪問幾次。

img

img

服務可以正常訪問,並且訪問了 6 次 /v1/index,訪問了 10 次 /v1/core。接下來,我們可以到 Prometheus UI 界面上使用 PromSQL 查詢自定義的監控信息了。分別添加 Graph 並執行如下查詢語句,查詢結果如下:

img

img

可以看到正確統計出來這兩個接口請求的訪問數,這里解釋一下查詢語句:app_requests_method_count_total{application="springboot2-prometheus", instance="springboot2-prometheus", method="IndexController.core"} 這里的

  • app_requests_method_count_total 為上邊代碼中設置的 Counter 名稱。
  • application 為初始化 registry 時設置的通用標簽,標注應用名稱,這樣做好處就是可以根據應用名稱區分不同的應用。
  • instance<local_dir>/groups/applicationgroups/application.json 中配置的 instance 實例名稱,用來區分應用實例。
  • method 為上邊代碼中設置的 Counter 標簽名稱,可以用來區分不同的方法,這樣就不用為每一個方法設置一個 Counter 了。

接下來,我們在 Grafana Dashboard 上添加一個新的 Panel 並添加 Query 查詢,最后圖形化展示出來。首先添加一個 Panel 並命名為 自定義監控指標,然后點擊 Add Query 增加一個新的 Query 查詢,查詢語句為上邊的 PromSQL 語句,不過這里為了更好的擴展性,我們可以將 applicationinstance 兩個參數賦值為變量,而這些變量可以直接從 Prometheus 上傳遞過來,最終的查詢語句為 app_requests_method_count_total{application="$application", instance="$instance", method="IndexController.core"},最后修改 Title 為 實時訪問量 /v1/core,保存一下,返回首頁就可以看到剛添加的 Dashboard 了,是不是很直觀。

img

6.2、監控所有 API 請求次數

上邊針對某個或某幾個接口請求次數做了監控,如果我們想針對整個應用監控所有接口請求總次數,這個該如何實現呢?監控請求次數可以繼續使用 Counter 計數器,整個應用所有請求,我們自然而然的想到了 Spring AOP,通過切面注入可以做到統計所有請求記錄,添加依賴如下:

...
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjrt</artifactId>
		<version>1.9.4</version>
	</dependency>
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>1.9.4</version>
	</dependency>
	<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.2.12</version>
	</dependency>

添加 AspectAop.java 代碼到 Springboot2PrometheusApplication.java 同級目錄, 代碼如下:

@Component
@Aspect
public class AspectAop {

    @Autowired
    MeterRegistry registry;

    private Counter counter_total;

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("execution(public * com.promethues.demo.controller.*.*(..))")
    private void pointCut(){}

    @PostConstruct
    public void init(){
        counter_total = registry.counter("app_requests_count", "v1", "core");
    }

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint)throws Throwable {
        startTime.set(System.currentTimeMillis());
        counter_total.increment();
    }

    @AfterReturning(returning = "returnVal", pointcut = "pointCut()")
    public void doAftereReturning(Object returnVal){
        System.out.println("請求執行時間:" + (System.currentTimeMillis() - startTime.get()));
    }
}

這里 Spring AOP 操作代碼就不在說了,我們創建了一個名稱為 app_requests_count 的 Counter,所有請求過來都會執行 counter_total.increment(); 操作,從而實現統計所有請求總數。重啟服務,訪問多次不同的接口,然后在 Prometheus UI 界面執行 PromSQL 查詢,查詢語句為 app_requests_count_total{application="springboot2-prometheus", instance="springboot2-prometheus", v1="core"} 查詢結果如下:

img

可以看到,能夠正確統計出來所有的請求數量,現在,我們可以在 Grafana 上之前的面板上增加一個新的 Query 並圖形化顯示出來了,Query 語句為: app_requests_count_total{application="$application", instance="$instance",v1="core"}, 添加完成后,展示效果如下:

img

6.3、監控實時在線人數

接下來,來演示下如何監控瞬時數據變化,例如實時交易總金額,實時網絡請求響應時間,實時在線人數等,這里我們簡單模擬一下實時在線人數監控,這里采用 Gauge 計量儀來做為指標統計類型,在 IndexController.java 中添加相關代碼如下:

@RestController
@RequestMapping("/v1")
public class IndexController {

    @Autowired
    MeterRegistry registry;

    private Counter counter_core;
    private Counter counter_index;
    private AtomicInteger app_online_count;

    @PostConstruct
    private void init(){
        counter_core = registry.counter("app_requests_method_count", "method", "IndexController.core");
        counter_index = registry.counter("app_requests_method_count", "method", "IndexController.index");
        app_online_count = registry.gauge("app_online_count", new AtomicInteger(0));
    }

    @RequestMapping(value = "/index")
    public Object index(){
        try{
            counter_index.increment();
        } catch (Exception e) {
            return e;
        }
        return counter_index.count() + " index of springboot2-prometheus.";
    }

    @RequestMapping(value = "/core")
    public Object coreUrl(){
        try{
            counter_core.increment();
        } catch (Exception e) {
            return e;
        }
        return counter_core.count() + " coreUrl Monitor by Prometheus.";
    }
    
    @RequestMapping(value = "/online")
    public Object onlineCount(){
        int people = 0;
        try {
            people = new Random().nextInt(2000);
            app_online_count.set(people);
        } catch (Exception e){
            return e;
        }
        return "current online people: " + people;
    }
}

重啟服務,訪問一下 /v1/online 接口,得到一個 2000 以內的隨機數作為實時在線人數,瀏覽器訪問一下,得到結果如下:

img

我們在 Prometheus UI 界面執行一下 PromeSQL 查詢語句 app_online_count{application="springboot2-prometheus", instance="springboot2-prometheus"},同樣能夠對應獲取到實時數據。

img

繼續在 Grafana 上之前的面板上增加一個新的 Query 並圖形化顯示出來,Query 語句為: app_online_count{application="$application", instance="$instance"}, 添加完成后,展示效果如下:

img

注意:這里我采用了 Grafana 中 Gauge 圖形來展示的,可以根據實際要求來展示對應的數據。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM