可观测性是架构属性,不是事后补的

一个服务能不能被观测,在写下第一个接口签名时就已经定了一半:日志字段是谁规定的、traceId 在哪一层生成、指标标签带不带用户 ID、消息中间件透不透传上下文。这些决定一旦落进代码,后期补的成本不是「加几行埋点」,而是要改所有服务的调用约定。本章只回答一个问题:可观测性在架构设计阶段要定下什么。具体怎么排查、敲哪条命令,属于运维排障的范围,这里不重复。

可观测性欠债的典型症状

症状表层表现架构层的根因
只能证明「服务活着」健康检查全绿,用户还在投诉只采集了资源指标,没有面向用户行为的 SLI
故障时无法定位到服务每个服务日志都正常,合起来就是错的没有跨服务上下文贯通,缺 traceId 或中途丢失
定位要登机器捞日志值班必须 SSH 才能查问题日志没结构化、没集中采集出口
指标平台账单失控指标数量随用户量线性增长标签用了高基数维度(用户 ID、订单号、URL 全路径)
告警天天响没人管群里刷屏,真故障被淹没告警按原因(CPU、连接数)设,而不是按症状设
上线后才发现看不见新链路完全没有监控可观测性没有进设计评审与 Definition of Done

结论:把可观测性当成验收项写进设计文档,而不是等到出故障时补。

设计阶段必须定下的六件事

  1. SLI 与 SLO:这个服务承诺什么,用什么指标衡量。
  2. 上下文传播约定:traceId 谁生成、走哪些协议头、异步链路怎么带。
  3. 日志字段规范:统一字段名、级别语义、脱敏规则、保留期。
  4. 指标命名与标签白名单:标签只能从白名单里选,禁止高基数维度。
  5. 采样策略:哪一段全采、哪一段低采、错误请求怎么保底。
  6. 告警契约:谁负责、几级、有没有 runbook、多久无人响应升级。

这六项就是架构决策记录(ADR)里可评审的内容,也是「事后补」与「设计时定」的分界线。

三条支柱的采集边界与成本

支柱采集边界(谁负责)数据量级主要成本项建议保留
日志 Logging应用内结构化输出,边车或采集代理统一出口与请求量成正比,单条 KB 级存储 GB 与索引开销热数据 7~30 天,冷归档按合规要求
指标 Metrics进程暴露端点(如 /metrics),平台定时拉取或推送与「时间序列基数」成正比,不随 QPS 涨活跃时间序列数、卡片基数原始 15 天,降采样后 1~2 年
追踪 Tracing框架或边车自动埋点 + 关键业务手工 Span与请求量 × 采样率成正比Span 存储、查询扫描量7~15 天,异常 Trace 单独留存

三条支柱的成本结构完全不同,架构决策也因此不同:指标的成本由维度设计决定(设计期可控),日志的成本由字段与采样决定(设计期可控),追踪的成本由采样率决定(运行期可调)。想省钱要先改设计,而不是先砍保留期。

traceId 与上下文如何贯通

约定比工具重要。一次请求的标识要满足三件事:唯一、可跨语言传递、能穿过异步边界。

入口(网关 / BFF):
  - 请求头已有 traceparent → 沿用,不重新生成(否则链路断裂)
  - 没有 → 生成 32 位十六进制 traceId,写入响应头便于用户报障时提供
  - 校验采样标记 sampled,决定后续是否落 Span

同步调用(HTTP / gRPC):
  - HTTP 用 W3C Trace Context:traceparent、tracestate
  - gRPC 用 metadata,键名与 HTTP 保持一致,避免两套解析

异步(消息 / 事件 / 定时任务):
  - 生产端把 traceId 写入消息头,不要只写进消息体
  - 消费端从消息头恢复上下文,并为「消费」新建一个子 Span
  - 定时任务没有上游:以「任务名 + 触发时间」作为链路根

跨线程(线程池 / 协程 / 回调):
  - 上下文必须显式传递(装饰任务、透传上下文对象)
  - 依赖线程本地变量自动继承是最常见的丢失点

设计文档里应写明一句话:任何一次跨进程调用,traceId 必须随协议头传递;任何一次跨线程切换,上下文必须显式携带。这句话写进编码规范,比事后逐个服务补埋点便宜得多。

SLI / SLO 与错误预算

