关于 observability
面向生产系统设计者的可观测性技能,帮助确定指标、日志、追踪、健康检查与告警策略。重点是围绕用户症状和 SLO 设计信号,并考虑高负载下的可靠性。
主要功能
- 01选择指标、日志与追踪
- 02使用 RED、USE 和黄金信号
- 03区分存活与就绪检查
- 04围绕 SLO 设计告警
- 05评估采样与指标基数
适用场景
- 01为生产服务制定监控方案
- 02设定 SLO 与错误预算
- 03排查跨服务请求的延迟来源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ proyecto26/ system-design-skills --skill observability安装后在 Claude Code 中输入/observability确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/deep-dive.mdreferences/providers/aws.mdazure.mdgcp.mdgeneric.md详细介绍
可观测性
决定要测量什么,让系统在生产环境中可见、可触发告警并可调试。做错这一点就是失效模式 #6——忽视故障:设计在白板上行得通,但在负载下就变得不可见,宕机的第一个信号不是告警,而是用户投诉。
何时使用
任何生产环境设计都需要回答“我们如何知道它出故障了,以及发现得有多快?”在定义系统要测量什么、什么情况需要通知人员、什么是可接受的服务水平(SLO),或如何跨服务追踪请求时,都应考虑使用。这个设计举措能让其他每个模块的压力应对部分落到实处——看不到请求风暴或热点分片,就无从缓解。
何时不使用
对于原型或没有用户需要取悦的内部工具,不要搭建完整的指标、日志和追踪技术栈(YAGNI)——健康检查和错误日志就足够了。不要凭空制定没人会维护的 SLO,也不要在弄清重要症状之前就接入告警;没有负责人和运行手册的告警只是噪声,会让团队习惯于忽略告警。此技能负责定义要测量和告警的内容;高容量日志管道(收集 → 缓冲 → 发送 → 索引 → 保留)属于 distributed-logging——在这里概述并链接即可,不要重建它。
先澄清
- 从用户角度看,什么是“健康”的? 定义糟糕体验的症状(结账缓慢、上传失败)——告警应针对这些症状,而不是 CPU。
- SLO 目标和时间窗口是什么? 例如:30 天内 99.9% 的请求耗时低于 300 ms。这决定错误预算和告警阈值。(→ 关于几个 9,请参阅
back-of-the-envelope。) - 请求量和基数是多少? QPS 决定指标和追踪的采样率;高基数标签(用户 ID、URL)会撑爆指标存储。
- 这是请求驱动还是资源驱动的? 这决定采用 RED(服务)还是 USE(CPU/磁盘/队列)作为测量框架。
- 请求路径是否跨越多个服务? 如果请求跨越多个服务,追踪就能发挥价值;单个服务暂时可能不需要。
选项
三大支柱(互为补充,并非二选一):
- 指标——开销低的数值时间序列(计数器、仪表、直方图)。用于仪表板、趋势分析和告警——始终开启的信号。
- 日志——包含上下文的离散事件。用于告警触发后调试具体故障。(传输日志的管道属于
distributed-logging。) - 追踪——单个请求跨服务的旅程,记录每一跳的耗时。用于找出延迟或错误源自哪个服务或依赖项。
测量内容(为每个组件选择一种框架):
- RED(请求驱动的服务):Rate(速率)、Errors(错误)、Duration(耗时)。用于 API、Web 层以及任何处理请求的组件。
- USE(资源):Utilization(利用率)、Saturation(饱和度)、Errors(错误)。用于 CPU、内存、磁盘、连接池和队列。
- 四大黄金信号(延迟、流量、错误、饱和度)——涵盖面最广;可作为服务仪表板的默认选择。
健康检查(由 load-balancing/编排器使用的信号):
- 存活检查——进程是否存活/未陷入死锁?失败 ⇒ 重启。保持检查开销低;不要检查依赖项。用于恢复卡住的进程。
- 就绪检查——此实例现在能否处理流量(依赖项可访问、预热完成)?失败 ⇒ 从轮转中移除,不要重启。用于控制冷启动或不稳定的实例。
告警:
- 基于症状(SLO 消耗)——在用户侧 SLO 面临风险时触发通知。作为默认选择;它可采取行动,且噪声较少。
- 基于原因(资源阈值)——针对 CPU、磁盘和饱和度创建工单或发出警告。用于容量规划,而非触发通知。
权衡
| 选项 | 解决的问题 | 带来的问题 | 何时调整 |
|---|---|---|---|
| 指标 | 低成本、持续运行的告警和趋势监控 | 无法查看单个请求的详情;高基数标签会急剧增加存储和成本 | 需要调试某个特定请求时 → 添加追踪/日志 |
| 日志 | 为事故调试提供丰富的上下文 | 数据量和成本高;需要 distributed-logging 管道才能扩展 | 数据量难以管理时 → 采样,或将详细信息转移到指标中 |
| 追踪 | 精确定位服务间缓慢或失败的环节 | 需要投入精力进行埋点;QPS 高时需要采样 | 单服务或数据量较低时 → 暂缓;指标已足够 |
| RED | 适用于请求服务的正确视角 | 无法发现尚未影响请求的资源耗尽问题 | 组件是资源(队列、磁盘)时 → 使用 USE |
| USE | 在资源饱和影响用户之前发现问题 | 以资源为中心,而非以用户为中心;可能产生过多噪声 | 用于告警时 → 改为基于症状/SLO |
| 存活检查 | 恢复死锁进程 | 过于激进 ⇒ 进入重启循环,掩盖真实缺陷 | 重启掩盖了崩溃循环时 → 修复就绪状态/根因 |
| 就绪检查 | 防止未预热或故障实例进入流量轮转 | 如果检查不稳定的依赖项,状态会反复波动 ⇒ 容量忽高忽低 | 所有实例同时未就绪时 → 依赖项故障 |
| SLO/错误预算 | 将告警和发布节奏与用户痛点关联起来 | 定义和维护需要投入精力;错误的 SLO 会误导 | 预算从不消耗(太宽松)或总是消耗(太严格) |
| 症状告警 | 噪声低、可执行的通知 | 定位根因稍慢 | 需要更快定位时 → 添加基于原因的工单(而非通知) |
压力下的行为
可观测性恰恰在最可能出故障或造成误导时最为重要。
- 监控放大了故障。 在请求路径上同步记录日志,会让缓慢的日志后端增加请求延迟。每个请求都导出追踪且不进行采样,会在流量激增时压垮收集器。遥测应保持异步并进行采样,以便退化的是信号,而不是服务。
- 健康检查引发风暴。 激进的存活探针会重启只是运行缓慢的实例;就绪状态反复波动会在流量激增期间撤走容量,令峰值更严重。准入/恢复行为由
load-balancing和resilience-failure负责;本模块负责定义稳定的信号(合理的阈值、连续失败计数,以及将依赖项检查放在就绪检查而非存活检查中)。 - 基数激增。
user_id或原始 URL 这类标签会让时间序列增至数百万条,并在负载下导致指标存储 OOM——应移除高基数维度,或将其分桶。 - 告警风暴。 单一根因(数据库故障)触发 50 条相互关联的告警,值班人员不堪重负。针对面向用户的症状发出告警;对下游告警进行分组/抑制。
- 恢复盲区。 事故发生后,仪表板必须显示修复是否奏效,以及恢复流量是否压垮了尚未预热的层。
监控: 每项服务的四个黄金信号(速率、错误、延迟 p50/p95/p99、饱和度)、SLO 错误预算消耗率、健康主机数量和探针波动率,以及遥测管道自身的延迟/丢弃率(监控监控系统)。
如何应用
- 明确输入信息 — 确定面向用户的症状、SLO 目标和时间窗口、 请求量/基数,以及请求路径是否涉及多个服务(参见先明确信息)。还没有 SLO? 先定义症状;数值随后再定。
- 根据权衡表选择支柱并确定框架 — 始终使用指标进行告警; 服务使用 RED,资源使用 USE;仅当请求跨越多个服务或请求量足以支撑时才添加追踪。
- 设定关键参数 — 定义存活与就绪端点(依赖项检查放在 就绪端点,而非存活端点中)、连续失败阈值、追踪采样率,以及 SLO 和错误预算策略。提前剔除高基数标签。
- 对方案进行压力测试 — 按照压力下的行为逐项检查:确认遥测是 异步的/经过采样的,探针不会引发请求风暴,基数受到限制,告警按 根本原因分组,避免一次故障触发 50 条告警。
- 用数字估算规模 — 检查指标时间序列数量和保留期限、 追踪/日志采样量与 QPS 是否匹配,以及 SLO 中的 9 是否符合架构的冗余能力 (→ 重要指标)。
- 选择提供商 — 默认使用通用方案;只有用户指定了云服务时才打开提供商文件(参见选择提供商)。
- 在回答中说明权衡 — 提供一张
Decision | Solves | Worsens | Change it when…表格,为此处做出的每项选择各列一行(例如 选项、存储系统、故障策略);最后一列填写具体的触发条件(一个数值或可观察到的信号)。然后指出最先会出问题的环节。
应做与不应做
应做
- 针对面向用户的症状(SLO 消耗率)设置告警,并确保每条告警都有可执行的运行手册。
- 将依赖项检查放在就绪检查中,并确保存活检查开销低且不依赖其他组件。
- 异步并经过采样地发送遥测数据,避免增加延迟或压垮采集器。
- 制定你确实会坚守的 SLO 和错误预算,并据此调整发布节奏。
- 为每个服务统一标准仪表板,展示四个黄金信号。
不应做
- 不要针对原因(CPU > 80%)发送告警——这类情况应创建工单;告警只针对用户痛点。
- 不要将高基数标签(用户 ID、原始 URL)用作指标维度。
- 不要在存活检查中检查下游依赖项——否则整个服务集群会陷入重启循环。
- 不要为原型搭建完整技术栈,也不要配置无人负责的告警(YAGNI/告警疲劳)。
- 不要在这里重新实现日志流水线——那属于
distributed-logging。
重要指标
SLO 决定其他一切:30 天内达到 99.9% 的 SLO 允许约 43 分钟的预算;如果
架构的冗余无法达到这些 9,SLO 就是空谈(→
查看 back-of-the-envelope 中的可用性 9 表格)。针对 p95/p99 而非
平均值设置告警——平均值会掩盖尾部延迟问题。在高 QPS 下,追踪采样率通常设为
1–10%,使成本随流量增长而次线性上升。注意指标的基数(时间序列数 ≈
标签值数量的乘积):一个无界标签就可能产生数百万条时间序列。不要重复列出
延迟/QPS/9 的表格——它们位于 back-of-the-envelope 中。
接口示意
遥测有值得明确约定的契约。指标:名称 + 标签集 +
类型(http_requests_total{service,method,status} 计数器)——标签应为
低基数。健康端点:GET /livez → 200/503(仅检查进程),
GET /readyz → 200/503(检查依赖项和预热状态),在响应正文中提供版本/构建信息
以便调试。追踪上下文:每次传入/传出调用都传递一个
trace_id + span_id(例如 W3C traceparent 标头),以便关联追踪和日志。
选择提供商
默认采用上文的通用方案(Prometheus + Grafana + Loki + Jaeger,通过
OpenTelemetry 连接)。如果用户指定了云服务,请阅读
references/providers/<provider>.md,了解托管服务映射、配额/限制
以及提供商特有的权衡。如果该提供商没有对应文件,则采用通用方案。
图示
要可视化遥测流(应用 → OpenTelemetry SDK → 收集器 → 指标 /
日志 / 链路追踪后端 → 仪表板 + alertmanager)或告警到页面的路径,请使用插件内的 architecture-diagram 技能。遥测导出使用虚线箭头,表示它不在请求路径上。
相关构建模块
distributed-logging— 所属概念位于此处:高吞吐量日志管道(收集 → 缓冲 → 发送 → 索引 → 保留)。此技能决定记录和告警的内容;该技能决定如何大规模传输和存储日志。resilience-failure— 与此技能配合:告警和 SLO 消耗速率会触发优雅降级和熔断;此处定义的健康检查信号是其故障转移和load-balancing健康状态门控所使用的输入。scaling-evolution— 为其提供输入:饱和度指标和黄金信号会揭示下一个瓶颈,从而说明下一步扩展的必要性。back-of-the-envelope— 为此技能提供输入:它提供可用性 9 的个数和 QPS,将 SLO 和采样率转化为实际数字。system-design— 所属概念位于编排器中:推理循环、权衡方法以及十种故障模式(此模块用于防范第 6 种)。
参考资料
references/deep-dive.md— 支柱机制(直方图与仪表、推送与拉取、采样)、SLI/SLO/错误预算计算和消耗速率告警、详细介绍 RED/USE、健康检查调优和告警设计。深入设计可观测性层时请阅读。references/providers/{generic,aws,azure,gcp}.md— 各环境的服务映射、限制和注意事项。