1. 为什么需要Spring Boot监控体系?
在微服务架构中,服务实例数量可能达到数百甚至上千个。我曾遇到一个线上事故:某个核心服务的内存泄漏导致整个集群雪崩,但由于缺乏有效的监控指标,直到用户投诉才发现问题。这就是为什么我们需要建立完善的监控体系——它就像分布式系统的"神经系统",能够实时感知应用的健康状态。
Spring Boot Actuator提供了生产级监控端点(如/health、/metrics),但这些数据需要专业的工具来采集、存储和可视化。Prometheus作为云原生监控的事实标准,配合Grafana的强大仪表盘能力,可以构建从指标采集到告警的完整闭环。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 依赖引入
在pom.xml中添加以下关键依赖(Spring Boot 2.7.x示例):
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
注意:Spring Boot 3.x版本需要额外配置security适配,建议使用以下安全策略:
java复制@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth ->
auth.requestMatchers("/actuator/prometheus").permitAll()
.requestMatchers("/actuator/**").authenticated()
);
return http.build();
}
2.2 指标暴露配置
在application.yml中开启必要的端点:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,prometheus
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
这里有个实际踩坑点:默认情况下,Prometheus每15秒抓取一次数据。如果应用QPS很高,建议调整micrometer的聚合窗口:
java复制@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().meterFilter(
new MeterFilter() {
@Override
public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
return DistributionStatisticConfig.builder()
.percentilesHistogram(true)
.expiry(Duration.ofMinutes(5)) // 关键配置:控制数据保留窗口
.build()
.merge(config);
}
}
);
}
3. Prometheus部署与配置实战
3.1 Docker快速部署方案
推荐使用以下docker-compose.yml部署Prometheus:
yaml复制version: '3'
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=15d' # 控制数据保留周期
对应的prometheus.yml配置示例:
yaml复制global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'spring-boot-apps'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080'] # 本地开发环境地址
labels:
env: 'dev'
3.2 磁盘空间优化技巧
当出现"prometheus磁盘空间告警"时,可以通过以下方案解决:
- 调整存储周期(默认15天):
bash复制--storage.tsdb.retention.time=7d
- 启用块压缩(v2.20+):
bash复制--storage.tsdb.head-chunks-write-buffer-size=4194304
- 对于Kubernetes环境,建议使用PVC动态扩容
4. Grafana高级可视化配置
4.1 数据源连接
在Grafana的Configuration > Data Sources中添加Prometheus:
- URL: http://prometheus:9090
- Scrape interval: 15s
- 开启"Manage alerts via Alerting UI"选项
4.2 推荐仪表盘模板
- JVM监控:ID 4701(Micrometer仪表盘)
- Spring Boot:ID 11378(官方推荐)
- 业务指标:建议自定义构建,例如:
json复制{
"panels": [{
"title": "订单创建QPS",
"targets": [{
"expr": "rate(orders_created_total[1m])",
"legendFormat": "{{instance}}"
}],
"type": "graph",
"fill": 1
}]
}
4.3 主题修改与告警配置
修改主题的方法:
- 登录Grafana
- 点击左下角齿轮图标 > Preferences
- 在UI Theme中选择Dark/Light
对于告警去重问题(如多个磁盘告警),可以在Alert Rules中使用分组规则:
yaml复制groups:
- name: disk-alerts
rules:
- alert: DiskSpaceLow
expr: predict_linear(node_filesystem_free_bytes[1h], 4*3600) < 0
for: 10m
labels:
severity: warning
annotations:
summary: "Low disk space on {{ $labels.instance }}"
# 关键配置:合并相同挂载点的告警
group_by: [mountpoint]
5. 生产环境最佳实践
5.1 指标命名规范
遵循Micrometer的命名约定:
- 计数器:
<name>_total(如http_requests_total) - 直方图:
<name>_seconds(如http_request_duration_seconds) - 计量单位:时间用seconds,大小用bytes
错误示例:
java复制// 不推荐
registry.counter("orderCount");
// 推荐
registry.counter("orders_created_total", "status", "success");
5.2 关键监控指标清单
| 指标类型 | 表达式示例 | 告警阈值建议 |
|---|---|---|
| JVM堆内存 | jvm_memory_used_bytes | > 80% of max for 5m |
| GC暂停时间 | jvm_gc_pause_seconds_max | > 1s for 3/5 samples |
| 数据库连接池 | hikaricp_connections_active | > 90% of max for 2m |
| HTTP错误率 | rate(http_requests_error_total[1m]) / rate(http_requests_total[1m]) | > 5% for 5m |
5.3 性能优化技巧
- 指标采样:对高频操作使用采样
java复制Timer.builder("api.call")
.publishPercentiles(0.95, 0.99)
.publishPercentileHistogram()
.sla(Duration.ofMillis(100))
.register(registry);
- 标签控制:避免高基数标签(如userID)
java复制// 错误示例 - 会导致指标爆炸
registry.counter("login_attempts", "userId", userId);
// 正确做法
registry.counter("login_attempts", "result", "success");
- 聚合策略:在客户端预聚合
java复制DistributionSummary summary = DistributionSummary
.builder("response.size")
.baseUnit("bytes")
.scale(100) // 将字节转换为百字节
.register(registry);
6. 典型问题排查指南
6.1 Prometheus抓取失败
排查步骤:
- 检查端点可访问性:
bash复制curl http://localhost:8080/actuator/prometheus
- 验证Prometheus目标状态:
- 访问http://prometheus:9090/targets
- 查看State是否为UP
常见问题:
- 证书问题(HTTPS场景):添加
insecure_skip_verify: true - 网络不通:检查Docker网络或K8s Service配置
6.2 Grafana数据不显示
诊断方法:
- 在Explore界面直接执行PromQL查询
- 检查时间范围选择(右上角)
- 验证数据源连接测试
一个真实案例:由于时区设置不一致(Grafana UTC vs 本地时区),导致图表显示异常。解决方案:
ini复制[grafana]
default_timezone = Asia/Shanghai
6.3 指标丢失问题
可能原因及解决方案:
- 应用重启:配置Prometheus的
scrape_interval小于应用启动时间 - 标签变更:避免动态标签值,使用
meterFilter过滤
java复制registry.config().meterFilter(MeterFilter.ignoreTags("sessionId"));
- 内存限制:调整Prometheus的
--storage.tsdb.memory-chunks参数
我在实际项目中发现,当自定义指标超过5000个时,需要调整JVM参数:
bash复制JAVA_OPTS="-Xmx512m -XX:MaxMetaspaceSize=256m"