SLI 是测量值,SLO 是目标,错误预算是「允许失败多少」的额度。

SLI 类型度量方式适合谁
可用性成功请求数 / 总请求数(按分钟聚合)所有对外服务
延迟快于阈值的请求数 / 总请求数(如 P95 < 300ms)用户可感知的接口
正确性业务成功数 / 有效请求数(排除用户自身错误)交易、支付类
吞吐单位时间处理量批处理、消费型服务
新鲜度数据延迟时间(如同步滞后秒数)数据管道、Feed
SLO 示例:下单接口月度可用性 99.9%
错误预算 = (1 - 0.999) × 30 天 = 43.2 分钟/月

预算消耗策略(比单点阈值告警更抗噪):
   - 燃烧率 > 14.4 倍(1 小时烧掉 2% 月度预算)→ 立即呼叫
   - 燃烧率 > 6 倍(6 小时烧掉 5%)→ 群里通知,值班跟进
   - 燃烧率 > 1 倍(持续消耗)→ 只进工单,复盘时看

预算用尽后的约定:冻结非修复类变更,直到预算恢复

错误预算的价值不在数字,而在它把「要不要发版」从争论变成算术。没有 SLO 的团队,只能靠吵架决定能不能上线。

可观测性预算与采样决策

先给可观测性定一个成本上限(常见做法是基础设施成本的 5%~15%),再决定采样。

决策点选项建议
追踪采样位置头部采样(入口决定)实现简单、成本可预测,但会随机丢掉长尾
尾部采样(收集端按结果决定)能保住错误与慢请求,需要缓冲与聚合能力
采样率按服务分级核心交易链路 10%~100%,内部批处理 1% 或更低
错误保底一律全采只要出现错误或超过延迟阈值,无条件保留整条链路
指标维度标签白名单只允许:服务名、接口、方法、状态码、实例、版本
日志级别语义固定ERROR 必须可行动,WARN 表示降级生效,INFO 不做高频循环输出

高基数标签是成本失控的第一杀手:把用户 ID、订单号、完整 URL 当标签,时间序列数会随业务量爆炸,而查询性能同时崩塌。需要按用户排查时,那是日志与 Trace 的职责,不是指标的。

告警设计原则

  • 面向症状,不面向原因:「下单 5xx 比例超 1%」是症状,「数据库连接数超 80」是原因。原因类信号做大盘,症状类信号做告警。
  • 可行动:每条告警必须对应一个明确动作。写不出 runbook 的告警,先别上。
  • 信噪比优先:频繁误报的告警要下线或调参,而不是让人学会忽略。
  • 分级与责任到人:P0 呼叫、P1 群通知、P2 工单;每条告警都有 owner,无主告警等于没有告警。
  • 用预算驱动:优先告警「错误预算燃烧率」,比逐个接口设静态阈值更稳、更少误报。
  • 新链路必须带告警:上线清单里写清楚——新服务的核心 SLI、告警规则、大盘链接缺一不可。

常见误区

误区后果正确做法
把可观测性等同于「装个 APM」工具到位但上下文断裂,链路仍然拼不起来先定字段与传播约定,工具只是执行者
让每个团队自由决定日志格式跨服务检索失效,聚合查询要写 N 套解析字段规范统一发布,变更走评审
指标里带上用户或订单维度序列数爆炸、账单失控、查询变慢高基数信息只进日志与 Trace
只监控资源不监控业务资源正常但业务已错每个核心流程至少一个业务 SLI
告警全部直连值班群,不设分级告警疲劳,真故障被淹没分级 + 抑制 + 聚合,按 SLO 燃烧率触发
采样率一刀切 1%长尾与错误请求被丢,故障时无证据错误与慢请求全采,正常流量可低采

边界说明:故障发生后的具体定位步骤与命令见运维排障的可观测性章节,稳定性控制手段见弹性设计章节,决策留痕与评审见架构决策记录章节。

小结:可观测性是设计出来的——在架构阶段就把 SLI/SLO 与错误预算、traceId 与上下文的传播约定、日志字段规范、指标标签白名单、采样与保留策略、告警分级契约定下来;成本由维度与字段设计决定而非保留期决定,告警要面向症状并用预算燃烧率驱动;等到故障发生再补,补的不是埋点,而是所有服务的调用约定。

笔记加载中…