运维
分布式系统中监控与可观测性的区别
监控报告的是预期可能出问题的地方已经出了问题。可观测性则让人能够查明意料之外的情况为何发生,而一旦系统分布在多个服务、队列、缓存和区域中,大多数事件都属于这种情况。
监控回答已知的问题
传统监控围绕预先已知的问题构建:服务器是否在线,CPU 是否超过 80%,磁盘是否即将写满,夜间任务是否完成。运维人员选定一个信号,设置阈值,超过阈值时发出告警。对于运行单体应用的少量服务器,这种方式效果很好,因为可能出错的情况屈指可数,值班人员对此了然于胸。
其局限在于,每一项检查都隐含着一种预测。当故障出乎所有人意料时,例如下游依赖变慢、重试风暴,或缓存虽然在线却返回过期数据,仪表板依旧一片绿色,客户却在投诉。监控仍然必要,但一旦系统的规模超出一个人的认知范围,仅靠监控就不够了。
分布式带来了哪些变化
将同一业务功能拆分到十几个服务中,并在中间加入消息队列,就会带来三个变化。第一,单个用户请求会涉及多台主机上的多个进程,任何单一日志文件都无法反映全貌。第二,故障变为局部性的:某个区域、某个租户或某条代码路径变慢,而整体指标看起来仍然正常。第三,系统每天变更多次,昨天的基线已不再适用。
可观测性是指能够根据系统发出的数据了解其内部状态,而无需为了提出新问题而发布新代码。在实践中,这意味着收集丰富的高基数遥测数据(哪个客户、哪个端点、哪个版本、哪个区域),并能够按需切分分析。问题也从“系统是否在线”转变为“哪些用户遇到了缓慢、从何时开始、发生了什么变化”。
三类信号及其用途
指标、日志和链路追踪是三种不同的数据。每种数据回答不同的问题,而价值在于能够在它们之间自由切换。
指标
按时间聚合的数值:请求率、错误率、延迟百分位数、队列深度。它们存储成本低、查询速度快,非常适合用于告警和发现变化。它们能说明发生了什么、何时发生,却很少能说明原因。
日志
附带上下文的离散事件。结构化日志(字段一致的 JSON)可检索、可关联;自由文本日志只能由人逐条阅读。日志承载细节,但按字节计算的成本会随流量增长。
链路追踪
单个请求跨服务的路径,以及每一跳的耗时。链路追踪显示时间花在了哪里、哪个依赖出现故障。在每行日志中加入共享的追踪 ID 后,工程师即可从一条缓慢的链路直接定位到其背后的具体日志条目。
以服务等级目标作为告警的基础
服务等级目标(SLO)是针对面向用户的指标设定的目标,例如:在 30 天内,99.9% 的结账请求在 500 毫秒内成功完成。百分比和时间窗口由组织设定;关键在于 SLO 描述的是用户的实际体验,而不是主机上报的数据。
SLO 定义了错误预算,即时间窗口内可承受的故障量,并由此带来一种不同的告警模式。团队不再在 CPU 越过某条线时呼叫值班人员,而是在预算消耗过快、无法撑过整个时间窗口时才发出呼叫(消耗速率告警)。缓慢消耗转为下一个工作日处理的工单;快速消耗则呼叫值班工程师。仅这一项改变,就能消除大部分无需任何人处理的告警。
SLO 还为工程团队和业务部门提供了共同语言。预算充裕时,团队可以加快发布;预算正在消耗时,团队则投入可靠性工作。一张 CPU 曲线图无法支撑这样的讨论。
告警疲劳与值班轮换
监控工作最常见的失败在于告警过多,而不是过少。当值班轮换每周收到数十次呼叫、且大多无需处理时,人们便不再阅读,真正重要的告警就会淹没在噪声中。每条告警都应通过一个简单的检验:必须有人能够立即对其采取行动。否则,它应放在仪表板面板或日报中,而不是作为呼叫发出。
像审查代码一样管理告警集合。每条告警都要有负责人、运行手册链接和存在的理由;一个月内触发却无人处理的告警应删除或降级。同时衡量值班轮换本身:每周呼叫次数、非工作时间呼叫次数、确认时间。健康的值班轮换是系统健康的标志,不健康的值班轮换则清楚地指明了需要投入的方向。
分布式系统还多了一项要求:告警应附带上下文。一条写着“payments-api 错误率过高”的呼叫意味着一项调查任务;而一条链接到受影响的 SLO、最近一次部署和失败最多的端点的呼叫,则可以直接据此做出决策。
遥测的成本
可观测性数据是有成本的,而账单往往在使用习惯养成之后才到来。两大成本驱动因素是数据量(每个请求的日志和 span 字节数乘以流量)和基数(一个指标上不同标签组合的数量)。以用户 ID 或请求 ID 作为标签的指标,会为每个取值生成一条新的时间序列,足以压垮任何指标存储。
合理的默认配置能起到很大作用。高基数标识符应放在链路追踪和结构化日志中,而不是放在指标标签里。对链路追踪进行采样,保留所有错误请求和慢请求,正常请求只保留一部分。按信号类型设置保留期限:指标以较低精度保留一年,日志保留数周,链路追踪保留数天,合规要求保留的数据则转入归档层。每月审查日志量最大的来源;热点路径上一条冗长的调试语句,就可能占去账单的很大一部分。
目标不是收集一切数据,而是能够以组织愿意长期承担的成本,迅速回答下一个未知的问题。
从何入手
对于从服务器监控转向可观测性的团队,按以下顺序推进,见效最快。
- 为最重要的用户流程定义两到三个 SLO,并基于消耗速率而非原始阈值发出告警。
- 在所有服务中采用结构化日志,并使用一组统一的字段,其中包括追踪 ID。
- 为请求路径接入分布式追踪;借助开放标准和 SDK,这只需更换库,无需重写代码。
- 围绕用户能直接感受到的四个信号,为每个服务建立一个仪表板:流量、错误、延迟、饱和度。
- 每月审查告警和遥测数据量,删除无人处理的部分。