微服务监控体系:Prometheus + Grafana + 自定义指标,SLO/SLI/SLA 落地
提出问题
微服务架构下,服务数量从 10 个增长到 100 个,每个服务都有独立的 CPU、内存、线程池、GC 行为、请求量、延迟、错误率。运维人员面对几十个 Grafana 面板,每天收到 200+ 条告警,但真正需要人工介入的故障反而被淹没在告警噪音里。更常见的问题是:某个服务出错率升到 5%,团队觉得"还行"没处理,等发现问题时已经影响了 10 分钟的用户体验。
问题出在哪里?不是工具不够,是没有把监控和业务目标绑定。没有 SLO(服务等级目标),你就没法回答"5% 的错误率到底算不算严重";没有 Error Budget,你就没法在可用性和发布速度之间做理性决策。本文从四层监控体系搭建讲起,一直到 SLO/SLI 的落地实践,帮你把监控从"搭几个大盘"升级为"驱动架构决策的量化体系"。
分析问题
四层监控体系:从基础设施到业务指标
微服务监控不能只盯着 CPU 和请求量,一个完整的监控体系应该覆盖四个层次:
第一层:基础设施层。CPU、内存、磁盘、网络、IO 等操作系统级指标,通过 Node Exporter 暴露给 Prometheus。这一层是"服务还活着吗"的底线判断,但不能作为核心告警源——CPU 飙到 90% 不代表服务不可用,很多服务在 90% CPU 下仍然正常运行。
第二层:中间件层。MySQL、Redis、Kafka、Nginx 等中间件的运行状态。Redis Exporter 采集 hit/miss 率、内存碎片率;Kafka Exporter 采集消费组 lag、分区 Leader 分布;MySQL Exporter 采集连接数、慢查询数、InnoDB 状态。这一层往往是被忽视的——很多团队只监控应用层,等 MySQL 连接池满了才发现问题。
第三层:应用层——RED 指标。Google SRE 提出的 RED 方法论:Rate(请求量)、Errors(错误率)、Duration(延迟)。每个服务至少暴露三个指标:
// Micrometer 埋点示例
@RestController
public class OrderController {
private final MeterRegistry meterRegistry;
private final Counter orderCreateCounter;
private final Timer orderCreateTimer;
public OrderController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCreateCounter = Counter.builder("order_create_total")
.tag("service", "order-service")
.register(meterRegistry);
this.orderCreateTimer = Timer.builder("order_create_duration_seconds")
.tag("service", "order-service")
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry);
}
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest req) {
return orderCreateTimer.record(() -> {
Order order = orderService.create(req);
orderCreateCounter.increment();
return ResponseEntity.ok(order);
});
}
}Spring Boot 应用只需引入 micrometer-registry-prometheus,在 application.yml 中配置暴露 /actuator/prometheus 端点,Prometheus 自动抓取。注意:不要暴露 env、user 等敏感信息到 Prometheus 标签中。
第四层:业务层。订单量、支付成功率、转化率、用户活跃度等业务特有指标。这一层由业务团队自己定义,通过 Micrometer 的 Gauge/Counter 注册。业务指标的价值在于:当应用层指标正常但业务指标异常时,说明业务逻辑有 bug。
业务层指标落地:一个真实案例
2024 年我在一家电商平台做过一次排查:Grafana 看应用层 RED 指标全部正常——请求量 2000 QPS、P99 延迟 150ms、错误率 0.01%,但业务团队反馈"今天下单成功量比昨天少了 30%"。为什么?因为下单接口返回了 200,但库存扣减服务返回了「库存不足」业务错误——HTTP 状态码是 200,业务 code 是 4001。应用层指标只盯着 HTTP 状态码,根本抓不到。
解决方案:业务层单独埋点,区分「技术错误」(HTTP 5xx)和「业务错误」(业务异常码):
// 业务异常埋点
@Aspect
@Component
public class BusinessMetricAspect {
private final Counter bizErrorCounter;
public BusinessMetricAspect(MeterRegistry registry) {
this.bizErrorCounter = Counter.builder("business_error_total")
.tag("service", "order-service")
.register(registry);
}
@AfterThrowing(pointcut = "execution(* com.example..*Service.*(..))",
throwing = "ex")
public void recordBusinessError(Throwable ex) {
bizErrorCounter.increment();
}
}这样,业务异常在 Grafana 上单独一张图,告警规则也独立——业务错误率连续 5 分钟 > 1% 就走 P1 告警。这个案例说明:只用 RED 指标是不够的,必须把业务层面的异常也纳入监控体系。
Prometheus Pull 模式 vs Push 模式
Prometheus 选择 Pull 模式而非 Graphite/StatsD 的 Push 模式,有三点考量:
- 目标状态可感知:如果目标服务挂了,Prometheus 的 Pull 请求直接超时/失败,监控系统能立刻发现服务下线;而 Push 模式下,客户端不推送了,服务端不知道是客户端挂了还是网络问题。
- 采集频率统一控制:所有目标的 scrape_interval 由 Prometheus Server 统一管理,不会出现客户端疯狂推送把服务端打爆的情况。
- 无中心化瓶颈:不需要额外部署 Agent 或 Collector 集群,每个服务只需暴露一个
/metrics端点。
# prometheus.yml 配置
scrape_configs:
- job_name: 'order-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['order-service:8080']
labels:
service: 'order-service'
env: 'prod'
scrape_interval: 15s
scrape_timeout: 10sSLO/SLI/SLA 落地:从口号到可量化
很多团队的口头禅是"高可用 99.9%",但真问起来"你的 99.9% 怎么算的"就说不清了。三个概念必须厘清:
- SLI(Service Level Indicator):可量化的指标,比如请求延迟 P99 < 200ms、错误率 < 0.1%、可用性 > 99.9%。
- SLO(Service Level Objective):目标阈值,比如"季度内 99.9% 的请求延迟 P99 < 200ms"。
- SLA(Service Level Agreement):对外承诺,违反需赔偿,通常比 SLO 更宽松(比如 SLA 承诺 99.9%,SLO 定为 99.95% 留余量)。
Prometheus 中计算 SLO 的典型做法是使用 recording rules 和 alerting rules:
# Prometheus recording rules
groups:
- name: slo.rules
interval: 1m
rules:
# 错误率 SLI
- record: service:error_rate:ratio_5m
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 延迟 P99 SLI
- record: service:latency_p99:seconds
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
)
# 错误预算消耗(月度 SLO 99.9%)
- record: service:error_budget_consumed:ratio
expr: |
(1 - (sum(rate(http_requests_total{status!~"5.."}[30d]))
/ sum(rate(http_requests_total[30d]))))
/ (1 - 0.999)Error Budget 消耗计算:真实数据模拟
假设一个服务每天有 1000 万请求,SLO 为 99.9%(季度内),季度总请求量 ≈ 9 亿次。允许的失败请求数 = 9亿 × (1 - 0.999) = 90 万次,对应约 43 分钟的全量不可用。
场景模拟:某天凌晨 2 点发布了一个新版,上线后错误率从 0.01% 升到 0.5%,持续了 2 小时才被发现回滚:
- 2 小时内错误请求数 = 1000万 × 2/24 × 0.5% ≈ 4167 次
- 错误预算消耗 = 4167 / 90万 ≈ 0.46%
- 看起来不多,但如果每周发生一次,季度内累计消耗 ≈ 0.46% × 12 ≈ 5.5%,还安全
但如果发现晚了:错误率 5% 持续 4 小时:
- 错误请求数 = 1000万 × 4/24 × 5% ≈ 83333 次
- 单次消耗 = 83333 / 90万 ≈ 9.3%
- 再来 3 次类似的故障,错误预算烧掉 28%,团队就该叫停发布、全力修稳定性了
这个计算过程在 Grafana 上做一张 Error Budget 燃尽图,每天自动显示剩余预算百分比。当预算消耗 > 50% 时触发 P0 电话告警,> 30% 时触发 P1 IM 告警。
SLO 级别选择:99.9% 还是 99.99%?
| SLO 级别 | 季度允许故障时间 | 典型成本倍数 | 适用场景 |
|---|---|---|---|
| 99.9% | ≈ 43 分钟 | 1x(基准) | 大部分内部业务系统、非核心 API |
| 99.95% | ≈ 21.5 分钟 | 2-3x | 对外核心 API、支付链路 |
| 99.99% | ≈ 4.3 分钟 | 5-10x | 实时交易系统、金融核心链路 |
| 99.999% | ≈ 26 秒 | 20-50x | 极少需要,通常只有基础设施层 |
建议:核心链路定 99.95%,非核心定 99.9%,不要为了 KPI 定一个 99.99% 的 SLO 然后天天被告警轰炸。每多一个 9,基础设施成本大约翻倍,包含多活部署、异地容灾、全链路冗余、故障演练的投入。
总结
监控体系搭建关键点
- 四层覆盖:基础设施层(Node Exporter)→ 中间件层(各 Exporter)→ 应用层(RED 指标 + Micrometer)→ 业务层(自定义指标),缺一层都会导致排查盲区。
- 告警不发噪音:P0(SLO 错误预算消耗 > 50%,电话告警)→ P1(单个服务错误率 > 5% 持续 5 分钟,IM 告警)→ P2(CPU > 80%,第二天处理),不要在凌晨 3 点因为 CPU 过载 80% 打电话叫醒值班人员。
- SLO 定在 99.9% 还是 99.99%:每多一个 9,基础设施成本大约翻倍。大部分业务 99.9% 已经够用,不要为了 KPI 定一个达不到的 SLO 然后天天被告警轰炸。
- Error Budget 是管理工具,不是技术指标:季度内 99.9% 的 SLO 允许约 43 分钟故障时间,这 43 分钟是"可消耗的故障额度",预算充足时可以快速迭代,预算快耗尽时叫停发布全力修稳定性。
生产避坑
- Prometheus 的存储是单机 Time Series Database,默认保留 15 天。超过 1000 万时间序列时查询性能会显著下降,建议用 Thanos 或 VictoriaMetrics 做长期存储和全局查询。
- 自定义指标标签(label)的基数不能太高——
userId做标签会导致 Prometheus 内存爆炸,因为每个用户都会产生一个新的时间序列。标签的基数建议控制在 1000 以内。 - 告警规则的
for字段必须设置,比如for: 5m表示"持续 5 分钟异常才告警",避免瞬时的抖动触发误报。 - 业务错误 vs 技术错误必须分开埋点:否则 HTTP 200 但业务逻辑异常的场景完全漏掉。建议每个业务异常码注册一个单独的 Counter,Grafana 上按业务码聚合出图。
- Prometheus 的
/metrics端点不要暴露公网:内网通过负载均衡器访问,或者加 Prometheus 的 basic_auth 配置。曾经有公司把 Prometheus 暴露到公网,被爬虫抓走了所有服务拓扑信息。
参考:Google SRE 书、Prometheus 官方文档、Grafana Labs 博客、Nicolas 的《SRE with Prometheus》