Spring Boot有個子項目Spring Boot Actuator,它為應用提供了強大的監控能力。從Spring Boot 2.0開始,Actuator將底層改為Micrometer,提供了更強、更靈活的監控能力。本次便利用Micrometer搭建出一套可視化的監控體系。
Micrometer
Micrometer 為 Java 平台上的性能數據收集提供了一個通用的 API,應用程序只需要使用 Micrometer 的通用 API 來收集性能指標即可。Micrometer 會負責完成與不同監控系統的適配工作。這就使得切換監控系統變得很容易。Micrometer 還支持推送數據到多個不同的監控系統。
我們首先引入相關的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
在Micrometer中有以下幾種指標
計數器
只加不減,通常用於記錄服務的請求數量
public static void main(String[] args) throws Exception {
//tag必須成對出現,也就是偶數個
Counter counter = Counter.builder("counter")
.tag("counter", "counter")
.description("counter")
.register(new SimpleMeterRegistry());
counter.increment();
counter.increment(2D);
System.out.println(counter.count());
System.out.println(counter.measure());
//全局靜態方法
Metrics.addRegistry(new SimpleMeterRegistry());
counter = Metrics.counter("counter", "counter", "counter");
counter.increment(10086D);
counter.increment(10087D);
System.out.println(counter.count());
System.out.println(counter.measure());
}
儀表
表示單個數值的度量,它可以表示任意地上下移動的數值測量。通常用於變動的測量值,如當前的內存使用情況,同時也可以測量上下移動的”計數”,比如隊列中的消息數量
public static void main(String[] args) throws Exception {
AtomicInteger atomicInteger = new AtomicInteger();
Gauge gauge = Gauge.builder("gauge", atomicInteger, AtomicInteger::get)
.tag("gauge", "gauge")
.description("gauge")
.register(new SimpleMeterRegistry());
atomicInteger.addAndGet(5);
System.out.println(gauge.value());
System.out.println(gauge.measure());
atomicInteger.decrementAndGet();
System.out.println(gauge.value());
System.out.println(gauge.measure());
Metrics.addRegistry(new SimpleMeterRegistry());
AtomicInteger other = Metrics.gauge("gauge", atomicInteger, AtomicInteger::get);
System.out.println(other);
}
摘要
用於跟蹤事件的分布。它類似於一個計時器,但更一般的情況是,它的大小並不一定是一段時間的測量值。在micrometer中,對應的類是DistributionSummary,它的用法有點像Timer,但是記錄的值是需要直接指定,而不是通過測量一個任務的執行時間。
public static void main(String[] args) throws Exception {
DistributionSummary summary = DistributionSummary.builder("summary")
.tag("summary", "summary")
.description("summary")
.register(new SimpleMeterRegistry());
summary.record(2D);
summary.record(3D);
summary.record(4D);
System.out.println(summary.measure());
System.out.println(summary.count());
System.out.println(summary.max());
System.out.println(summary.mean());
System.out.println(summary.totalAmount());
}
計時器
測量一個特定的代碼邏輯塊的調用(執行)速度和它的時間分布
public static void main(String[] args) throws Exception{
Timer timer = Timer.builder("timer")
.tag("timer","timer")
.description("timer")
.register(new SimpleMeterRegistry());
timer.record(()->{
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
//ignore
}
});
System.out.println(timer.count());
System.out.println(timer.measure());
System.out.println(timer.totalTime(TimeUnit.SECONDS));
System.out.println(timer.mean(TimeUnit.SECONDS));
System.out.println(timer.max(TimeUnit.SECONDS));
}
有了以上幾個api后我們就能實現簡單的自定義監控指標進行測量。但是這樣的數據無法直接的顯示到頁面上。所以我們這里還需要引入兩個中間件
Prometheus
Prometheus 是一套開源的系統監控報警框架
作為新一代的監控框架,Prometheus 具有以下特點:
靈活而強大的查詢語句(PromQL):在同一個查詢語句,可以對多個 metrics 進行乘法、加法、連接、取分數位等操作。
易於管理: Prometheus server 是一個單獨的二進制文件,可直接在本地工作,不依賴於分布式存儲。
高效:平均每個采樣點僅占 3.5 bytes,且一個 Prometheus server 可以處理數百萬的 metrics。
使用 pull 模式采集時間序列數據,這樣不僅有利於本機測試而且可以避免有問題的服務器推送壞的 metrics。
可以采用 push gateway 的方式把時間序列數據推送至 Prometheus server 端。
可以通過服務發現或者靜態配置去獲取監控的 targets。
有多種可視化圖形界面。
我們先下載安裝 Prometheus
為了更直接的操作,我們這次不使用docker。去官網下載壓縮文件解壓執行
wget https://github.com/prometheus/prometheus/releases/download/v2.11.1/prometheus-2.11.1.darwin-amd64.tar.gz
tar -zvxf prometheus-2.11.1.darwin-amd64.tar.gz
解壓完成后修改Prometheus的配置文件prometheus.yml。將metrics_path和 static_configs.targets的地址修改成項目的地址。
# 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'.
metrics_path: /prometheus
static_configs:
- targets: ['localhost:9091']
然后運行prometheus
./prometheus -config.file=prometheus.yml
這個時候我們要在項目中增加一個prometheus依賴這樣就能把項目中斷點數據暴露到prometheus了。
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
訪問 http://localhost:9090/targets
這個時候項目的數據已經能夠展示成一個圖表了。但還不夠直觀,這里我們再引入grafana
grafana
Grafana是一個跨平台的開源的度量分析和可視化工具,可以通過將采集的數據查詢然后可視化的展示,並及時通知。它主要有以下六大特點:
1、展示方式:快速靈活的客戶端圖表,面板插件有許多不同方式的可視化指標和日志,官方庫中具有豐富的儀表盤插件,比如熱圖、折線圖、圖表等多種展示方式;
2、數據源:Graphite,InfluxDB,OpenTSDB,Prometheus,Elasticsearch,CloudWatch和KairosDB等;
3、通知提醒:以可視方式定義最重要指標的警報規則,Grafana將不斷計算並發送通知,在數據達到閾值時通過Slack、PagerDuty等獲得通知;
4、混合展示:在同一圖表中混合使用不同的數據源,可以基於每個查詢指定數據源,甚至自定義數據源;
5、注釋:使用來自不同數據源的豐富事件注釋圖表,將鼠標懸停在事件上會顯示完整的事件元數據和標記;
6、過濾器:Ad-hoc過濾器允許動態創建新的鍵/值過濾器,這些過濾器會自動應用於使用該數據源的所有查詢。
安裝
wget https://dl.grafana.com/oss/release/grafana-6.2.5.darwin-amd64.tar.gz
tar -zxvf grafana-6.2.5.darwin-amd64.tar.gz
默認配置先不用改
./grafana-server
運行grafana,訪問localhost:3000 賬號密碼是admin/admin。我們就進入grafana的界面了
先添加一個數據源
選擇prometheus
填寫信息保存即可
再創建監控Dashboard
Dashboard也就是數據面板。規定了數據源中的數據已何種方式展現。我們這里選擇導入別人已有的數據面板。前往 Grafana Lab - Dashboards,選擇適合的數據面板
輸入后即可看到類似如下的界面,選擇數據源,並點擊Import。
此時,即可看到類似如下的界面,如圖所示,我們常關心的指標該Dashboard均已支持!
好了,一個簡單的監控系統小案例就完成了。
那現在我們想要自定義一些指標展現到面板上。舉個例子,我們要統計所有HTTP請求數量。
首先添加一個攔截器,在連接器中用一個Counter做累加器
/**
* @author Xu.Minzhe
* @version V1.0
* @package com.xmz.consume.micrometer
* @class: SampleMvcInterceptor.java
* @description: 統計所有入站的Http請求數量(包括成功、失敗和非法的)
* @Date 2019-07-18 16:40
*/
//請求攔截器
@Component
public class SampleMvcInterceptor extends HandlerInterceptorAdapter {
private static final Counter COUNTER = Counter.builder("Http請求統計")
.tag("HttpCount", "HttpCount")
.description("Http請求統計")
.register(Metrics.globalRegistry);
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
COUNTER.increment();
}
}
/**
* @author Xu.Minzhe
* @version V1.0
* @package com.xmz.consume.micrometer.interceptor
* @class: SampleWebMvcConfigurer.java
* @description:
* @Date 2019-07-18 16:42
*/
@Component
public class SampleWebMvcConfigurer implements WebMvcConfigurer {
@Autowired
private SampleMvcInterceptor sampleMvcInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sampleMvcInterceptor);
}
}
然后我們訪問http://localhost:9091/prometheus 查看prometheus的的斷點中是否多了Http請求統計
然后有了上述端點后我們在grafana中添加http請求的數據窗口
保存后我們就能在dashboard上看得我我們的監控指標了
參考
https://www.ibm.com/developerworks/cn/java/j-using-micrometer-to-record-java-metric/index.html
http://www.itmuch.com/spring-boot/actuator-prometheus-grafana/