在10 分钟教你使用Prometheus监控Spring Boot工程中介绍了如何使用Prometheus监控Spring Boot提供的默认指标,这篇介绍如何自定义业务指标,并使用Prometheus进行监控并报警,同时在 Grafana 进行展现。
示例介绍
充值次数 充值金额 提现次数 提现金额 余额
Counter:只增不减的计数器,用作定义充值次数、提现次数
Gauge:可增可减的仪表盘,侧重于反应系统的当前状态,用作定义余额
Summary:用于记录某些东西的平均大小,也可以计算总和,用作定义充值金额、提现金额


监控与验证
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,开启监控的端点
#监控的端点
management.endpoints.web.exposure.include=*
#应用程序名称,在prometheus 上会显示
management.metrics.tags.application=${spring.application.name}
#tomcat 指标需要开启
server.tomcat.mbeanregistry.enabled=true
编写业务代码,提供体现和充值方法,并在init方法中定义五个业务指标,使用了三种Metrics类型
package com.adx.service;
import java.math.BigDecimal;
/**
* @author gao_liang
* @date 2024-05-31 上午9:16
*/
public interface IAccountService {
void withdrawOrder(BigDecimal amount);
void depositOrder(BigDecimal amount);
}
package com.adx.service.impl;
import com.adx.service.IAccountService;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
/**
* @author gao_liang
* @date 2024-05-31 上午9:18
*/
@Service
@Slf4j
public class IAccountServiceImpl implements IAccountService {
@Autowired
private MeterRegistry registry;
//入金笔数
private Counter depositCounter;
// 出金笔数
private Counter withdrawCounter;
//入金金额
private DistributionSummary depositAmountSummary;
// 出金金额
private DistributionSummary withdrawAmountSummary;
//余额
private BigDecimal balance = new BigDecimal(1000);
/**
* 初始化函数,用于在对象构造完成后执行一次性的配置或资源获取。
* 该方法没有参数,也没有返回值。
* 主要完成以下功能:
* 1. 初始化存款计数器;
* 2. 初始化取款计数器;
* 3. 初始化存款金额统计;
* 4. 初始化取款金额统计;
* 5. 注册余额的实时 gauge 仪表盘。
*/
@PostConstruct
private void init() {
depositCounter = (Counter) registry.counter("deposit_counter", "currency", "btc");
withdrawCounter = (Counter) 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);
}
/**
* 充值操作
* 为账户增加指定金额,同时更新相关统计信息。
*
* @param amount 充值金额,使用BigDecimal类型以确保精确计算。
*/
@Override
// 充值操作
public void depositOrder(BigDecimal amount) {
log.info("depositOrder amount:{}", amount);
try {
//余额增加
balance = balance.add(amount);
//充值笔数埋点
depositCounter.increment();
//充值金额埋点
depositAmountSummary.record(amount.doubleValue());
} catch (Exception e) {
log.info("depositOrder error", e);
} finally {
log.info("depositOrder result:{}", amount);
}
}
/**
* 提现操作
*
* @param amount 提现金额
* 该方法实现用户提现功能,会检查余额是否充足,若充足则进行余额扣减,并记录提现相关数据。
*/
@Override
//提现操作
public void withdrawOrder(BigDecimal amount) {
log.info(" withdrawOrder amount:{}", amount);
try {
if (balance.subtract(amount).compareTo(BigDecimal.ZERO) < 0) {
throw new Exception("提现金额不足,提现失败");
}
//余额减少
balance = balance.subtract(amount);
// 提现笔数埋点数据
withdrawCounter.increment();
// 提现金额埋点
withdrawAmountSummary.record(amount.doubleValue());
} catch (Exception e) {
log.info("withdrawOrder error", e);
} finally {
log.info("withdrawOrder result:{}", amount);
}
}
}
Controller 方法,定义了充值
和提现
接口
package com.adx.controller;
import com.adx.constants.ControllerConstants;
import com.adx.service.IAccountService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
@RequestMapping(ControllerConstants.PATH_PREFIX + "/account")
@AllArgsConstructor
public class AccountController {
private final IAccountService accountService;
/**
* 充值
*/
@RequestMapping(value = "/deposit", method = RequestMethod.GET)
public void deposit(@RequestParam("amount") BigDecimal amount) {
accountService.depositOrder(amount);
}
/**
* 提现
*/
@RequestMapping(value = "/withdraw", method = RequestMethod.GET)
public void withdraw(@RequestParam("amount") BigDecimal amount) {
accountService.withdrawOrder(amount);
}
}
actuator/prometheus接口,如果能查询以下指标则配置成功
##充值笔数
deposit_counter_total
## 充值总金额
deposit_amount_sum
##提现笔数
withdraw_counter_total
##提现总金额
withdraw_amount_sum
## 余额
balanceGauge

