在SpringBoot中自定義指標(biāo)并使用Prometheus監(jiān)控報(bào)警
在10 分鐘教你使用Prometheus監(jiān)控Spring Boot工程中介紹了如何使用Prometheus監(jiān)控Spring Boot提供的默認(rèn)指標(biāo),這篇介紹如何自定義業(yè)務(wù)指標(biāo),并使用Prometheus進(jìn)行監(jiān)控并報(bào)警,同時(shí)在 Grafana 進(jìn)行展現(xiàn)
示例介紹
我們模擬一個(gè)賬務(wù)系統(tǒng),主要功能有:充值與提現(xiàn),其中會(huì)定義5 個(gè)業(yè)務(wù)指標(biāo),如下
- 充值次數(shù)
- 充值金額
- 提現(xiàn)次數(shù)
- 提現(xiàn)金額
- 余額
針對(duì)以上5 業(yè)務(wù)指標(biāo),會(huì)使用prometheus的三種Metrics類型,如下
- Counter:只增不減的計(jì)數(shù)器,用作定義充值次數(shù)、提現(xiàn)次數(shù)
- Gauge:可增可減的儀表盤,側(cè)重于反應(yīng)系統(tǒng)的當(dāng)前狀態(tài),用作定義余額
- Summary:用于記錄某些東西的平均大小,也可以計(jì)算總和,用作定義充值金額、提現(xiàn)金額
最終我們對(duì)以上指標(biāo)進(jìn)行 grafana 進(jìn)行展現(xiàn),同時(shí)對(duì)余額小于500 進(jìn)行告警通知,效果如下
圖片
圖片
監(jiān)控與驗(yàn)證
Spring Boot 工程配置
- 添加 maven 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
- 在application.properties,開啟監(jiān)控的端點(diǎn)
#監(jiān)控的端點(diǎn)
management.endpoints.web.exposure.include=*
#應(yīng)用程序名稱,在prometheus 上會(huì)顯示
management.metrics.tags.applicatinotallow=${spring.application.name}
#tomcat 指標(biāo)需要開啟
server.tomcat.mbeanregistry.enabled=true
- 編寫業(yè)務(wù)代碼,提供體現(xiàn)和充值方法,并在init方法中定義五個(gè)業(yè)務(wù)指標(biāo),使用了三種Metrics類型
@Service
@Slf4j
public class AccountServiceImpl implements IAccountService {
@Autowired
private MeterRegistry registry;
//入金筆數(shù)
private Counter depositCounter;
// 出金筆數(shù)
private Counter withdrawCounter;
//入金金額
private DistributionSummary depositAmountSummary;
// 出金金額
private DistributionSummary withdrawAmountSummary;
//余額
private BigDecimal balance = new BigDecimal(1000);
@PostConstruct
private void init() {
depositCounter = registry.counter("deposit_counter", "currency", "btc");
withdrawCounter = registry.counter("withdraw_counter", "currency", "btc");
depositAmountSummary = registry.summary("deposit_amount", "currency", "btc");
withdrawAmountSummary = registry.summary("withdraw_amount", "currency", "btc");
Gauge.builder("balanceGauge", () -> balance)
.tags("currency", "btc")
.description("余額")
.register(registry);
}
@Override
// 充值操作
public void depositOrder(BigDecimal amount) {
log.info("depositOrder amount:{}", amount);
try {
//余額增加
balance = balance.add(amount);
//充值筆數(shù)埋點(diǎn)
depositCounter.increment();
//充值金額埋點(diǎn)
depositAmountSummary.record(amount.doubleValue());
} catch (Exception e) {
log.info("depositOrder error", e);
} finally {
log.info("depositOrder result:{}", amount);
}
}
@Override
//提現(xiàn)操作
public void withdrawOrder(BigDecimal amount) {
log.info(" withdrawOrder amount:{}", amount);
try {
if (balance.subtract(amount).compareTo(BigDecimal.ZERO) < 0) {
throw new Exception("提現(xiàn)金額不足,提現(xiàn)失敗");
}
//余額減少
balance = balance.subtract(amount);
// 提現(xiàn)筆數(shù)埋點(diǎn)數(shù)據(jù)
withdrawCounter.increment();
// 提現(xiàn)金額埋點(diǎn)
withdrawAmountSummary.record(amount.doubleValue());
} catch (Exception e) {
log.info("withdrawOrder error", e);
} finally {
log.info("withdrawOrder result:{}", amount);
}
}
}
- Controller 方法,定義了充值和提現(xiàn)接口
@RestController
@RequestMapping(ControllerConstants.PATH_PREFIX + "/account")
public class AccountController {
@Autowired
IAccountService accountService;
/**
* 充值
*/
@RequestMapping(value = "/deposit", method = RequestMethod.GET)
public void deposit(@RequestParam("amount") BigDecimal amount) {
accountService.depositOrder(amount);
}
/**
* 提現(xiàn)
*/
@RequestMapping(value = "/withdraw", method = RequestMethod.GET)
public void withdraw(@RequestParam("amount") BigDecimal amount) {
accountService.withdrawOrder(amount);
}
}
- 啟動(dòng)服務(wù)查看,訪問actuator/prometheus接口,如果能查詢以下指標(biāo)則配置成功
##充值筆數(shù)
deposit_counter_total
## 充值總金額
deposit_amount_sum
##提現(xiàn)筆數(shù)
withdraw_counter_total
##提現(xiàn)總金額
withdraw_amount_sum
## 余額
balanceGauge
Promethues 配置
在prometheus.yml文件中進(jìn)行配置業(yè)務(wù)系統(tǒng)采集點(diǎn),5s 拉取一次指標(biāo),由于prometheus server 部署在docker 中,所以訪問主機(jī)IP 用host.docker.internal
#業(yè)務(wù)系統(tǒng)監(jiān)控
- job_name: 'SpringBoot'
# Override the global default and
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
圖片
告警規(guī)則配置,在容器啟動(dòng)時(shí)用主機(jī)的/data/prometheus目錄映射到容器的/prometheus目錄,因此在主機(jī)/data/prometheus/目錄創(chuàng)建rules文件夾,并創(chuàng)建告警文件business-alert.rules,這里告警對(duì)余額小于 500 則進(jìn)行告警
groups:
- name: businessAlert
rules:
- alert: balanceAlert
expr: balanceGauge{applicatinotallow="backend"} < 500
for: 20s
labels:
severity: page
team: g2park
annotations:
summary: "{{ $labels.currency }} balance is insufficient "
description: "{{ $labels.currency }} balance : {{ $value }}"
啟動(dòng)Prometheus,進(jìn)行驗(yàn)證,查詢采集目標(biāo),已生效
圖片
查詢充值次數(shù),已采集點(diǎn)擊Alters,可以看到業(yè)務(wù)告警已經(jīng)生效
AlterManager配置
在/data/prometheus/alertmanager目錄下,新增告警模板notify-template.tmpl,此目錄映射到altermanager 的/etc/alertmanager目錄,模板包含告警和自愈兩部分,2006-01-02 15:04:05是go語(yǔ)言的日志格式,固定值,加28800e9表示轉(zhuǎn)換為東八區(qū)時(shí)間,即北京時(shí)間
{{ define "test.html" }}
{{- if gt (len .Alerts.Firing) 0 -}}
{{ range .Alerts }}
<h1 align="left" style="color:red;">告警</h1>
<pre>
告警級(jí)別: {{ .Labels.severity }} 級(jí) <br>
告警類型: {{ .Labels.alertname }} <br>
故障主機(jī): {{ .Labels.instance }} <br>
告警主題: {{ .Annotations.summary }} <br>
告警詳情: {{ .Annotations.description }} <br>
告警時(shí)間:{{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
</pre>
{{ end }}
{{ end }}
{{- if gt (len .Alerts.Resolved) 0 -}}
{{ range .Alerts }}
<h1 align="left" style="color:green;">恢復(fù)</h1>
<pre>
告警名稱:{{ .Labels.alertname }}<br>
告警級(jí)別:{{ .Labels.severity }}<br>
告警機(jī)器:{{ .Labels.instance }}<br>
告警主題:{{ .Annotations.summary }}<br>
告警主題:{{ .Annotations.description }}<br>
告警時(shí)間:{{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
恢復(fù)時(shí)間:{{ (.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
</pre>
{{- end }}
{{- end }}
{{- end }}
修改alertmanager.yml為以下內(nèi)容,替換對(duì)應(yīng)賬號(hào)即可
global:
smtp_smarthost: smtp.qq.com:465
smtp_from: 9238223@qq.com
smtp_auth_username: 9238223@qq.com
smtp_auth_identity: 9238223@qq.com
smtp_auth_password: 123
smtp_require_tls: false
templates: #添加模板
- '/etc/alertmanager/notify-template.tmpl' #指定路徑
route:
group_by: ['alertname']
receiver: 'default-receiver'
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
receivers:
- name: default-receiver
email_configs:
- to: abc123@foxmail.com
html: '{{ template "test.html" . }}'
send_resolved: true
headers: { Subject: "系統(tǒng)監(jiān)控告警{{- if gt (len .Alerts.Resolved) 0 -}}恢復(fù){{ end }}" }
global: 這是一個(gè)全局配置部分,用于配置全局的Alertmanager設(shè)置。
route: 用于配置警報(bào)的路由規(guī)則。
receivers: 接收者部分,用于配置接收告警通知的收件人。
- to: abc123@foxmail.com: 這是收件人的郵件地址,即接收警報(bào)通知的郵箱地址。
- send_resolved: true: 這是一個(gè)布爾值,指示是否發(fā)送已解決的警報(bào)通知。在這個(gè)例子中,設(shè)置為true,表示發(fā)送已解決的警報(bào)通知。
- name: default-receiver: 這是默認(rèn)接收者的名稱。
- email_configs: 用于指定接收郵件通知的收件人和其他相關(guān)設(shè)置。
- group_by: ['alertname']: 這是一個(gè)標(biāo)簽列表,用于按照警報(bào)名稱(alertname)進(jìn)行分組。
- receiver: 'default-receiver': 這是指定默認(rèn)接收者的名稱,即接收警報(bào)通知的收件人。
- group_wait: 30s: 在發(fā)送警報(bào)通知前等待的時(shí)間,以便將相同的警報(bào)分組在一起。
- group_interval: 5m: 這是發(fā)送同一組警報(bào)通知之間的最小時(shí)間間隔。
- repeat_interval: 1h: 這是在重復(fù)發(fā)送未解決的警報(bào)通知之前等待的時(shí)間間隔。
- smtp_smarthost: 這是SMTP服務(wù)器的地址和端口,用于發(fā)送郵件通知。
- smtp_from: 這是郵件發(fā)送方的郵件地址,即發(fā)送郵件的地址。
啟動(dòng)Altermanager,進(jìn)行驗(yàn)證
docker start alertmanager
訪問stauts,如果出現(xiàn)以下結(jié)果則成功
告警驗(yàn)證,系統(tǒng)默認(rèn)余額為1000,調(diào)用backend/account/withdraw提現(xiàn)接口,使余額降至500,進(jìn)行報(bào)警
等待20s 左右,prometheus 收到報(bào)警會(huì)推送至Altermanager
圖片
Altermanager則會(huì)根據(jù)我們配置時(shí)間等待 30s,進(jìn)行通知告警
圖片
自愈驗(yàn)證,調(diào)用充值backend/account/deposit接口,使余額大于500,等待6m 左右會(huì)收到自愈告警,如果嫌時(shí)間比較長(zhǎng),修改alertmanager.yml中 group_wait、group_interval參數(shù)值即可
Grafana配置
啟動(dòng) Grafana,點(diǎn)擊新增面板,創(chuàng)建三種圖表,分別為余額走勢(shì)、提現(xiàn)與充值金額占比、提現(xiàn)與充值筆數(shù)走勢(shì)圖,如下
圖片
余額走勢(shì),報(bào)表類型為Stat
sum(balanceGauge{applicatinotallow="backend"})
圖片
提現(xiàn)與充值金額占比,報(bào)表類型為Pie chart
withdraw_amount_sum{applicatinotallow="backend"}
deposit_amount_sum{applicatinotallow="backend"}
提現(xiàn)與充值筆數(shù)走勢(shì)圖,報(bào)表類型為Time series
increase(deposit_counter_total{applicatinotallow="backend"}[5m])
increase(withdraw_counter_total{applicatinotallow="backend"}[5m])
總結(jié)
以上介紹了如何在Spring Boot中自定義業(yè)務(wù)指標(biāo)以及對(duì)指標(biāo)進(jìn)行監(jiān)控和告警,希望對(duì)你所幫助,注意以上示例只是為了簡(jiǎn)單便于理解才是這樣寫,真實(shí)使用中,指標(biāo)可以與數(shù)據(jù)庫(kù)或者緩存進(jìn)行結(jié)合,比如余額報(bào)警,調(diào)用查詢余額接口即可。