系统接入 Prometheus 和 Grafana 后,很容易拥有几十张图:CPU、内存、请求量、队列长度。图表丰富不等于可观测。真正故障发生时,如果团队仍然不知道用户受到了什么影响、问题从哪里开始,监控只是装饰。
图 1:仪表盘用于探索,告警必须指向行动,复盘则同时修正系统和信号。
从问题反推信号
每个指标都应回答一个运营问题。请求量、错误率和延迟说明服务是否健康;任务等待时间和重试次数说明队列是否积压;业务流程完成率说明系统是否仍在交付价值。
我通常先写服务级目标,再决定采集什么。以发布平台为例,可以先定义:在 30 天窗口内,99.5% 的发布任务应在 15 分钟内进入成功、失败或等待人工状态;不能永久停在运行中。
这个目标拆成两个可计算信号:终态率和完成时长。Prometheus 查询可以从业务状态出发,而不是先看 CPU:
sum(rate(release_job_terminal_total[5m]))
/
sum(rate(release_job_created_total[5m]))histogram_quantile(
0.95,
sum by (le) (rate(release_job_duration_seconds_bucket[15m]))
)比值异常后,再沿任务队列等待、Worker 执行和外部部署接口查看资源信号。调查顺序和用户路径一致,仪表盘就不再是一组互不相关的系统图。
资源指标用于解释原因,业务指标用于判断影响。只看 CPU 很难知道用户是否无法发布,只看成功率又无法定位瓶颈。
日志应带有请求或任务标识,使一次流程可以跨服务串联。错误日志记录上下文和分类,但避免敏感数据与无界对象。追踪只在关键链路采样,不能为了完整而制造新的成本。
一次任务至少需要关联这些字段:
{
"traceId": "tr_7a2f",
"taskId": "release_812",
"step": "deploy",
"attempt": 2,
"kind": "dependency_timeout",
"dependency": "cluster-api",
"durationMs": 5012
}日志里不直接写完整部署参数和 Token。需要复原输入时,通过 taskId 到受权限控制的业务存储查询。日志负责索引事件,不应该成为影子数据库。
告警必须指向行动
告警阈值要考虑持续时间和业务基线,瞬时波动不应唤醒所有人。每条告警都需要负责人、影响说明和第一步检查入口;无人处理的告警应该删除或降级。
我会把告警说明和代码一起版本化:
alert: ReleaseTerminalRateLow
for: 10m
severity: page
owner: developer-platform
impact: 用户发布任务无法进入可解释终态
runbook: /runbooks/release-terminal-ratefor: 10m 避免单个采集周期波动直接呼叫值班;Runbook 第一屏先给查询路径和止损动作,而不是从系统历史讲起。一次告警若无法指向任何动作,它更适合做仪表盘信号,而不是打断人。
仪表盘用于探索,告警用于行动,复盘用于修正系统。三者通过相同信号连接,才形成真正的可观测性闭环。
从一次故障验证监控
监控体系是否有效,最好用真实故障或演练检查。隐藏一个下游依赖、制造任务积压,观察团队多快发现、能否判断用户影响、是否找到相关日志。如果只能通过熟悉系统的人凭经验定位,说明信号仍未形成路径。
复盘后不仅增加指标,也要删除无用面板、修正阈值和补充行动说明。可观测性与代码一样会老化,服务拆分、流量模式和业务目标改变后,过去重要的信号可能只剩噪声。持续维护信号质量,才不会在需要时面对一面失真的仪表墙。
告警还必须走完关闭闭环。告警关闭时必须选择:用户影响结束、指标误报、已知维护或尚未解决但转为长期任务;同时记录止损动作和后续 owner。没有结局的告警会不断重复消耗注意力。月度复盘看重复根因、无行动分页占比、从发现到止损的时间,以及 Runbook 是否真的被使用。可观测性的产出不是图表数量,而是更短、更确定的恢复路径。
这条链路的上游是告警如何被触发:用户结果怎样变成 SLO、错误预算和燃烧率,我在告警为什么总在半夜吵醒错误的人里单独记录过。