可观测性 — 在用户投诉之前知道坏了

一句话:可观测性不是装个监控面板,而是让系统能回答三个问题——坏了吗?哪里坏?为什么坏?——并且答案来自数据,不是来自猜。

🎯 这 20% 能解决哪些问题

你遇到的困惑本质原因马上能改的动作
用户投诉了才知道挂了只监控了服务器存活,没监控用户链路给核心接口埋延迟、错误、流量三个指标
告警一天几十条,全都忽略告警报的是原因(CPU 高),不是症状只对「用户感知的失败」告警,原因类进看板
日志一堆,查问题靠 grep日志非结构化,没有请求标识统一 JSON 日志 + trace_id 贯穿全链路
平均延迟 100ms,用户却说卡平均值掩盖长尾改看 P95/P99,并把分位写进看板
监控费用比服务器还贵全量打点、全量日志、高基数标签采样 + 分级保留 + 禁止用用户 ID 做标签

一、三支柱:各管一段,不能互相替代

支柱回答什么问题成本典型工具保留期
指标 Metrics整体是否异常、趋势如何低(聚合数字)Prometheus / VictoriaMetrics长(月~年)
日志 Logs具体哪一次、报了什么错高(文本量大)Loki / ELK短(7–30 天)
链路 Traces一次请求慢在哪一段中(采样)Jaeger / Tempo中(3–7 天)

核心规律:指标负责「发现」,链路负责「定位」,日志负责「看清细节」。顺序不能颠倒——先用指标发现异常,再用链路与日志下钻。

flowchart LR
    A["指标异常<br/>错误率上升"] --> B["链路下钻<br/>哪一段慢/错"]
    B --> C["日志细看<br/>具体异常与参数"]
    C --> D["修复与验证"]

二、四个黄金信号:任何服务都先埋这四个

信号指标定义看什么阈值示例
延迟 Latency请求耗时直方图P95 / P99,区分成功与失败请求P99 < 300ms
流量 TrafficQPS / 每分钟请求数突增突降(突降常是上游挂了)相对基线的 ±30%
错误 Errors失败请求占比(含超时)5xx、业务错误码、超时< 0.5%
饱和度 SaturationCPU、内存、连接池、队列积压最紧张的那一项资源< 80%

2.1 两套速记法

方法适用对象内容
RED请求型服务(API、Web)Rate 请求率、Errors 错误率、Duration 耗时
USE资源型对象(CPU、磁盘、连接池)Utilization 使用率、Saturation 饱和度、Errors 错误数

三、指标:命名、分位与基数

规则正确做法错误做法
命名http_request_duration_seconds(单位进名字)time、cost 无单位
类型计数用 counter,瞬时值用 gauge,分布用 histogram用 gauge 存累计值
分位在看板与告警里用 P95/P99只报平均值
标签只放低基数字段:服务、接口、状态码、区域放 user_id、订单号、URL 全路径
聚合先按接口分组,再看全局全局平均掩盖单接口崩

基数陷阱:标签每多一个高基数字段,时间序列数量成倍增长。user_id 做标签,一周就能把监控打挂。


四、日志:结构化才有用

要素要求
格式JSON,一行一条,禁止多行拼接
必带字段timestamp、level、service、trace_id、user_id(可脱敏)、message
级别ERROR 只用于「需要人处理」,WARN 用于可自愈异常,INFO 记录关键业务节点
敏感信息手机号/身份证/密码/token 一律脱敏或剔除
采样高频 INFO 采样 1%–10%,ERROR 全量
上下文打印「输入参数摘要 + 关键分支 + 结果」,不打印整个对象

判据:拿到一个 trace_id,能在 1 分钟内串起这次请求的所有服务日志——日志才算合格。


五、链路追踪:一次请求的地图

要点做法
贯穿入口生成 trace_id,通过 HTTP Header / 消息属性透传到所有下游
采样正常流量 1%–10% 采样;错误与慢请求强制采样
Span 粒度一次外部调用一个 Span,包含目标服务、耗时、状态
关键属性接口名、状态码、重试次数、是否命中缓存
用途定位「慢在哪一段」「错误从哪个服务开始」

