整體結構
SpringBoot 的 actuator
提供了監控端點。
Prometheus 是監控系統,可以從 Springboot 獲取監控數據,以時序數據的形式存儲,並提供了監控數據的查詢服務。
Grafana 是專業的 UI 儀表盤系統,支持非常多的數據源,其中就包括 Prometheus,可以便利的從中獲取數據,使用儀表盤展示出來。
springboot 2 中引入了 micrometer
,它可以更方便的對接各種監控系統,包括 Prometheus。
所以整體的結構就是:
- springboot(micrometer)產生監控數據。
- Prometheus 獲取 springboot 應用的監控數據,存儲,並提供數據查詢服務。
- Grafana 對接 Prometheus 數據源,調用其數據查詢服務,用專業的儀表盤 UI 進行展示。
實踐步驟
-
創建應用 -- 作為監控目標,產生監控數據。
-
集成度量庫 micrometer -- 以便對接監控系統 Prometheus。
-
部署 prometheus
-
配置 prometheus -- 監控之前創建的 springboot 應用,了解 Prometheus 的查詢服務。
-
部署 Grafana
-
添加 Prometheus 數據源
-
添加 JVM 監控儀表盤 -- 展示之前 springboot 應用的 JVM 狀態。
-
自定義監控指標 -- 自有的監控指標都是底層基礎數據,業務相關指標需要我們自己寫代碼。
-
動態變更監控目標 -- 如果監控目標發生變動就改一次 Prometheus 的配置文件,並重新啟動,這是不適合的,需要使用動態配置的方式。
1. 創建應用 集成 micrometer
創建一個最簡的 springboot 應用,添加 micrometer 依賴。
pom.xml :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot2demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot2demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.application.name=springboot2demo
# 打開所有 Actuator 服務
management.endpoints.web.exposure.include=*
# 將應用名稱添加到計量器的 tag 中去
# 以便 Prometheus 根據應用名區分不同服務
management.metrics.tags.application=${spring.application.name}
在啟動類中添加Bean,用於監控JVM性能指標:
package com.example.springboot2demo;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Springboot2demoApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot2demoApplication.class, args);
}
@Bean
MeterRegistryCustomizer<MeterRegistry> configurer(
@Value("${spring.application.name}") String applicationName) {
return (registry) -> registry.config().commonTags("application", applicationName);
}
}
啟動服務。
查看監控端點信息:
2. 部署 Prometheus
官網:
可以下載安裝包來安裝,但下載速度極其慢,幾乎下載不了。
可以使用 docker 部署,因為國內有docker鏡像,所以速度很快。
docker 方式啟動:
$ docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus
執行完成后就OK了,可以看一下 Prometheus 的界面。
http://localhost:9090/targets 是監控目標列表頁:
http://localhost:9090/graph 是查詢控制台,也有簡單的圖表展示:
現在還沒對接應用,后面對接之后可以看到詳細的內容。
3. Prometheus + Springboot應用
監控應用,需要在 Prometheus 配置文件中添加應用的相關信息。
配置文件在容器中的路徑:/etc/prometheus
。
查看一下配置文件的默認內容:
$ docker exec -it [容器ID] cat /etc/prometheus/prometheus.yml
紅框內是我們要關注的部分,按照這個形式添加我們的應用即可。
需要添加的內容為:
- job_name: 'springboot_app'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['192.168.31.6:8080']
"labels": {
"instance": "springboot2-A",
"service": "springboot2-A-service"
}
metrics_path
指定監控端點的路徑。
targets
指定應用的IP端口,這里使用了IP,沒有使用localhost
,因為 Prometheus 是容器運行的,如果使用 localhost
就會訪問容器內部。
配置不是直接在容器內部修改,可以把容器內部的配置文件拷貝出來一份,修改后,重啟啟動容器,掛載本地修改過的配置文件。
拷貝容器中的配置文件:
$ docker cp [容器ID]:/etc/prometheus/prometheus.yml .
修改配置文件,添加配置,最終的內容:
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
- job_name: 'springboot_app'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['192.168.31.6:8080']
"labels": {
"instance": "springboot2-A",
"service": "springboot2-A-service"
}
停掉之前的容器,重新啟動:
$ docker run --name prometheus -d \
-p 9090:9090 \
-v [PATH]/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
訪問監控列表頁 http://localhost:9090/targets 就可以看到我們的應用了:
點擊端點鏈接,可以看到監控數據,例如:
進入查詢控制台頁面 http://localhost:9090/graph,可以查詢一個指標,例如 http_server_requests_seconds_sum
,效果:
4. 部署 Grafana
docker方式運行:
$ docker run -d \
-p 3000:3000 \
--name=grafana \
grafana/grafana
啟動后,訪問:http://localhost:3000,默認用戶名密碼 admin/admin
。
5. 添加 Prometheus 數據源
6. 展示應用的 JVM 信息
Grafana 中已經有現成的 JVM 儀表盤,我們直接導入使用即可。
這個儀表盤的編號為 4701
。
至此,Prometheus + Grafana + Springboot 的整體流程已經跑通了。
但是,這些指標都是底層通用指標,在業務層面一定會有個性需求,下面我們自己定義一些監控指標。
7. 自定義監控指標
需求:監控所有接口的請求次數。
應用中添加依賴:
<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>
使用AOP方式對接口請求計數:
package com.example.springboot2demo;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Aspect
public class APICounterAop {
@Pointcut("execution(public * com.example.springboot2demo.*.*(..))")
public void pointCut() {
}
ThreadLocal<Long> startTime = new ThreadLocal<>();
@Autowired
MeterRegistry registry;
private Counter counter;
@PostConstruct
private void init() {
counter = registry.counter("requests_total", "status", "success");
}
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
System.out.println("do before");
counter.increment(); //請求計數
}
@AfterReturning(returning = "returnVal", pointcut = "pointCut()")
public void doAfterReturning(Object returnVal) {
System.out.println("do after");
}
}
創建一個測試接口:
package com.example.springboot2demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
重啟應用,多訪問幾次測試接口,然后查看 Prometheus 中的應用監控端點頁面,就可以看到監控結果:
然后,我們把這個指標在 Grafana 中顯示出來。
8. 動態變更監控目標
上面 Prometheus 配置文件中定義的監控目標使用的是靜態方式,改配置文件后需要重啟。
如果服務變更了,或者增加服務了,經常重啟 Prometheus 肯定不合適。
Prometheus 提供了動態加載的方式,把服務信息放到一個單獨的文件中,Prometheus 配置中指定這個外部文件,內容變化后,Prometheus 就會自動重新加載。
服務信息配置文件例如:
[
{
"targets": [
"192.168.31.6:8080"
],
"labels": {
"instance": "springboot2-A",
"service": "springboot2-A-service"
}
}
]
Prometheus 配置文件中的寫法:
...
- job_name: 'springboot_app'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
file_sd_configs:
- files:
- /home/*.json
refresh_interval: 1m
啟動 Prometheus 容器時要掛載這個服務信息配置文件的目錄:
$ docker run --name prometheus -d -p 9090:9090 \
-v [PATH]/prometheus.yml:/etc/prometheus/prometheus.yml \
-v [PATH]:/home \
prom/prometheus
推薦閱讀: