跳到主要内容

第 25 章 可观测性:挂了或慢了,怎么知道是哪里

副题:三件套——日志(当时发生了什么)、监控(现在是否正常)、链路追踪(一次请求内部发生了什么);可观测性是投资,不是装饰

第 24 章把高可用建好了:冗余、限流、熔断降级、on-call 值班。但第一次值班,你就遇到最难的问题:用户说"打不开",监控显示一切正常——问题到底出在哪?——你只能看见"系统活着",看不见"一次请求内部发生了什么"。本章回答:让系统"看得见"。

本章要建立的认知

  1. 可观测性三件套:日志回答"当时发生了什么"、监控回答"现在是否正常"、链路追踪回答"一次请求内部发生了什么"——三者缺一不可,各自回答一个问题;
  2. 可观测性的第一原则:排查从被记录开始——没被记录的问题,等于不存在(第 14 章预演过这句话);
  3. 告警是把"看着"交给机器:阈值定多高、告警给谁,是决策(第 17 次应用)——告警太多等于没有告警。

25.1 线上是黑盒:三问与三件套

场景:第一次值班。(上章 on-call 的真实第一夜——"值班的人被叫醒时,全站已经 502 了",本章把它讲透)凌晨一点,老周发来消息:"首页打不开了。"你打开电脑——网站是好的:首页能打开、接口有响应、服务器负载正常。你回老周:"我这边正常啊。"老周发来截图:他那边就是转圈。这就是线上排障的起点:你和用户看到的不是同一个世界(上章说过的"信息真空"——本章正面回答)。

老周视角的"打不开"(它是"用户说不清"的实景):老周不会说"P95 超时"——他说"转圈";问他什么页面,他说"就首页";问他什么时候开始,他说"刚发现"——用户提供的信息天然残缺(他们不是排障者——8 章说用户只会说"打不开")——排障者的工作:从残缺的信息出发,用系统的记录补全——"转圈"(症状)→ 问出时间点(触发条件)→ 查那个时间点的日志/指标(证据)——可观测性把"用户的一句话"变成"系统的一堆证据"

为什么"打不开"这么难查(它是黑盒问题的本质):一次"打不开"可能是——前端问题(JS 报错/资源挂了——8 章白屏)、网络问题(用户网络/CDN 边缘节点——11 章)、服务端问题(接口慢/数据库慢——14/16 章)——同一个症状,三个可能的方向。没有工具,只能猜;猜的代价是时间,时间是事故的放大器(上章"恢复优先")。

没有三件套的世界(它是"黑盒"的代价对照):想象没有日志/监控/链路的排障——用户报"打不开":先问用户(说不清)→ 自己试(我这边好的)→ 重启(碰运气)→ 加日志再等下一次(24 小时后又来一次)→ 反复几轮,用户流失(24 章宕机成本)——黑盒排障的本质是"拿用户的耐心做实验"——三件套的本质:把实验挪到系统内部做(记录一切,出事回放)。

三问(15 章联调三问的运行期升级):排障时永远先问三个问题——

  1. 现在挂没挂?——系统整体是否正常(监控回答);
  2. 哪里挂的?——哪个环节出问题(日志回答);
  3. 当时发生了什么?——出问题那一刻的细节(日志+链路回答)。