Promethues 配置
prometheus.yml文件中进行配置业务系统采集点,5s 拉取一次指标,由于我的项目是部署在docker 中,所以访问主机IP 用
host.docker.internal,如果是用jar方式启动的,这里写IP:端口即可
#业务系统监控
- job_name: 'SpringBoot'
# Override the global default and
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']

/data/prometheus目录映射到容器的
/prometheus目录,因此在主机
/data/prometheus/目录创建
rules文件夹,并创建告警文件
business-alert.rules,这里告警对余额小于 500 则进行告警(下面配置需要改一下服务名字,例如我的是sa-token-demo)
groups:
- name: businessAlert
rules:
- alert: balanceAlert
expr: balanceGauge{application="sa-token-demo"} < 500
for: 20s
labels:
severity: page
team: g2park
annotations:
summary: "{{ $labels.currency }} balance is insufficient "
description: "{{ $labels.currency }} balance : {{ $value }}"
启动Prometheus,进行验证,查询采集目标,已生效
docker restart prometheus
查询充值次数,已采集
点击Alters,可以看到业务告警已经生效

AlterManager配置
在
/data/prometheus/alertmanager
目录下,新增告警模板notify-template.tmpl
,此目录映射到altermanager 的/etc/alertmanager
目录,模板包含告警和自愈两部分,2006-01-02 15:04:05
是go语言的日志格式,固定值,加28800e9
表示转换为东八区时间,即北京时间{{ define "test.html" }}
{{- if gt (len .Alerts.Firing) 0 -}}
{{ range .Alerts }}
<h1 align="left" style="color:red;">告警</h1>
<pre>
告警级别: {{ .Labels.severity }} 级 <br>
告警类型: {{ .Labels.alertname }} <br>
故障主机: {{ .Labels.instance }} <br>
告警主题: {{ .Annotations.summary }} <br>
告警详情: {{ .Annotations.description }} <br>
告警时间:{{ (.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;">恢复</h1>
<pre>
告警名称:{{ .Labels.alertname }}<br>
告警级别:{{ .Labels.severity }}<br>
告警机器:{{ .Labels.instance }}<br>
告警主题:{{ .Annotations.summary }}<br>
告警主题:{{ .Annotations.description }}<br>
告警时间:{{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
恢复时间:{{ (.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
</pre>
{{- end }}
{{- end }}
{{- end }}修改
alertmanager.yml
为以下内容,替换对应账号即可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: "系统监控告警{{- if gt (len .Alerts.Resolved) 0 -}}恢复{{ end }}" }global
: 这是一个全局配置部分,用于配置全局的Alertmanager设置。route
: 用于配置警报的路由规则。receivers
: 接收者部分,用于配置接收告警通知的收件人。to: abc123@foxmail.com
: 这是收件人的邮件地址,即接收警报通知的邮箱地址。send_resolved: true
: 这是一个布尔值,指示是否发送已解决的警报通知。在这个例子中,设置为true
,表示发送已解决的警报通知。name: default-receiver
: 这是默认接收者的名称。email_configs
: 用于指定接收邮件通知的收件人和其他相关设置。group_by: ['alertname']
: 这是一个标签列表,用于按照警报名称(alertname)进行分组。receiver: 'default-receiver'
: 这是指定默认接收者的名称,即接收警报通知的收件人。group_wait: 30s
: 在发送警报通知前等待的时间,以便将相同的警报分组在一起。group_interval: 5m
: 这是发送同一组警报通知之间的最小时间间隔。repeat_interval: 1h
: 这是在重复发送未解决的警报通知之前等待的时间间隔。smtp_smarthost
: 这是SMTP服务器的地址和端口,用于发送邮件通知。smtp_from
: 这是邮件发送方的邮件地址,即发送邮件的地址。启动Altermanager,进行验证
docker start alertmanager访问stauts,如果出现以下结果则成功

告警验证,系统默认余额为1000,调用
backend/account/withdraw
提现接口,使余额降至500,进行报警(backend是你的系统前缀,我的是/api)

http://ip:8081/api/account/withdraw?amount=800



自愈验证,调用充值
backend/account/deposit
接口,使余额大于500,等待6m 左右会收到自愈告警,如果嫌时间比较长,修改alertmanager.yml中group_wait
、group_interval
参数值即可
http://ip:8081/api/account/deposit?amount=800


Grafana配置
启动 Grafana,点击新增面板,创建三种图表,分别为余额走势
、提现与充值金额占比
、提现与充值笔数走势图
,如下

Statsum(balanceGauge{application="backend"})

Pie chartwithdraw_amount_sum{application="backend"}
deposit_amount_sum{application="backend"}

Time seriesincrease(deposit_counter_total{application="backend"}[5m])
increase(withdraw_counter_total{application="backend"}[5m])

总结
以上介绍了如何在Spring Boot中自定义业务指标以及对指标进行监控和告警,希望对你所帮助,注意以上示例只是为了简单便于理解才是这样写,真实使用中,指标可以与数据库或者缓存进行结合,比如余额报警,调用查询余额接口即可.
------
---THE END---