反模式:每个函数都埋 Span,链路变成毛线团,反而看不清。


六、告警设计:只报症状,不报原因

告警类型例子是否叫人
症状告警(好)下单成功率 < 95% 持续 5 分钟叫,必须处理
原因告警(差)单台机器 CPU > 80%进看板,不叫人
预测告警磁盘 7 天内写满工单,不半夜叫
事件通知发布完成、扩容完成只记录

6.1 一条好告警的五个要素

1. 症状:用户能感知的失败(错误率/延迟/业务成功率)
2. 阈值与窗口:连续 5 分钟超过 1%,而非瞬时抖动
3. 分级:P1 立即叫人 / P2 工作时间处理 / P3 工单
4. 处置:一句话说明先看哪个看板、能否直接回滚
5. 归属:明确的负责团队,而非「所有人」

6.2 减少告警疲劳

手段说明
多窗口燃烧率1 小时燃尽 2% 预算 → P1;6 小时燃尽 5% → P2
去重与抑制同一根因只发一条;上游故障时抑制下游告警
定期清理每月统计「触发了但没人处理」的告警,直接删或改
目标无效告警占比 < 20%,每条告警都能对应一个动作

七、看板分层:不同人看不同的屏

层级看什么观众更新
业务层下单量、支付成功率、活跃用户、错误预算业务 + 管理层分钟级
服务层RED 指标、依赖健康、队列积压研发 + 运维分钟级
资源层CPU/内存/磁盘/网络/连接池运维分钟级
发布层版本分布、灰度比例、发布后错误率对比发布负责人实时

判据:值班人打开第一屏(业务层)就能判断「现在是否在出事」,不需要点三次以上。


八、业务埋点:技术指标之外的第二只眼

埋什么为什么示例
关键动作成功/失败HTTP 200 不代表业务成功下单成功数、支付成功数
漏斗节点定位用户在哪一步流失加购 → 下单 → 支付转化
关键耗时端到端体验首屏时间、下单总耗时
异常兜底静默失败最危险降级触发次数、缓存击穿次数

规范:埋点事件名用 对象_动作(如 order_created),字段稳定,禁止随意改名。


🎓 实战场景(TIL)

  • 场景:用户投诉变慢,客服报了才知道。本质:只监控资源水位(CPU/内存),不监控用户体验(延迟、错误、饱和度)。要点:先上黄金四信号(延迟/流量/错误/饱和度),资源指标只做容量预警。
  • 场景:日志一搜一大片,仍定位不了具体请求。本质:日志无结构、无关联 ID。要点:一个 trace_id 贯穿网关→服务→队列,日志按结构化字段输出,报错必带请求上下文。
  • 场景:告警设「CPU 超 80% 则报警」,真故障时却不报。本质:盯的是原因指标,不是结果指标。要点:用 SLO/错误预算烧穿来驱动报警;资源类指标作为诊断维度下钻,不作为主告警。
  • 场景:看板十几块,出事还是靠临场翻。本质:看板按团队划分而非按提问路径。要点:顶层只看健康度,第二屏给分维下钻(接口/依赖/资源),每张图都带「异常时下一步看哪里」。

📋 一页速查

我要做照着做
给新服务加监控先埋四个黄金信号,再看板 + 一条症状告警
选指标请求型用 RED,资源型用 USE,一律看 P95/P99
写日志JSON + trace_id + 级别语义化;ERROR 必须可行动
设计告警只报用户症状;5 分钟窗口;有分级、有处置、有归属
压告警噪声每月清理「触发无人处理」的规则,目标无效占比 <20%
控制成本指标标签只放低基数字段;日志分级保留;链路采样
排查故障指标发现 → 链路定位 → 日志取证,禁止直接 grep
看板第一屏业务层,能一眼判断是否在出事

🔗 相关链接