上个月某个周五晚上,正准备下班去吃火锅,结果客服群里突然炸锅了,狂甩一堆用户支付失败的截图。登上服务器一看,好家伙,接口全部报 504 响应超时。排查了一圈才发现,是因为运营搞了个促销活动,流量激增导致数据库出现慢查询,把后端的连接池给活活拖死了。最离谱的是,在这期间我们的监控面板居然一片绿,没有任何报警通知!当时大老板在群里直接发飙:“线上挂了半小时,开发居然全在装死?”这简直是奇耻大辱。为了避免重蹈覆辙,我周末直接爬起来重构了整套 Prometheus + Alertmanager 告警规则,把微服务核心的 5xx 报错和延迟指标钉死。
这次事故给我们的教训就是:不要只监控机器 CPU 和内存,服务本身的黄金指标(吞吐量、延迟、错误率、饱和度)才是重中之重。特别是 5xx 错误率和接口响应时间(P99 latency)。
我们使用的是 Prometheus 配合 Alertmanager。为了让报警精准且不产生告警风暴,我们重新梳理了告警阈值设计。以下是我们在 prometheus.rules.yml 中配置的生产环境微服务告警规则,里面包含了对 HTTP 5xx 错误率(基于速率变化)以及 API 响应延迟的精准抓取,没有使用任何敷衍的硬编码:
groups:
- name: microservice-alerts
rules:
- alert: Http5xxRateHigh
expr: sum(rate(http_requests_total{status=~"5.."}[5m])) by (job, service) / sum(rate(http_requests_total[5m])) by (job, service) * 100 > 5
for: 2m
labels:
severity: critical
team: devops
annotations:
summary: "Service {{ $labels.service }} HTTP 5xx error rate is high"
description: "HTTP 5xx error rate for service {{ $labels.service }} is {{ $value | printf \"%.2f\" }}% over the last 5 minutes."
- alert: HttpLatencyTooHigh
expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job, service)) > 1.5
for: 3m
labels:
severity: warning
team: dev
annotations:
summary: "Service {{ $labels.service }} P99 latency is high"
description: "P99 response time for service {{ $labels.service }} has exceeded 1.5s (current value: {{ $value | printf \"%.2f\" }}s) for more than 3 minutes."
- alert: DbConnectionPoolSaturated
expr: hikaricp_pending_threads{pool="default"} > 10
for: 1m
labels:
severity: critical
team: dba
annotations:
summary: "Database connection pool default is saturated"
description: "HikariCP pending threads count is {{ $value }} (exceeded threshold 10) for 1 minute, potential database deadlock or slow queries."
配置里的第一个规则 Http5xxRateHigh 算的是最近 5 分钟内 5xx 报错占总请求的百分比。如果直接用绝对请求数报警,在半夜流量低谷期,即便有几个个人报错也会触发假警;而在白天流量高峰,几百个报错可能被稀释掉。采用错误率百分比(阈值设为 5%)并且持续 2 分钟以上才报警,能有效过滤网络抖动。
第二个规则 HttpLatencyTooHigh 则是用 histogram_quantile 算 P99 延迟。一旦有超过 99% 的请求耗时大于 1.5 秒,且持续 3 分钟,立刻报 warning。这比平均响应时间靠谱得多,因为平均值会把长尾慢请求彻底抹平,导致系统响应变慢时你根本无感。
至于第三个规则 DbConnectionPoolSaturated,就是专门为了针对上次拖死连接池设计的。我们用的是 Java 的 HikariCP 连接池,如果等待连接的线程数(pending threads)持续 1 分钟大于 10,说明连接池基本被耗尽了,必须立马介入,否则紧接着就是全盘崩溃。
折腾完这套 Prometheus 规则后,我们又把 Alertmanager 的路由和分组(group_by)做了解耦,防止同个微服务挂掉时狂发几百条重复短信。现在的告警直接对接了飞书机器人,按照 critical 和 warning 级别分流处理。
把这套配置上线之后,心里总算踏实了点。各位同行,你们公司的 5xx 报警阈值一般是配多少?有没有针对突发流量的动态阈值(比如自适应异常检测)实践经验?