1. 项目概述
Spring Boot Actuator作为Spring生态中不可或缺的监控组件,为开发者提供了开箱即用的应用监控能力。但在实际生产环境中,仅使用默认配置往往难以满足复杂的监控需求。本文将深入探讨如何通过Actuator实现细粒度指标采集,并与Prometheus监控系统进行深度集成。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心需求解析
2.1 监控指标采集的痛点
在微服务架构下,传统监控方式面临三大挑战:
- 指标维度单一:默认的/actuator/metrics端点提供的基础指标(如JVM内存、线程数)无法反映业务状态
- 采集频率固定:预设的采样间隔可能错过关键业务峰值
- 数据孤岛问题:各服务监控数据分散,缺乏统一视图
2.2 Prometheus集成的价值
Prometheus作为云原生监控的事实标准,与Actuator结合可带来:
- 多维数据模型:支持按标签(label)进行灵活查询
- 强大的告警能力:基于PromQL实现复杂告警规则
- 可视化集成:与Grafana无缝配合,打造专业监控看板
3. 技术实现方案
3.1 基础环境搭建
3.1.1 依赖配置
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>
3.1.2 关键配置项
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
3.2 自定义指标开发
3.2.1 计数器(Counter)实现
java复制@RestController
public class OrderController {
private final Counter orderCounter;
public OrderController(MeterRegistry registry) {
this.orderCounter = Counter.builder("orders.total")
.description("Total order count")
.tags("region", System.getenv("REGION"))
.register(registry);
}
@PostMapping("/orders")
public void createOrder() {
orderCounter.increment();
// 业务逻辑...
}
}
3.2.2 计时器(Timer)应用
java复制@Aspect
@Component
public class ApiMonitorAspect {
private final Timer apiTimer;
public ApiMonitorAspect(MeterRegistry registry) {
this.apiTimer = Timer.builder("api.latency")
.publishPercentiles(0.5, 0.95, 0.99)
.register(registry);
}
@Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object monitorApi(ProceedingJoinPoint pjp) throws Throwable {
return apiTimer.record(() -> {
try {
return pjp.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
});
}
}
3.3 Prometheus集成配置
3.3.1 服务发现配置
yaml复制scrape_configs:
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
relabel_configs:
- source_labels: [__address__]
target_label: instance
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
3.3.2 采样频率优化
yaml复制management:
metrics:
export:
prometheus:
step: 15s # 默认1分钟改为15秒
distribution:
percentiles:
http.server.requests: 0.5,0.75,0.95,0.99
4. 高级监控场景实现
4.1 业务指标监控
4.1.1 库存预警指标
java复制@Scheduled(fixedRate = 30000)
public void checkInventory() {
int stock = inventoryService.getStock();
Metrics.gauge("inventory.level",
Tags.of("productId", "123"),
stock);
if(stock < 10) {
Metrics.counter("inventory.alert",
Tags.of("severity", "critical"))
.increment();
}
}
4.1.2 支付成功率监控
java复制@Aspect
@Component
public class PaymentMonitor {
private final Counter successCounter;
private final Counter failureCounter;
public PaymentMonitor(MeterRegistry registry) {
this.successCounter = registry.counter("payment.result", "status", "success");
this.failureCounter = registry.counter("payment.result", "status", "failure");
}
@AfterReturning("execution(* com..payment.PaymentService.process(..))")
public void onSuccess() {
successCounter.increment();
}
@AfterThrowing("execution(* com..payment.PaymentService.process(..))")
public void onFailure() {
failureCounter.increment();
}
}
4.2 动态标签管理
4.2.1 请求上下文标签
java复制@Configuration
public class MetricsConfig {
@Bean
MeterFilter addCommonTags() {
return MeterFilter.commonTags(Arrays.asList(
Tag.of("env", System.getenv("APP_ENV")),
Tag.of("zone", System.getenv("ZONE"))
));
}
@Bean
MeterFilter ignoreUris() {
return MeterFilter.deny(id -> {
String uri = id.getTag("uri");
return uri != null && uri.startsWith("/actuator");
});
}
}
5. 性能优化与问题排查
5.1 内存泄漏预防
重要提示:高频率指标采集可能导致内存堆积,建议:
- 对于Gauge类型指标,使用WeakReference持有测量对象
- 定期清理不再使用的指标标签组合
java复制@Bean
MeterFilter expireOldMetrics() {
return MeterFilter.maximumAllowableTags(
"http.server.requests",
"uri",
100,
MeterFilter.deny()
);
}
5.2 采集性能优化
5.2.1 指标采样策略
yaml复制management:
metrics:
enable:
jvm: true
system: true
logback: false # 非必要不开启
distribution:
sla:
http.server.requests: 100ms,500ms,1s
5.2.2 Prometheus抓取优化
yaml复制scrape_configs:
- job_name: 'spring-actuator'
scrape_interval: 15s
scrape_timeout: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['service1:8080', 'service2:8080']
5.3 常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| Prometheus无数据 | 端点未暴露 | 检查management.endpoints.web.exposure.include配置 |
| 指标缺失 | 未正确注册 | 确保MeterRegistry注入成功 |
| 标签值混乱 | 标签动态变化 | 限制标签取值范围或使用有限枚举值 |
| 内存持续增长 | 指标累积过多 | 配置MeterFilter清理旧指标 |
6. 生产环境最佳实践
6.1 安全防护措施
6.1.1 端点访问控制
java复制@Configuration
@Profile("prod")
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
.anyRequest().hasRole("MONITOR")
.and()
.httpBasic();
}
}
6.1.2 敏感信息过滤
yaml复制management:
endpoint:
health:
show-details: never
metrics:
export:
prometheus:
descriptions: false # 生产环境关闭描述文本
6.2 监控看板设计
6.2.1 关键业务指标
- 请求成功率:sum(rate(http_server_requests_seconds_count{status!~"5.."}[1m])) / sum(rate(http_server_requests_seconds_count[1m]))
- 平均响应时间:histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[1m])) by (le, uri))
6.2.2 JVM监控模板
promql复制# 内存使用
sum(jvm_memory_used_bytes{area="heap"}) by (instance) / sum(jvm_memory_max_bytes{area="heap"}) by (instance)
# GC次数
rate(jvm_gc_pause_seconds_count[1m])
6.3 告警规则配置
6.3.1 基础告警规则
yaml复制groups:
- name: spring-alerts
rules:
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status=~"5.."}[1m]) / rate(http_server_requests_seconds_count[1m]) > 0.01
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.instance }}"
description: "Error rate is {{ $value }}"
6.3.2 业务告警示例
yaml复制 - alert: InventoryLow
expr: inventory_level < 10
for: 10m
labels:
severity: warning
annotations:
summary: "Low inventory for product {{ $labels.productId }}"
7. 扩展集成方案
7.1 与Grafana联动
7.1.1 看板导入配置
json复制{
"title": "Spring Boot Monitoring",
"panels": [
{
"title": "Request Rate",
"targets": [{
"expr": "rate(http_server_requests_seconds_count[1m])",
"legendFormat": "{{instance}} - {{uri}}"
}]
}
]
}
7.2 多维度日志关联
7.2.1 日志标记示例
java复制@RestController
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
@PostMapping("/orders")
public ResponseEntity createOrder() {
log.info("Order created",
StructuredArguments.keyValue("traceId", MDC.get("traceId")),
StructuredArguments.keyValue("metrics.orders", 1));
return ResponseEntity.ok().build();
}
}
7.3 跨服务监控
7.3.1 分布式追踪集成
xml复制<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
yaml复制management:
tracing:
sampling:
probability: 1.0
8. 版本升级策略
8.1 从Spring Boot 2.x迁移
8.1.1 指标名称变化对照
| 旧指标名 | 新指标名 |
|---|---|
| http.server.requests | http.server.requests |
| system.cpu.usage | process.cpu.usage |
| jvm.memory.max | jvm.memory.max |
8.1.2 废弃API处理
java复制// 旧方式(废弃)
Metrics.addRegistry(new SimpleMeterRegistry());
// 新方式
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("region", "us-east");
}
8.2 Micrometer配置调整
8.2.1 直方图配置变化
yaml复制management:
metrics:
distribution:
percentiles-histogram:
http.server.requests: true
percentiles:
http.server.requests: 0.95,0.99
sla:
http.server.requests: 500ms,1s
9. 实战经验总结
-
标签设计原则:
- 避免高基数标签(如user_id)
- 使用有限枚举值(如region=east/west)
- 业务维度与系统维度分离
-
采集频率权衡:
- 业务指标:15-30秒
- 系统指标:1分钟
- 高频指标考虑客户端聚合
-
指标命名规范:
- 统一使用.分隔单词(orders.total)
- 避免特殊字符(_/-)
- 单位作为后缀(duration.seconds)
-
监控策略建议:
- 核心业务指标配置SLO告警
- 非核心指标仅做趋势观察
- 定期review指标使用情况
