前言
在现代应用开发中,监控系统已经成为保障服务稳定性和可靠性的关键组成部分。通过实时监控应用的各项指标,我们可以及时发现潜在问题,快速定位故障原因,甚至预测系统可能出现的风险。
Grafana 作为一款功能强大的开源可视化监控工具,结合 Prometheus 等时序数据库,可以帮助我们构建一套完整的监控体系。本文将详细介绍如何使用 Grafana 监控 Spring Boot 应用的服务指标,从依赖引入到面板配置,全方位覆盖监控系统的搭建和使用。
1. 监控体系架构
在开始实际操作之前,让我们先了解一下本文将要搭建的监控体系架构:
- 应用层:Spring Boot 应用,通过 Actuator 和 Micrometer 暴露指标
- 采集层:Prometheus,负责采集和存储应用指标
- 可视化层:Grafana,负责将指标数据可视化展示
这种架构是目前业界比较流行的监控方案,具有以下优势:
- 低侵入性:通过依赖引入即可实现基础监控
- 可扩展性:支持自定义业务指标
- 可视化效果好:Grafana 提供丰富的图表类型和配置选项
- 告警能力强:支持设置告警规则,及时发现问题
2. 依赖引入
在项目的 pom.xml 文件中添加以下依赖:
xml
<!-- 监控核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<!-- 使用与项目 Spring Boot 版本匹配的版本 -->
</dependency>
<!-- Prometheus 指标 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<!-- 使用与项目 Spring Boot 版本匹配的版本 -->
</dependency>
依赖说明:
spring-boot-starter-actuator:Spring Boot 提供的监控核心依赖,暴露各种监控端点micrometer-registry-prometheus:Micrometer 的 Prometheus 注册表实现,用于将应用指标转换为 Prometheus 格式
3. 配置
在项目的 application.yml 或 application.properties 文件中添加以下配置:
3.1 基本配置
yaml
management:
endpoints:
web:
exposure:
include: health,info,prometheus # 暴露的端点
endpoint:
health:
show-details: always # 显示健康检查的详细信息
3.2 高级配置(可选)
yaml
management:
metrics:
tags:
application: ${spring.application.name} # 添加应用名称标签
export:
prometheus:
enabled: true
step: 1m # 指标收集间隔
配置说明:
management.endpoints.web.exposure.include:指定需要暴露的端点,这里我们暴露了health、info和prometheus三个端点management.endpoint.health.show-details:设置为always可以在健康检查端点中显示详细信息management.metrics.tags:为所有指标添加全局标签,这里添加了应用名称标签,便于在多应用场景下区分management.metrics.export.prometheus.step:设置指标导出的时间间隔,默认为 1 分钟
4. Prometheus 和 Grafana 部署
4.1 使用 Docker 部署
4.1.1 创建 docker-compose.yml 文件
yaml
version: '3'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
restart: always
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
volumes:
- grafana-storage:/var/lib/grafana
restart: always
depends_on:
- prometheus
volumes:
grafana-storage:
4.1.2 创建 prometheus.yml 配置文件
yaml
global:
scrape_interval: 15s # 全局抓取间隔
scrape_configs:
- job_name: 'spring-application'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080'] # 应用服务地址,Windows 环境使用 host.docker.internal
# 如果是 Linux 环境,使用实际的 IP 地址,例如:['192.168.1.100:8080']
配置说明:
scrape_interval:设置 Prometheus 的全局抓取间隔,默认为 15 秒job_name:设置抓取任务的名称,便于在 Prometheus 中识别metrics_path:指定指标暴露的路径,Spring Boot 应用默认是/actuator/prometheustargets:指定需要抓取的目标地址,这里需要根据实际环境设置
4.1.3 启动服务
在包含 docker-compose.yml 文件的目录中执行:
bash
docker-compose up -d
4.2 访问地址
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (默认用户名/密码: admin/admin)
5. 自定义指标添加(Micrometer 业务指标常见编码案例)
5.1 注入 MeterRegistry
java
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MetricsService {
private final MeterRegistry registry;
@Autowired
public MetricsService(MeterRegistry registry) {
this.registry = registry;
}
// 指标相关方法
}
5.2 计数器(Counter)
用于统计事件发生的次数,例如成功请求数、失败请求数等。
5.2.1 编程式开发
java
// 基本计数器
Counter successCounter = Counter.builder("success_total")
.description("成功次数")
.tag("service", "user") // 添加标签
.register(registry);
// 使用计数器
successCounter.increment(); // 增加 1
successCounter.increment(5); // 增加指定值
5.2.2 注解式开发
从 Spring Boot 2.5+ 开始,可以直接使用 Micrometer 提供的 @io.micrometer.core.annotation.Counted 注解来实现计数器功能:
使用示例:
java
import io.micrometer.core.annotation.Counted;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
// 使用 Micrometer 提供的 @Counted 注解
@Counted(value = "user.login.count",
description = "用户登录次数",
extraTags = {"service", "user", "operation", "login"})
@GetMapping("/api/user/login")
public String login(String username, String password) {
// 执行业务逻辑
return "登录成功";
}
}
注解参数说明:
value:计数器名称,默认值为被注解方法的完全限定名description:计数器描述extraTags:额外的标签,格式为{"key1", "value1", "key2", "value2"}recordFailuresOnly:是否只记录失败的调用,默认为falsefailureTag:当recordFailuresOnly为true时,失败标签的名称
注意事项:
- 要使
@Counted注解生效,需要确保应用中已配置MeterRegistry实例 - 对于 Spring Boot 应用,只要添加了相关依赖,Spring Boot 会自动配置
MeterRegistry - 注解式计数器会在方法执行完成后自动增加计数,无需手动调用
increment()方法
5.3 仪表盘(Gauge)
用于测量当前值,例如当前在线用户数、队列长度等。
java
// 基本仪表盘
AtomicInteger onlineUsers = new AtomicInteger(0);
Gauge.builder("online_users", onlineUsers, AtomicInteger::get)
.description("当前在线用户数")
.register(registry);
// 使用仪表盘
onlineUsers.incrementAndGet(); // 增加在线用户数
onlineUsers.decrementAndGet(); // 减少在线用户数
5.4 计时器(Timer)
用于测量操作的执行时间,例如请求处理时间、方法执行时间等。
5.4.1 编程式开发
java
// 方法 1:手动计时
Timer timer = Timer.builder("request_processing_time")
.description("请求处理时间")
.tag("endpoint", "/api/user")
.register(registry);
// 使用计时器
Timer.Sample sample = Timer.start(registry);
try {
// 执行业务逻辑
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
sample.stop(timer);
}
5.4.2 注解式开发
从 Spring Boot 2.5+ 开始,可以直接使用 Micrometer 提供的 @Timed 注解来实现方法执行时间的监控,无需手动创建计时器实例。
依赖要求:
- Spring Boot 2.5+
- 确保已添加
spring-boot-starter-actuator和micrometer-registry-prometheus依赖
使用示例:
java
import io.micrometer.core.annotation.Timed;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
// 使用 Micrometer 提供的 @Timed 注解
@Timed(
value = "user.get", // 计时器名称
description = "获取用户信息的时间", // 计时器描述
extraTags = {"endpoint", "/api/user/{id}"}, // 额外标签
longTask = false, // 是否为长任务
percentiles = {0.5, 0.9, 0.99} // 需要统计的百分位数
)
@GetMapping("/api/user/{id}")
public User getUserById(@PathVariable Long id) {
// 执行业务逻辑
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new User(id, "张三");
}
}
注解参数说明:
value:计时器名称,默认值为被注解方法的完全限定名description:计时器描述extraTags:额外的标签,格式为{"key1", "value1", "key2", "value2"}longTask:是否为长任务,默认为falsepercentiles:需要统计的百分位数,例如{0.5, 0.9, 0.99}表示统计 50%、90% 和 99% 百分位数histogram:是否启用直方图,默认为falserecordFailuresOnly:是否只记录失败的调用,默认为false
使用注意事项:
- 要使
@Timed注解生效,需要确保应用中已配置MeterRegistry实例 - 对于 Spring Boot 应用,只要添加了相关依赖,Spring Boot 会自动配置
MeterRegistry - 注解式计时器会在方法执行完成后自动记录执行时间,无需手动调用计时方法
- 可以通过
extraTags参数添加业务相关的标签,便于在 Grafana 中进行多维度分析
5.5 分布摘要(DistributionSummary)
用于测量事件的分布情况,例如响应大小、订单金额等。
java
// 基本分布摘要
DistributionSummary responseSize = DistributionSummary.builder("response_size")
.description("响应大小")
.baseUnit("bytes")
.register(registry);
// 使用分布摘要
responseSize.record(1024); // 记录 1024 bytes
6. Grafana 监控面板配置
6.1 添加 Prometheus 数据源
- 登录 Grafana(默认地址:http://localhost:3000,默认用户名/密码:admin/admin)
- 点击左侧菜单的 "Configuration" -> "Data sources"
- 点击 "Add data source"
- 选择 "Prometheus"
- 在 "URL" 字段中输入 Prometheus 的地址(例如:http://prometheus:9090)
- 点击 "Save & Test" 按钮,确保连接成功
6.2 创建监控面板
- 点击左侧菜单的 "Create" -> "Dashboard"
- 点击 "Add new panel"
- 在 "Query" 标签页中,选择之前添加的 Prometheus 数据源
- 在查询编辑器中输入 PromQL 查询语句,例如:
- 查看成功次数:
success_total{service="user"} - 查看在线用户数:
online_users - 查看请求处理时间:
rate(request_processing_time_sum[5m]) / rate(request_processing_time_count[5m])
- 查看成功次数:
- 在 "Visualization" 标签页中选择合适的图表类型(例如:Graph、Gauge、Stat 等)
- 在 "General" 标签页中设置面板标题和描述
- 点击 "Apply" 按钮保存面板
- 点击 "Save dashboard" 按钮保存整个仪表盘
6.3 导入预定义仪表盘
Grafana 提供了许多预定义的仪表盘模板,可以直接导入使用:
- 点击左侧菜单的 "Create" -> "Import"
- 输入仪表盘 ID(例如:12856 是 Spring Boot 2.1 监控仪表盘)
- 选择之前添加的 Prometheus 数据源
- 点击 "Import" 按钮导入仪表盘
6.4 实用监控面板推荐
- 系统概览面板:显示 CPU、内存、磁盘等系统指标
- 应用性能面板:显示请求量、响应时间、错误率等应用指标
- 业务指标面板:显示与业务相关的指标,例如订单量、用户活跃度等
- JVM 监控面板:显示 JVM 相关指标,例如堆内存使用情况、GC 次数等
7. 告警配置
Grafana 不仅可以展示指标,还可以设置告警规则,当指标达到阈值时发送通知。
7.1 创建告警规则
- 打开需要设置告警的面板
- 点击面板标题,选择 "Edit"
- 切换到 "Alert" 标签页
- 点击 "Create Alert"
- 设置告警规则,包括:
- 告警名称
- 评估时间窗口
- 条件表达式
- 阈值
- 通知方式
- 点击 "Save" 按钮保存告警规则
7.2 配置通知渠道
- 点击左侧菜单的 "Alerting" -> "Notification channels"
- 点击 "Add channel"
- 选择通知类型(例如:Email、Slack、Webhook 等)
- 填写通知配置
- 点击 "Save" 按钮保存通知渠道
8. 常见问题和解决方案
8.1 无法访问 /actuator/prometheus 端点
问题 :访问 http://localhost:8080/actuator/prometheus 时返回 404 错误。
解决方案:
- 检查依赖是否正确引入
- 检查配置文件中的
management.endpoints.web.exposure.include是否包含prometheus - 检查应用是否正常启动
8.2 Prometheus 无法抓取指标
问题:在 Prometheus 中查看目标状态时显示 "DOWN"。
解决方案:
- 检查
prometheus.yml中的targets配置是否正确 - 检查应用是否可以正常访问
/actuator/prometheus端点 - 检查网络连接是否正常
8.3 Grafana 中没有数据
问题:在 Grafana 面板中看不到数据。
解决方案:
- 检查数据源配置是否正确
- 检查查询语句是否正确
- 检查 Prometheus 是否成功抓取到指标
- 检查时间范围是否设置正确
8.4 指标值不准确
问题:监控面板中的指标值与实际情况不符。
解决方案:
- 检查指标的定义和使用是否正确
- 检查标签的使用是否合理
- 检查查询语句是否正确理解了指标的含义
9. 最佳实践
9.1 指标设计原则
- 命名规范 :指标名称应使用 snake_case 格式,例如
http_requests_total - 标签合理:使用有意义的标签,便于多维度分析,但标签数量不宜过多
- 粒度适当:根据监控需求设计合适粒度的指标,避免指标过多或过少
- 类型匹配:根据监控对象选择合适的指标类型(Counter、Gauge、Timer 等)
9.2 监控体系建设建议
- 分层监控:建立应用层、中间件层、系统层的分层监控体系
- 告警策略:设置合理的告警阈值和通知策略,避免告警风暴
- 面板标准化:为不同类型的应用创建标准化的监控面板
- 定期review:定期 review 监控指标和面板,确保监控的有效性
- 持续优化:根据实际使用情况,持续优化监控体系
9.3 性能优化
- 减少指标数量:只监控必要的指标,避免过多指标影响系统性能
- 合理设置抓取间隔:根据指标变化频率设置合适的抓取间隔
- 使用标签选择器:在查询时使用标签选择器,减少数据传输量
- 启用压缩:启用 Prometheus 和 Grafana 之间的通信压缩
10. 总结
通过本文的介绍,我们已经学习了如何使用 Grafana 监控 Spring Boot 应用的服务指标,从依赖引入到面板配置,构建了一套完整的监控体系。
监控系统的建设是一个持续的过程,需要根据应用的实际情况不断调整和优化。合理的监控体系不仅可以帮助我们及时发现和解决问题,还可以为系统的性能优化和容量规划提供数据支持。