三件套(图 25-1,一级图 #7 首现):三个问题,三件工具——

  • 日志(logging):记录发生过的事——"当时发生了什么";
  • 监控(monitoring):持续测量系统状态——"现在是否正常";
  • 链路追踪(tracing):把一次请求的完整路径串起来——"一次请求内部发生了什么"。
图25-1 一级#7首现 图稿占位
可观测性三件套
日志/监控/链路追踪各答一个问题

三件套的"分工不重叠"(它是"为什么三件都要"的答案):日志回答"发生了什么事"(历史、具体);监控回答"现在正不正常"(现状、整体);链路回答"这次请求内部怎么样"(细节、结构)——少日志:知道挂了不知道为什么(监控说错误率 10%,日志没有——查不了);少监控:挂了不知道(日志有但没人看——那场事故"告警半小时后才响");少链路:知道挂了、有日志,但"慢在哪一站"靠手工拼(12 章的手工账——慢,容易错)——三件套各自补一块盲区,缺一块就有一类问题查不动

可观测性第一原则(14 章预演过:"排查从"被记录"开始"):没被记录的问题,等于不存在——用户报"打不开"时,如果系统没有任何记录(日志/指标/链路),这次事故就是"不可知"的:猜、试、重启,全凭运气——可观测性的全部工作,就是让"未知的问题"变成"已知的问题"(15 章说"上线不是结束,是问题从已知变成未知的开始"——三件套把未知变回已知)。

本章在第六部分的位置(它是"运行期"的感知层):第 23 章部署(放上去)、第 24 章高可用(挂不了)、本章可观测性(看得见)——三章合起来,"跑起来 + 挂不了 + 看得见",运行期的完整闭环(24 章说"第 25 章再加看得见"——本章就是那个"再加")。

阶段 4 的起点(它是本章的现状):可观测性不是从零开始——前面章节已经埋了一路:第 12 章每层打日志、第 7 章 request_id、第 14 章慢查询、第 16 章 P95 曲线、第 21 章 /health——本章把它们串成体系(30 处预告的兑现章)。

25.2 日志:当时发生了什么

第一件套:日志——把发生过的事记下来。它是可观测性的地基:监控是日志的汇总,链路是日志的串联——先有日志,才有其他(12 章说过"请求日志是可观测性的起点")。

日志的级别(它是"记多细"的分层):DEBUG/INFO/WARN/ERROR——DEBUG(开发调试细节——生产不记,23 章"debug 不上生产")、INFO(正常事件:请求完成/下单成功——业务日志的主场)、WARN(异常但可恢复:重试/降级——24 章熔断触发该记 WARN)、ERROR(错误:未捕获异常/数据库不可用——ERROR 是排障的第一入口:值班的人先看 ERROR 再想别的)——级别是日志的过滤器:级别定得对,排障先看 ERROR,不被 INFO 淹没(19 章"错误详情只进日志"——ERROR 里才有详情)。

日志与第 10 章"排查时间线"的衔接("日志里的请求"兑现):10 章说过"本章的报文示例和排查时间线,第 25 章可观测性会以'日志里的请求'身份再见到"——兑现:HTTP 报文(10 章)→ 接口日志(12 章)→ 可观测性日志(本章)——同一个请求的三次出场:报文是协议的视角、日志是服务的视角、观测是运维的视角——排障者看到的"请求",就是这几层视角的叠加

日志的规范(它是"日志能不能用"的关键):一条好日志要有——时间(精确到毫秒)、级别(INFO/ERROR/WARN——12 章分层)、request_id(第 7 章的排障 id——这条日志属于哪次请求)、上下文(谁、什么操作、结果如何——第 6 章 created_at 的思想:每条记录都要能回答"这条数据哪来的")——规范的意义:日志是给未来的排障者读的(18 章"日志是排障的原料"——原料要齐,排障才快)。

结构化日志(它是"机器可读"的形态):日志别用自然语言,用结构化格式(JSON 一行一条)——人看自然语言舒服,机器看 JSON 舒服——日志量大了以后,检索靠机器(按 request_id 过滤、按级别统计)——"日志是数据,不是文字"(12-Factor 的"日志是事件流",23 章说过——事件流 = 一条一条结构化的事件)。

日志与三问的对应(它是"日志回答哪一问"的澄清):日志回答的主要是第三问"当时发生了什么"——但第一问(挂没挂)和第二问(哪里挂)也要日志配合:监控说"错误率 10%"(第一问)——是哪些请求错了?看 ERROR 日志(第二问的入口)——日志是其他两问的"取证层":监控给方向,日志给证据(25.5 会说链路给结构)。

日志与 12 章"每层打日志"的衔接(它是"日志的源头"):12 章说过"中间件记请求进来、业务层记决策结果、数据层记查询耗时"——本章的日志规范是这套打法的升级:加 request_id(7 章)、加级别(本章)、加结构化(本章)——12 章的日志习惯没白打:规范的只是格式,习惯早有了——"日志文化"的建设成本,主要是习惯不是工具(12 章埋的伏笔,本章收成规范)。

日志的部署侧(23 章 12-Factor 兑现):应用把日志打到标准输出,平台统一收集——不是应用自己写文件(多实例时代,每个实例一个文件,查日志要 SSH 到每台机器——23 章容器化之后更明显)——日志收集器把每台机器的日志汇总到一个地方(日志平台),按 request_id 一查到底——"日志集中"是多实例部署的必然要求(23 章"所有实例部署同一个制品",日志也要"所有实例汇总到同一个平台")。

日志的"排障实操"(它是"日志怎么用"的一瞥):按 request_id 捞(用户报障 → 拿到 request_id → 日志平台一查,那次请求的全部日志按时间排开——15 章联调的做法,生产版);按 ERROR 扫(每天看一眼今天的 ERROR——没告警不代表没错误,错误率 1% 的常态 ERROR 要靠扫);按慢查询看(14 章每周三件事:本章让它们自动化)——日志平台的两个基本操作:过滤(按 id/级别)和时间线(按时间排开)——会用这两个操作,排障就入门了(8 章开发者工具的 Network/Performance 两面板,同样的两个操作)。

错误详情只进日志(19/23 章兑现):生产环境的错误细节(堆栈/表结构/内部参数)只进日志,不进响应——响应给第 7 章通用格式(code/message/request_id)——原因有两层:安全(19 章:错误详情是攻击者的免费地图)和排障(详情在日志里,排障者按 request_id 找到它)——"对外最小化,对内最大化":响应里最少的细节,日志里最多的细节

日志里的敏感数据(它是"日志的暗面"):日志会无意间记下敏感信息——用户密码(登录日志别打密码)、token/密钥(第 13 章凭证、19 章密钥——密钥进日志=密钥泄露)、个人数据(19 章隐私)——日志规范里要有"不打什么"(脱敏清单:密码/密钥/token 一律不打——日志是泄密高发地,排障便利和安全要同时管(19 章"错误详情只进日志"的另一面:日志自己也要被保护——日志平台的访问控制,谁能看到 ERROR 详情,最小权限(19 章)。

审计日志(19 章兑现——"审计是安全的'事后诸葛亮'"):安全事件要有日志——登录失败、权限变更、支付操作——日志要留得住(攻击者清理日志是常见手法——日志写到攻击者删不到的地方:独立的日志平台+权限控制——19 章说过,本章落地为"日志平台的访问控制")——审计日志回答"被攻击了怎么知道"(19.1 的第四个发现路径:主动发现)。

日志的"留痕"哲学(它是"为什么要日志"的底层):系统的每个动作都该留痕——请求来了(12 章)、决策做了(业务日志)、错误发生了(ERROR)——留痕的意义:系统是可回放的历史——出事时把时间线拉出来,那一刻发生了什么一清二楚(10 章"排查时间线"的思想,本章系统化)——"回放能力"是可观测性给排障的最大礼物:不用复现(很多 bug 复现不了——18 章),直接看记录。

日志与业务日志的区别(它是"记什么"的边界):系统日志(请求/错误/慢查询——本章主角)与业务日志(下单成功 order_no/支付回调/用户操作——18 章说过"关键路径打了日志",19 章审计日志)——业务日志是给业务排障的("用户说订单没到"→ 按 order_no 查业务日志——17 章异步排查靠它)、系统日志是给系统排障的("接口慢了"→ 按 request_id 查系统日志)——两类日志,一套体系(都结构化、都带 id、都集中收集)。

日志的代价(它是第一件套的账单):日志量(阶段 4:每天几 GB——检索变慢、存储变贵)——对策:级别过滤(DEBUG 只在开发环境,生产只记 INFO+)、保留期(日志保留 30 天,按月归档——排障要的是"最近",历史审计按月)——日志不是越多越好,是"够排障+够审计"(第 4 章复杂度预算:日志量也是预算)。

25.3 监控指标:现在是否正常

第二件套:监控——持续测量系统状态。它是"现在挂没挂"的答案,也是告警的原料(25.4)。

四类指标的两个"主角"细节("监控从哪几个开始"的实操):延迟的 P95(第 7/16 章一路的预算指标——P95 是最早该上监控的指标:预算已定(7 章)、故事已多(16 章)、阈值已有依据);饱和度的连接池(24 章雪崩事故的元凶——连接池使用率是该死的第一个饱和度指标:它红了,事故已经在路上)——"监控什么"的起步答案:P95 + 错误率 + 连接池 + /health(四选四,都是故事里死过的)。

指标四类("监控什么"的完整清单,业界称 USE/RED 的通俗版):延迟(接口响应多快——P95 是主角,16 章)、错误率(请求失败的比例——5xx/4xx 分开看)、流量(每秒请求数/QPS——容量告警的依据,24 章压测拐点)、饱和度(资源用到多少——CPU/内存/连接池——"快满"的信号)——四类指标对应四类问题:慢(延迟)、错(错误率)、多(流量)、满(饱和度)——"系统出问题"永远落在这四类里

"监控"与"可观测性"的差别(它是本章标题的含义):监控是"我们已经知道要问什么"(预设指标:延迟/错误率——问的是已知的问题);可观测性是"出事之后能问出问题"(日志/链路——回答未知的问题)——监控+日志+链路=可观测性:已知的自动化(监控),未知的留证据(日志/链路)——本章标题用"可观测性",因为它比"监控"大一圈

指标与预算的关系(16 章 P95 预算兑现):第 16 章把 P95 预算拆到层内(中间件 10ms/控制器 5ms/数据层 150ms)——监控就是预算的"实时检查":每个指标对着预算看,超了就红——"预算"思想(第 4/7 章)的完整闭环:定预算(7 章)→ 拆预算(12/16 章)→ 量预算(本章)→ 超预算告警(25.4)

指标从哪来(它是"埋点"的形态):应用自己上报(每层代码里打点:这个接口耗时/这层调用耗时——12 章分层,每层一个计时点)、运行时采集(Node 的进程指标:内存/事件循环延迟——不写代码也有)、基础设施探针(数据库/Redis/CDN 的指标由平台/工具采集——14/11 章)——三个来源,一个平台(指标都汇到监控系统,画在同一张图上)——"监控系统"的本质:所有来源的指标,一个地方看(排障不用 SSH 到每台机器敲命令——23 章日志集中的同款逻辑,指标版)。

指标与 24 章压测的衔接("压测是测量一次,监控是测量一辈子"兑现):24 章说压测拐点(单机 1500 QPS)是容量告警的标尺——本章把它变成告警规则:QPS 接近拐点的 70% → 告警"该扩容了"——压测(一次性测量)→ 监控(持续测量)→ 告警(阈值化):测量的完整链条(16 章"先度量再优化"的运维版:度量不停,优化不停)。

指标的基础设施("监控哪些系统"的清单,兑现一路预告):应用指标(接口延迟/错误率——16 章)、数据库指标(连接数/慢查询/磁盘——14 章"数据层的健康不是不出事,是出事前有信号")、CDN 指标(命中率/回源率/节点延迟——11 章"CDN 健康状况的体温计")、服务存活(/health——21 章"一个接口三个用途":构建校验/高可用探活/监控存活)——监控不是"一个系统",是"每一层的体温计"(12 章说分层是排障地图——监控地图同样按层布)。

指标的存储与查询(它是"曲线怎么来的"):指标是时间序列(每个点:时间+值+标签)——存专门的时序存储(比通用数据库更适合:按时间聚合/降采样——14 章说数据库要选对场景,指标也要)——指标查询的三个动作看曲线(趋势)、对比(今天 vs 昨天)、下钻(总接口 → 单个接口 → 单个实例——从粗到细的排障路径:先看整体哪个接口,再看哪台机器——12 章分层排障的指标版)。

监控让"挂"有预兆(它是"层级"的补充):饱和度先红(连接池 80%)→ 延迟后红(P95 涨——排队开始了)→ 错误率再红(请求失败)→ 用户才感知——"监控的层级就是事故的提前量":在用户感知之前看见,才是监控的意义(25.4 的告警策略让提前量变成机制)。

指标与业务目标的对齐(它是"监控什么"的顶层):指标要能回答业务问题——"用户体验变差了吗"(P95/错误率)、"业务增长了吗"(QPS/订单量——业务指标)、"成本失控了吗"(资源使用率)——技术指标 + 业务指标两层:业务指标(订单量/注册量)是技术指标的"上游"(订单量涨→QPS 涨→饱和度涨——业务指标先变,技术指标后变,告警的是技术,解释的是业务——排障时先看业务指标:"订单量今天暴跌"和"QPS 暴涨"是两种完全不同的事故)。

指标与用户感知的"翻译"(16 章伏笔兑现——"用户感知是转圈,监控数据是 P95 2s+,同一个问题两种语言"):用户说"卡" → 指标是 P95 涨;用户说"打不开" → 指标是错误率 5xx 涨;用户说"图片加载慢" → CDN 命中率掉——排障的第一件事:把用户语言翻译成指标语言(16 章"信号是症状,度量是诊断"——翻译就是诊断的开始)——值班的人要会这门翻译(24 章值班清单的"再判断"一步,靠的就是它)。

指标的形态(它是"曲线"的意义):指标是时间序列(每个点带时间戳)——曲线的形状比单点重要:平稳 vs 爬升(16 章 P95 三个月从 200ms 爬到 2s——爬升期就该被看见)vs 陡增(雪崩)——"看监控"不是看现在,是看趋势(16 章巡检"每周三件事"的自动化版:命中率/慢查询/预算——本章让它们变成曲线)。

25.4 告警:把"看着"交给机器

监控有了,但人不能 24 小时盯着曲线——告警(alerting)是"把看着交给机器":指标异常时,机器通知值班的人(24 章 on-call 的眼睛——这里兑现)。告警设计是本章的决策点。

24 章事故的教训在这里收账(它是本章决策的起因):24 章雪崩事故里"告警半小时后才响"——为什么?阈值设得太松(P95 5 秒才告警——按"还扛得住"设的,不是按预算设的)+ 告警没分级(半夜全打给同一个人)+ 没有持续时间的判断(瞬时抖动也告)——本章的告警策略,就是那场事故的修复(事故=演进之母,第 2 章循环的又一次)。

★ 监控范围与告警策略——九步决策第 17 次应用(决策记录又添一行): 这个决策与 24 章可用性目标的呼应(它是"决策记录"的连贯):24 章定了 99.9%(第 16 次应用)——目标兑现需要"知道挂了"(告警)——第 17 次决策(监控范围与告警策略)是第 16 次的执行层:目标管"承诺多高",告警管"怎么知道没兑现"——决策记录不是孤立的行,是一层层执行的链(第 5 章"决策记录"思想:每次决策都接着上次的)。

① 目标:出问题时第一时间知道,且不被噪音淹没;② 约束:阶段 4——8 人团队、on-call 刚引入(24 章)、监控刚体系化;③ 问题:先监控什么?告警阈值怎么定?④ 候选:A 全量监控(所有指标都盯、都告警);B 核心链路优先(登录/浏览/下单+基础设施),阈值按预算定;C 只监控已有事故的(被动);⑤ 维度:覆盖度(漏报)、噪音(误报)、维护成本(指标也是要养的);⑥ 打分:A 的噪音会淹没信号(告警太多=狼来了,值班的人开始忽略告警——24 章说过"告警太多,值班等于狼来了");C 的盲区是未知的问题(可观测性第一原则:没记录的等于不存在);B 均衡——核心链路优先(第 17 章交易的接口永远第一优先级——钱的链路不能盲)、阈值按预算定(P95 预算 200ms → 告警 500ms 持续 5 分钟——预算×系数,不是拍脑袋);⑦ 选择B⑧ 收益:该知道的都知道(核心链路全覆盖),噪音可控(阈值有依据);⑨ 代价与演进:非核心链路有盲区(可接受:它们挂了的损失小)——演进条件:非核心链路出过事,再纳入监控(事故驱动扩容——19 章"后置的防御要有触发开关"同一个逻辑)。

告警阈值的"预算×系数"实操(它是"不拍脑袋"的配方):预算 × 2~3 倍 = 告警线(P95 预算 200ms → 告警 500ms——给正常波动留余量,限流 2.5 倍余量(上章)同一逻辑);持续 N 分钟(5 分钟:单次抖动不告警,持续异常才告警);对比基准(同比昨天同一时段——"今天比昨天慢 3 倍"比"500ms"更灵敏——趋势告警是进阶,阶段 4 先用阈值告警,知道趋势告警的存在)——告警阈值是配置(23.5 行为类配置:不发布也能改——调阈值也要走评审,24 章说过保护机制的参数要被管理)。

告警的分级(它是"半夜叫醒谁"的规则):P0(全站不可用/交易不可用——半夜叫醒 on-call+负责人);P1(单接口异常/部分用户受影响——on-call 处理,不用叫醒别人);P2(趋势异常/非核心链路——上班处理,记着就行)——分级的意义:告警是"叫醒"的决策(叫醒成本 vs 事故成本——升级路径上章已建,本章给"什么算 P0"的量化:错误率 >5% 持续 5 分钟 = P0,先于用户体验到之前)。

告警三要素("一条告警长什么样"):指标(什么异常了)、阈值与持续时间(P95 > 500ms 持续 5 分钟——持续 N 分钟才告警是关键:瞬时抖动不用打扰人,持续异常才是事故)、负责人(告警给谁——on-call 值班表)——告警不是"发通知",是"发对的通知给对的人"

告警的"值班流程"配合(它是"告警之后怎么办"):告警响了 → 值班的人先看是不是 P0(上章清单:先恢复再查因)→ 确认是真事故还是抖动(持续 5 分钟以上的大概率真——阈值设计里"持续 N 分钟"的意义)→ 处理/升级(30 分钟叫醒负责人)→ 处理完关掉告警+复盘(为什么响/阈值要不要调)——告警不是终点,是流程的起点(25.6 的排障时间线从告警开始)。

告警噪音治理(它是"告警会失效"的解药):告警太多 → 值班的人开始忽略 → 真事故也被忽略——噪音治理三招:阈值有依据(预算×系数,不是随手填)、合并(同一时间同一条链路的多个告警合并成一条)、分级(P0 半夜叫醒/P1 上班处理/P2 记下来——升级路径与值班清单配套)——告警的黄金标准:每条告警都是"需要人做点什么"(不需要行动的告警是噪音)。

告警与 on-call 的关系(24 章"on-call 的眼睛"兑现):24 章说"没有告警,值班等于等用户投诉;告警太多,值班等于狼来了"——本章把"眼睛"建好:告警=眼睛(自动看)、on-call=人(被叫醒处理)——眼睛+人=完整的事故响应:告警负责"知道",人负责"恢复"(24 章恢复优先)——24 章与本章的分工:24 章管"挂了怎么办"(机制),本章管"挂了怎么知道"(感知)——两章合起来才是完整的事故应对(24.7 说过)。

告警与限流数据的衔接("限流也要可观测"兑现):上章说"限流拦了多少请求要数得出来"——本章落地:限流拒绝数是一个指标(429 计数——正常 0,暴涨说明流量异常或阈值太紧);熔断打开次数也是一个指标(打开=依赖有问题,但每次打开都该被看见——机制的状态也要被观测(上章"保护机制的运行情况也是运行数据"——本章兑现)。

告警与安全(19 章兑现——"演进条件=监控告警配置项"):19 章说体验类防御后置,"挂了监控等信号"——信号清单就是告警规则:撞库特征(同一 IP 大量登录失败——登录失败率告警)、批量注册(注册频率异常)、异常下单(高频小金额)——安全章的后置开关,就是本章的告警规则(决策记录里的演进条件,变成监控告警的配置项——16 章说过"当时为什么不上、什么时候该上,都在记录里",这里是它的可执行形态)。

25.5 链路追踪:一次请求内部发生了什么

前两件套回答"整体",第三件套回答"一次请求":日志是一条一条的,链路把属于同一次请求的日志串成一条线(12 章说"链路追踪是日志链的自动化版"——这里兑现)。

trace_id 与 request_id 的关系(它是"两个 id"的澄清):request_id 是一次 HTTP 请求的 id(7 章:前端报错带上它);trace_id 是整条业务链的 id——一次用户操作(下单)可能触发多次请求+多个异步任务(17 章)——request_id 是 trace_id 的一部分(每个请求的 span 都带着同一个 trace_id)——前端报 request_id,后端按它找到 trace_id,再展开整棵树(15 章"联调吵不起来的秘密:两边对着同一个 id 说话"——本章让 id 能展开成一棵树)。

trace 的"一次请求"生命周期(它是"树怎么长"的实景):请求进来 → 网关/中间件生成 trace_id(12 章中间件:鉴权之后)→ 每进一层,记一个 span(父 span → 子 span)→ 数据库查询是一个 span(14 章:数据层也是链上的一站)→ 响应返回,树长完——一次请求=一棵树(10 章请求的旅程、15 章旅程十站——旅程思想(第 10/15 章)的观测版:每一站从"设计时的预算"变成"运行时的 span")。

从 request_id 到 trace(7/15 章兑现):第 7 章的 request_id 已经让"同一次请求的所有日志"可以按 id 捞出——链路追踪(tracing)把它自动化+结构化为父子树:一次请求进来,生成一个 trace_id(贯穿整条链);经过的每个环节(网关→中间件→业务→数据库)是一个 span(环节的名字+耗时+父子关系)——trace = 一棵树,span = 树上的节点——"一次请求在每层花了多久"从手工拼日志(12 章)变成自动画图(图 25-2)。

图25-2 图稿占位
链路追踪
一次请求跨服务的 trace/span

链路与 12 章旅程账的关系(它是"手工账"的自动化):12 章说"中间件 10ms/控制器 5ms/业务层 20ms/数据层 150ms"——那是设计时的预算账(手工拼日志算的);本章的链路把同一笔账自动画出来(图 25-2 的 span 耗时就是那笔账的运行时版本)——12 章埋的"每层打日志",本章收成"每层一个 span"(同一个分层结构,从代码结构升级为观测结构——12 章说"分层不只是代码结构,还是排障地图",本章兑现)。

链路与 17 章异步链的关系(它是"异步代价"的兑现):17 章说"异步化的代价清单里,排查复杂度最容易被低估"——本章的链路就是那笔代价的偿付:任务表→消息队列(26 章),一次下单动作拆成 5 个环节——没有 trace,排障=挨个环节猜;有 trace,一次操作一棵树——"异步能上,是因为链路能兜"(17 章说过"异步化之后必须有可观测性兜底"——本章兑现)。

链路的价值(它是"内部发生了什么"的答案):慢的请求,慢在哪一站?——一次接口慢 800ms:是中间件?业务?数据库?(12 章旅程账手工算过——链路自动画出来);异步任务断了,断在哪一环?(17 章说过"异步化之后必须有可观测性兜底"——下单后通知没到:回调没来/任务没跑/消息丢了/worker 挂了——trace_id 贯穿所有相关任务,一个 id 找到整条链)——链路回答的是"内部细节",是排障从"猜"到"看"的最后一公里

链路的"代价"与"适用范围"(它是"要不要上链路"的判断):链路是分布式系统的必需品(17 章:异步任务跨进程,不串起来没法排)——单体阶段不是必需品(12 章手工拼日志就够——但阶段 4 已经开始拆的苗头:任务表+异步(17 章)——链路从"异步出现"开始必要(17 章说过"异步化之后必须有可观测性兜底(第 25 章)"——本章兑现:链路就是异步时代的可观测性形态)——判断标准:一次操作跨了几个进程/任务(1 个:日志够;多个:链路要上——第 4 章复杂度预算)。

采样的经济学(它是"链路贵不贵"的答案):全量追踪成本高(每个请求都要记录+存储)——采样(sampling):只记录一部分请求(阶段 4:10%,高峰 1%)——排障要的是"代表性样本"(问题会重复出现,样本足够定位)——采样是"用一点点概率换大量成本"(16 章缓存随机的哲学:错开即省)。

链路追踪的工具(它是"怎么落地"的一瞥):开源体系(Jaeger/Zipkin 一类——语言无关、社区成熟)或云厂商方案——阶段 4 的落地:异步任务上线后(17 章),用现成工具把 trace_id 串起来(代码改动:中间件生成 trace_id + 每层 span——12 章分层,每个入口加两行)——链路不是新系统,是"request_id 的升级版"(从"一个 id 捞日志"升级为"一个 id 画树"——7 章埋的伏笔的最终形态)。

一个 trace 的"样子"(它是"树"的具象):trace_id: abc123——根 span:POST /orders(总耗时 850ms)→ 子 span:鉴权(15ms)→ 子 span:创建订单(200ms)→ 孙 span:INSERT orders(150ms)→ 子 span:发通知(异步,620ms 后才完成——17 章任务表)——一眼看出:慢在通知任务(620ms),不在主流程——这就是链路的价值:850ms 的请求,慢在哪一行代码的"下游",不用猜(15 章旅程账的自动化)。

链路与日志的关系(它是三件套的"串"):链路是索引,日志是内容——trace 告诉你"哪一站慢"(索引),点开那一站的 span 看日志细节(内容)——监控是"有没有病",链路是"病在哪一站",日志是"那一站的检查报告"(三件套的协作关系:从上到下,越来越细)。

25.6 排障流程:三问的自动化

三件套齐了,串成流程——排障的完整时间线(它是 15 章三问的自动化兑现,也是 24 章"先恢复再查因"的完整版):

排障时间线与 15 章排查法的对照(它是"升级"的完整形态):15 章联调三问(复现/分层/证据)是人工版——本章的告警/监控/日志是自动化版(15 章原话:"人工排查→自动化监控,是同一套三问的两次形态"——本章兑现)——两次形态的区别:人工版靠人记得走流程,自动化版靠体系记得看数据——"流程"从人的习惯变成系统的行为(20 章"流程是团队的函数"——运行期版本:流程是系统的函数)。

排障的"文档"(它是"事后"的留存):每次事故的复盘(24 章)和排障记录,要沉淀成团队的排障手册——"上次这个问题怎么解决的"(下次 5 分钟)——排障手册是团队的记忆(20 章说"流程是团队的函数"——排障手册是它的运行期形态:常见问题+处理步骤,新人值班也能处理——on-call 值班清单的"内容"来源之一)。

① 发现(三问的第一问自动化):告警响了(25.4)或用户报障——"现在挂没挂"由监控回答(挂没挂、挂多久、影响面多大——容量告警);② 定位(第二问):看监控曲线(哪类指标异常:延迟/错误率/流量/饱和度——25.3 四类)、查日志(按 request_id/trace_id 捞那批请求——25.2)、看链路(慢在哪一站——25.5)——定位从"猜"变成"查"(15 章"联调三问"的自动化版:报警=第一问自动化,日志链路=第二问自动化——15 章原话兑现);③ 恢复(24 章优先):先恢复再查因——回滚(23 章)、重启、切流量(24 章)——用户先能用复盘的"三问"(它是复盘的具体清单):哪道防线漏了(24 章机制)、哪条告警没响(本章感知)、哪个环节没记录(本章日志)——三问对应三件套+高可用:每问都有"补什么"的答案(补机制/补告警/补日志)——复盘不是写报告,是列"下次怎么更快"的清单(第 2 章演进循环的落地:每次事故都是体系的补丁)。

④ 复盘(24 章配套):哪道防线漏了?哪条告警没响?哪个环节没记录?——补机制、补监控、补日志——排障的终点不是修复,是"下一次更快"(第 2 章演进循环:事故→复盘→改进)。

一个完整的排障案例(它是流程的实景,用 24 章雪崩事故):告警响(P95 > 500ms 持续 5 分钟——P0)→ 值班的人醒来 → 看监控(错误率 5%、饱和度 80%——不是流量问题就是依赖问题)→ 看链路(数据库 span 3000ms——慢在数据层)→ 看日志(慢查询:全表扫描——14 章主角)→ 恢复(先回滚/限流止血)→ 复盘(补索引+加"慢查询告警"——下一次不用人发现)——流程的每一步都有工具,工具让流程从"靠人"变成"靠体系"

排障与第 2 章演进循环(它是"复盘"的理论版):第 2 章说演进循环"发现问题→解决问题→新问题"——排障复盘是运维版的演进循环:事故(发现问题)→ 修复+补监控(解决问题)→ 新的监控暴露新的问题(新问题——比如补了慢查询告警,发现连接池饱和更早)——可观测性体系不是建完的,是长出来的(每次事故长一块——25.7 的"从少到多",动力是事故)。

排障的辅助工具(它是"查日志"之外的取证):git blame/提交信息(20 章:排障时第一个看的就是它——"这次改动为什么存在"——能回滚 + 知道回滚什么);部署状态记录(22 章:哪个版本在跑——先确认"是不是这次发布引入的",排障的第一排除项);sourcemap(21 章:报错行号对着源码——错误日志从"压缩代码"变回"可读代码")——排障是团队所有章节积累的工具的集合(每章埋的工具,事故时一起上)。

MTTR 的三个阶段("从发现到恢复"的拆解):MTTD(发现时间)——告警快不快(25.4:阈值/分级决定);MTTI(定位时间)——三件套全不全(25.2-25.5);MTTR(恢复时间)——回滚/切换快不快(23/24 章)——24 章的 99.9% 目标,是这三个时间的总和决定的(年宕机 8.76 小时 ÷ 事故次数 = 每次事故的预算时间)——可观测性压缩的是前两段(发现+定位),恢复靠 23/24 章——每一章都是 MTTR 的一部分(第 22 章流水线管恢复的第一个动作:回滚)。

MTTR(它是排障速度的度量):MTTR(平均恢复时间)= 从发现到恢复——24 章 99.9% 目标(年宕机 8.76 小时)的兑现靠它:发现快(告警)、定位快(三件套)、恢复快(回滚/切换)——可观测性对业务的价值一句话:它把 MTTR 从"小时"压到"分钟"(那场雪崩:告警半小时后才响+人工排查=40 分钟;本章之后:告警 5 分钟+定位 10 分钟+回滚 5 分钟——MTTR 减半,靠的不是更努力,是工具)。

25.7 可观测性的边界与投资

三件套讲完,还要说清楚它的代价与边界——可观测性是投资,不是装饰(骨架原话)。

可观测性建设的顺序感(它是"投资怎么起步"的落地):别一上来就搭全家桶(日志平台+监控面板+链路系统一次到位——8 人团队会死在工具上)——阶段 4 的起步:日志先规范化(25.2 的规范,零成本:只是写日志的习惯)→ 用现成监控(云厂商的基础监控/开源方案)→ 告警只配核心链路(25.4 决策)→ 链路等"慢请求排不动"的信号再上(17 章异步上线后才需要)——每一步都是被问题逼出来的(第 2 章循环:可观测性也是被事故逼着长的)。

三件套的代价("可观测性不是免费的"):存储成本(日志/指标/链路都要存——阶段 4 每天几 GB);埋点成本(每层打日志、每个接口记指标——开发时间);维护成本(告警规则要养:阈值要调、噪音要清——不养的告警会烂掉);运维成本(日志平台/监控系统本身要维护——23 章说过 K8s 的教训:工具本身也是复杂度)——每一项都是第 4 章复杂度预算的花费(可观测性是"花复杂度买确定性")。

可观测性与第 26 章架构演进的衔接(它是"拆服务的前提"):26 章拆微服务的前提条件之一就是可观测性就位——拆了之后,一次用户操作跨多个服务(26 章),没有 trace 根本没法排(本章链路)——"拆之前先建可观测性"是微服务的最佳实践(先有眼睛,再动手术——26 章会正面展开:拆服务的第一件事不是代码,是观测)。

可观测性与团队成长的同步(它是"跟着人走"的投资):20 章说"流程是团队的函数"——可观测性也是团队的函数:1 人团队(阶段 1-3):日志够(12 章习惯);8 人团队(阶段 4):监控+告警(本章);几十人团队(阶段 5):链路+平台化(26 章拆服务后必配)——可观测性的建设跟着团队规模和系统复杂度走(第 4 章复杂度预算:工具也是预算,花在刀刃上)。

从少到多的顺序(它是"投资怎么分期"):阶段 4 的顺序:日志先行(地基——12 章已有雏形)→ 基础监控(延迟/错误率/存活)→ 告警(核心链路)→ 链路追踪(慢请求/异步排查需要时)——不是三件套一步到位,是按问题逼出来的(第 2 章演进循环:可观测性也是被事故逼着长的——24 章雪崩逼出告警,17 章异步逼出链路)。

可观测性与数据的关系(它是"日志也是数据"的提示):日志/指标/链路也是数据——它们同样要:安全(日志里可能有用户信息——19 章敏感数据:日志脱敏:密码/token 不打日志——第 13 章凭证、19 章密钥:日志是泄密高发地);保留策略(30 天——法律/审计要求,19 章审计日志);成本(存储——第 4 章预算)——"观测数据"不是免费的数据:它和业务数据一样要管理(第 6 章数据建模的运维版:观测数据也要建模)。

可观测性的边界(它是"投资不是装饰"的反面):过度可观测也是负债——每个接口都埋 50 个指标(没人看)、每条日志都打满上下文(检索慢)、告警 200 条(没人理)——判断标准:每条日志/指标/告警,都要回答"谁会看它、看了做什么"(第 4 章"需求可砍"思想的运维版:没人消费的观测数据,就是装饰)。

可观测性与 23 章配置的关系(它是"观测数据从哪来"的补充):日志级别、告警阈值、采样率都是配置(23.5 行为类配置)——发布不发布都能调,但调了要记录(配置变更走评审:把 ERROR 级别调成不记,等于把眼睛闭上——可观测性的"开关"也是生产行为,和限流阈值同级管理(24 章说过保护机制的参数要被管理)。

可观测性与第 27 章业务迭代的衔接(它是"监控反馈业务"的闭环):第 27 章业务迭代时,监控数据是"新功能好不好"的证据——上线后看指标(新功能转化率/接口错误率)——可观测性不只是排障工具,还是业务决策的数据源(16 章"业务指标先变"——第 27 章迭代的"上线→监控→下一轮",监控是那一环)。

可观测性与第 1 章地图的关系(它是"工程线"的收官件):第 1 章说工程线回答"怎么让能跑的代码变成能一直跑的产品"——第 22 章流水线(交付)、第 23 章部署(放置)、第 24 章高可用(保障)、本章可观测性(感知)——工程线的最后四块拼图——"能一直跑"的完整含义:能交付、能放置、挂不了、看得见(22 章说"第 1 章地图的三条线开始合流"——本章之后,工程线合流完成)。

前端可观测性(8 章兑现:"开发者工具是前端版可观测性"):前端的观测——浏览器开发者工具(8 章:单次排查)、前端监控 SDK(页面错误/资源加载失败/首屏时间——前端也有"错误率和延迟")、用户反馈(老周的消息——最真实也最滞后)——前后端合起来,才是完整的"看得见"(15 章联调:前后端各看各的日志,对着同一个 request_id——可观测性同理:前端记录+后端记录,同一根链)。

前端监控的具体指标(它是"前端版四类"的落地):页面错误(JS 异常率——8 章白屏的元凶)、资源加载失败率(图片/JS/CSS 没加载——11 章 CDN 视角)、首屏时间(FCP/LCP——8 章性能指标)、接口失败率(前端调后端失败的占比——15 章联调视角)——前端指标和后端指标对着看(前端接口失败率高+后端错误率正常 = 网络/网关问题;两个都高 = 后端问题——对表诊断:15 章"两边对着同一个 id 说话",25 章"两边对着同一组指标")。

"看得见"的三层(它是引导词的总收):第一层:系统看得见(三件套——本章主体);第二层:团队看得见(on-call 交接、排障手册——24/25 章的人和流程);第三层:业务看得见(指标回答业务问题——业务指标与技术指标对齐)——可观测性的终点:系统、团队、业务,三双眼睛都在看(第 1 章地图:看得见的产品,才谈得上"能一直跑")。

合成监控(18 章兑现——"E2E 从开发工具变成运维哨兵"):把核心路径的 E2E 部署到生产定时跑——用户报障之前,E2E 先发现"下单挂了"——"测试"和"监控"在这里合流(18 章说过:测试不只是上线前跑,也上线后跑)——合成监控是"主动的发现",用户报障是"被动的发现"(主动永远比被动好——24 章"发现快")。

25.8 本章对应表

业务诉求技术选择为什么代价/取舍
"打不开"说不清哪里三件套(图 25-1)三问各有一件工具:日志/监控/链路三件都要建(顺序:日志→监控→链路)
用户报障查不到那次请求request_id → trace_id对着同一个 id 说话(7/15 章)埋点要规范(每层都带)
挂了不知道告警(★决策第 17 次)把看着交给机器;on-call 的眼睛噪音=告警失效(阈值按预算×系数)
慢得诡异指标曲线(延迟/错误率/流量/饱和度)趋势比单点重要(P95 爬升)指标要养(阈值/噪音治理)
异步任务断了找不着链路追踪(图 25-2)17 章异步的代价清单:trace 贯穿采样(10%)换成本
被攻击了不知道审计日志19 章:审计是安全的"事后诸葛亮"日志要留得住(30 天)
用户报障前发现挂合成监控18 章:E2E 从开发工具变成运维哨兵核心路径才配得上(预算)

每一行都在本章正文里有完整论证:三件套在 25.1,日志在 25.2,指标在 25.3,告警在 25.4,链路在 25.5,排障流程在 25.6,边界在 25.7。先看"业务诉求"列——每一行都是一个"看不见"的问题,被一件工具变成"看得见"

本章小结

可观测性速查(第六部分回指本章时翻回这里):

  1. 三问与三件套:现在挂没挂(监控)/哪里挂的(日志+链路)/当时发生了什么(日志)——第一原则:排查从被记录开始;
  2. 日志:时间/级别/request_id/上下文;结构化(JSON 事件流);集中收集;错误详情只进日志(19/23);审计日志留得住(19);日志量是预算(级别过滤+30 天保留);
  3. 监控:四类指标(延迟/错误率/流量/饱和度);指标=预算的实时检查(16 章);每层体温计(应用/数据库/CDN/存活);
  4. 告警(★第 17 次决策):核心链路优先;阈值=预算×系数+持续 N 分钟;噪音治理(合并/分级);安全信号清单=告警规则(19);
  5. 链路追踪:request_id→trace_id;trace=树、span=节点(图 25-2);异步贯穿(17);采样 10%;链路是索引,日志是内容;
  6. 排障时间线:告警发现→监控定位→日志取证→恢复优先(24)→复盘补监控(第 2 章循环);MTTR=可观测性的业务价值;
  7. 边界:可观测性是投资不是装饰——没人消费的观测数据是负债;从少到多(事故逼着长);前端版=开发者工具(8);合成监控=主动发现(18)。 (七条速查对应本章结构:1 是"总览",2-3 是"日志与监控",4 是"告警",5 是"链路",6 是"流程",7 是"边界"——第 26 章架构演进回指时重点翻 5(链路)和 6(排障)。)

  • 三件套回答三问:日志(发生了什么)、监控(是否正常)、链路(内部细节)——从上到下,越来越细;
  • 第一原则:排查从被记录开始——没被记录的问题等于不存在(14 章预演兑现);
  • 告警是把"看着"交给机器(★决策第 17 次):核心链路优先、阈值=预算×系数——告警太多等于没有告警;
  • 可观测性是投资不是装饰:从少到多(事故逼着长)、没人消费的观测数据是负债;
  • MTTR 是业务价值:发现快(告警)、定位快(三件套)、恢复快(回滚/切换)——可观测性把 MTTR 从小时压到分钟。

下一章

系统现在"看得见"了:挂了有告警、慢了有曲线、错了有日志。业务也在增长——阶段 5 来了:日活新高、功能膨胀、8 人团队改一个仓库越来越挤、发布互相踩(第 20 章的老问题重演)、数据库连接数告急(24 章说"扩容的尽头是架构问题")。

第 26 章,架构演进:单体 vs 微服务——什么时候该拆?怎么拆?——这是全书架构线(第 3 章总架构、第 6 章设计、第 17 章异步链)的收官,也是"业务没到就别上"(第 23 章 K8s 决策)的姊妹篇:什么时候其实不需要微服务