# 看不见，就修不了

关于 observability 的速成课。22 个概念——Observability、Structured Logging、Four Golden Signals、Trace 与 Span、Correlation ID、SLI/SLO/SLA、Alert Fatigue 等——每个都配有英文名称、一张图、一张卡片，以及它与其他概念的联系。只讲精髓：在生产环境里你没法挂上 debugger，所以你要把系统建成会自己解释自己的样子。结尾附一页速查表，列出全部概念。

- **Author:** Fedor Chishchin
- **Level:** intermediate
- **Reading time:** ~35 分钟阅读
- **Published:** 2026-06-13
- **Source:** https://fedorthinks.com/zh/learn/observability-express

---

## 1. 为什么需要 observability

整个领域的存在源于一个硬事实：你没法像在自己机器上调试代码那样去调试一个正在运行的生产系统。所以你得让系统自己告诉你它在做什么。

### 全景图：七组共 22 个概念

> 一张地铁线路图：先看到所有线路的全貌，再一站一站地坐过去。

先是三个**基础**——为什么在生产环境里你只能靠仪表飞行，monitoring 和 observability 有何不同，以及什么是 black box。然后是六组，每章一组：**logs**、**metrics**、**traces**、三大支柱如何**合在一起**用、**alerting**，以及如何**用好它**。

下面每个概念都是同一个结构：它的**英文名称**（记住它——这就是术语）、一幅生活中的画面、一张**图**，以及一张带字段的**卡片**：_问题_、_思路_、_例子_、*代价*或*注意*、_何时使用_、_关联_。

_Diagram: 上面是基础；下面是六组——第 2–7 章依次对应它们。_

### Flying by Instruments — 你没法给生产环境挂上 debugger

> 飞行员不能在飞行途中爬出去检查发动机——他完全靠仪表盘上的仪表飞行，相信表盘告诉他的一切。

在笔记本上，你可以暂停代码、查看变量、单步执行。在**生产环境**——真实的服务器、真实的用户、就在此刻——你没法停下它来看。你只能从系统运行时发出的**信号**里了解发生了什么。

这就是核心的转变：在生产环境里你靠仪表飞行，而 observability 就是在需要之前，先把正确的仪表装在仪表盘上。

_Diagram: 在笔记本上，你用 debugger 往里看。在生产环境里，你只能看到系统发出的东西：logs、metrics、traces。_

#### Flying by Instruments (生产环境，靠信号运行)

- **问题:** 你没法暂停线上的生产环境，用 debugger 去检查它。
- **思路:** 只通过系统运行时发出的信号来了解发生了什么。
- **例子:** 不是在支付代码里打一个 breakpoint，而是看错误 metric、请求的 trace 和一行 log。
- **后果:** 仪表必须提前装在仪表盘上，而不是在故障期间才去加。
- **关联:** 这些仪表就是三大支柱：**logs**、**metrics**、**traces**。

### Monitoring vs Observability — 已知的问题与新问题

> 汽车仪表盘显示的是你早就知道要盯的那几样——车速、油量、温度。但当出现一种陌生的新噪音时，你需要能去调查一个没人给它装表盘的东西。

**Monitoring** 是盯着你预料到的问题——针对已知故障模式的 dashboard 和告警。**Observability**（常写作 **o11y**）是更深一层的特性：只凭系统产生的数据，你能不能回答你*没有*预见到的问题？

真正的故障往往是前所未有的——"为什么巴西的用户从下午两点起结账很慢？"——而 observability 就看你的系统发出的数据够不够让你去追一个你从没计划过的问题。

_Diagram: Monitoring 回答事先设好的问题。Observability 让你对丰富的数据做切片，去回答一个昨天还不存在的问题。_

#### Observability (o11y（相对于 monitoring）)

- **问题:** Dashboard 和告警只能抓住你预见到的故障；真正的故障往往是新的。
- **思路:** 系统发出足够的数据，能回答一个没人计划过的问题。
- **例子:** "为什么巴西的结账从下午两点起变慢？"——你按地区、时间和 endpoint 对数据做切片。
- **监控:** 盯着已知的东西。需要，但不够。
- **关联:** 让你能调查；**alerting** 告诉你何时开始。

### Black Box — 只能靠猜的系统

> 一台吞了别人钱却什么都没吐出来的自动售货机，没有显示屏，也没有小票——你只能耸耸肩去猜，因为它什么都不告诉你。

一个很少发出信号的系统就是 **black box**：它出问题时，你只剩下猜和重启。代价出现在最糟的时刻——一场生产事故，每一分钟都很宝贵，而你完全不知道该往哪儿看。

Observability 是提前付出的，在系统平静的时候就给它做**埋点**（instrumenting），这样当它着火时，你才有光可以照亮。

_Diagram: 上：black box——出错时你只能猜和重启。下：同一个服务，但它会发出 logs、metrics 和 traces。_

#### Black Box (不透明的系统)

- **是什么:** 一个几乎不对外发出任何自身信息的系统。
- **为什么有害:** 事故期间你只能猜和重启，而每一分钟都在烧钱。
- **例子:** 服务挂了，logs 是空的，也没有 metrics——该往哪儿看？
- **解法:** 趁系统平静时就做好埋点。
- **关联:** 靠 **Instrument as You Build** 这个做法来治。

> **核心问题:** "当这个东西凌晨三点在生产环境里坏掉时，系统到底能告诉我什么——还是我只能在黑暗中瞎猜？"

> 你没法暂停生产环境去检查它。Observability 就是把系统建成能自己解释自己——这样你不只是盯着预料到的问题，还能回答你从没预见到的问题。

## 2. Logs

最古老、最详细的信号就是 log：系统做过什么的流水账。它是你最先去翻的东西，也是最容易用错的东西。

### Log — 系统的日记

> 船上的航海日志：带时间戳的条目记录发生了什么、何时发生——"10:42，驶入港口"——这样任何人事后都能还原整段航程。

**Log** 是一个事件带时间戳的记录："用户 42 登录了"、"支付失败：银行卡被拒"、"开始处理订单 91"。每一行都是一条小而详细的笔记，记下发生的某件事，在代码运行时写下。

Logs 是信息最丰富的信号，因为它们带着具体细节——到底是什么、到底何时、附带哪些细节。当你需要知道某一个案例里到底发生了什么，就去看 logs。

_Diagram: 一条 log 流：时间戳、级别、事件。一行就是一个事件。_

#### Log (事件记录)

- **是什么:** 一个事件的记录，带时间戳和细节。
- **回答:** "在这一个具体案例里，到底发生了什么？"
- **例子:** `10:42:09 ERROR payment failed: card declined`
- **注意:** 容易写过头——噪声、存储账单、搜索变慢。
- **关联:** 靠 **structured logging** 和 **log levels** 变得有用；通过 **correlation ID** 与 trace 关联起来。

### Structured Logging — 可以搜索的 logs

> 一盒手写笔记和一张电子表格的区别——两者都记着事实，但只有后者能让你立刻筛出与客户 42 有关的一切。

一行自由文本，在几百万条记录里很难搜。**Structured logs** 把每个事件记成数据——比如 `user_id: 42`、`status: failed`、`duration_ms: 230` 这样的字段——这样你就能查询："显示今天所有超过 500ms 的失败支付。"

这把 logs 从一面要不停滚动的文字墙，变成了一个可以审问的数据库。有了结构，logs 才能在生产规模下用得起来。

_Diagram: 同一条记录，一份是自由文本，一份是带字段的数据。字段才是你能查询的东西。_

#### Structured Logging (把 logs 当数据)

- **问题:** 自由文本没法在几百万行里查找或过滤。
- **思路:** 把每个事件写成数据：用有名字的字段，而不是一句话。
- **例子:** `user_id: 42`、`status: failed`、`duration_ms: 230` → "今天所有超过 500ms 的失败支付。"
- **代价:** 你得统一字段名，并保持一致。
- **何时使用:** 总是——只要 logs 多到肉眼没法滚着看了。
- **关联:** 每一行上的 `request_id` 字段是 **correlation ID** 的基础。

### Log Levels — 把信号和噪声分开

> 一本日记：日常条目用铅笔写，紧急情况用红笔写——这样遇到危机时，你能直接翻到红色的那些，忽略其余。

每条 log 都有一个标记重要程度的**级别**：`DEBUG` 和 `INFO` 用于日常细节，`WARN` 表示有点不对劲，`ERROR` 表示真正的故障。级别让你在调查时调大音量，在正常运行时调小，并在一大堆记录里直接跳到错误。

用好了，级别能让重要的行始终找得到；被忽视了，每条 log 看起来都同样紧急，没有一条显眼。

_Diagram: 按重要程度分的四个级别。正常运行时保留 INFO 及以上；调查时再把 DEBUG 也打开。_

#### Log Levels (DEBUG、INFO、WARN、ERROR)

- **是什么:** 每行 log 上的一个重要程度标签。
- **原理:** `DEBUG`/`INFO` — 日常，`WARN` — 有点不对劲，`ERROR` — 真正的故障。
- **例子:** 事故期间你过滤出 `ERROR`，立刻就能看到故障。
- **注意:** 如果所有东西都记成 `ERROR`，就没有哪个显眼了。
- **关联:** 相对于 **log volume** 的音量旋钮。

### Log Volume — log 太多和太少一样没用

> 一本把每一次呼吸都记下来的日记，和一本空白的日记一样没法读——你需要的信号被埋在没人筛得完的噪声里。

Logs 很容易被滥用，而 **over-logging** 有实实在在的代价：存储贵、搜索慢，还会把重要的行埋进噪声里。

关键在于记下你以后真正会想要的东西——**决策、故障、关键事件**——细节够用就行，别多到把信号淹没。记 log 要有目的，别凭条件反射。

_Diagram: logs 太少——你是瞎的。太多——噪声加存储账单。价值在中间：决策、故障、关键事件。_

#### Log Volume (over-logging)

- **是什么:** "以防万一"地把每一步都记下来。
- **为什么有害:** 存储贵、搜索慢，重要的东西淹没在噪声里。
- **例子:** 一本把每次呼吸都记下的日记，读起来和空白的一样没用。
- **解法:** 有目的地记：决策、故障、关键事件。
- **关联:** 由 **log levels** 控制；和 **alert fatigue** 是同一种噪声陷阱。

> **关于 logs 的问题:** "以后我调试这个问题时，logs 里会有我需要的细节吗——有结构、有级别，并且聚焦于重要的东西，而不是把它埋掉？"

> Logs 是发生过什么的详细日记。让它们有结构，这样能查询；有级别，这样能过滤；有重点，这样信号不会淹没在噪声里。

## 3. Metrics

Logs 告诉你单个事件。Metrics 告诉你整体随时间的变化——那些一眼就能看出系统是健康还是在走下坡路的数字。

### Metric — 随时间变化的一个数字

> 医院里记录整夜心率的图表——不是每一次心跳，而是稳定采样得到的那个数字，所以一条上升的趋势会一下子跳出来。

**Metric** 是随时间追踪的一项度量：每秒请求数、错误率、响应时间、已用内存。和 log 不同，它说的不是某一个事件——它是**聚合**，被持续采样，所以你看到的是趋势和尖峰。

Metrics 采集和存储都很便宜，因为它们只是数字，这意味着你可以对所有东西、一直保留它们，并看着系统的形态变化。

_Diagram: Metric 是随时间排列的一串点。你看到的是趋势和尖峰，而不是某一个请求。_

#### Metric (时间序列)

- **是什么:** 随时间稳定采样的一个数值度量。
- **回答:** "有没有哪里不对，趋势如何？"
- **例子:** 每秒请求数、错误率、响应时间、内存。
- **优点:** 采集和存储便宜——对所有东西、一直保留。
- **缺点:** 对单个请求的细节一无所知——那要去看 traces 和 logs。
- **关联:** 分为 **counter** 或 **gauge**；在 **dashboard** 上查看；是 **SLI** 的基础。

### Counter vs Gauge — counter 一路上升，gauge 上下摆动

> 里程表只会一路往上，数着一共开过多少英里；速度表则随你此刻的快慢起起落落。

两种基本形状涵盖了大多数 metrics。**Counter** 只增不减——已处理的请求总数、错误总数——你要看的是它的变化*速率*。**Gauge** 上下移动，显示当前值——正在使用的内存、活跃连接数、队列长度。

知道自己看的是哪一种，就知道该怎么读它：counter 看的是斜率；gauge 看的是当前的高度。

_Diagram: Counter 是里程表：读斜率（速率）。Gauge 是速度表：读当前值。_

#### Counter vs Gauge (metric 的两种形状)

- **Counter:** 只增不减：请求总数、错误总数。读它的速率。
- **Gauge:** 上下波动：内存、活跃连接数、队列长度。读它的当前值。
- **例子:** "累计 10,400 个错误"说明不了什么；"每分钟的错误数翻了三倍"说明很多。
- **注意:** 把 counter 当 gauge 来读——看的是高度，而不是斜率。
- **关联:** 任何 **metric** 的两种形状。

### Dashboard — 让趋势看得见

> 控制室里一整面墙的仪表：操作员一眼就能看出一切都是绿色且平稳，或者哪个表盘正朝红色爬升。

Metrics 通常在 **dashboard** 上查看——把关键数字随时间变化的图并排摆在一起。好的 dashboard 能让你几秒钟内看清系统的健康状况，并发现某条线是在哪一刻拐向了不对的方向。

Metrics 的价值就体现在这里：不在任何单个数值，而在那条可见的趋势——它在用户还没抱怨完之前就告诉你"下午两点起有什么开始出问题了"。

_Diagram: 并排的四张图：三张是平的，错误在下午两点向上拐——一眼就能看见。_

#### Dashboard (一眼看清 metrics)

- **是什么:** 关键 metrics 随时间变化的图，并排摆放。
- **为什么:** 几秒内看清系统的健康状况，以及某条线拐弯的那一刻。
- **例子:** 错误从下午两点开始攀升——在投诉到来之前就能看到。
- **注意:** Dashboard 不会叫醒任何人——得有人去看。紧急的事要交给 **alerts**。
- **关联:** 展示 **metrics**；最先放的几张图是 **four golden signals**。

### Four Golden Signals — 服务的生命体征

> 医生快速检查生命体征——脉搏、体温、血压、呼吸——一小组指标，不必什么都测，就能发现大部分问题。

起步不需要一千个 metrics。**Four golden signals** 涵盖了系统大部分的健康状况：**latency**（请求要多久）、**traffic**（有多少需求）、**errors**（有多少请求失败）和 **saturation**（你的资源有多满）。

盯住这四个，你就能及早发现绝大多数问题。它们是服务的生命体征——是最先该装到仪表盘上的几个表盘。

_Diagram: 围绕一个服务的四个 golden signals：latency、traffic、errors、saturation。_

#### Four Golden Signals (latency、traffic、errors、saturation)

- **问题:** 不清楚该从哪些 metrics 开始，而一千个 metrics 只是噪声。
- **思路:** 四个数字涵盖系统大部分的健康状况：latency、traffic、errors、saturation。
- **例子:** 一个支付服务：响应时间、每秒请求数、失败占比、连接池使用率。
- **何时使用:** 任何新服务最先要画的几张图。
- **关联:** 放在 **dashboard** 上；**SLI** 从它们中取得；是 **Start Small and Grow** 的起点。

> **关于 metrics 的问题:** "我有没有在追踪生命体征——latency、traffic、errors、saturation——这样我就能在问题变成故障之前，把它当作趋势看出来？"

> Metrics 是随时间变化的数字——一路上升的 counter、上下摆动的 gauge——展示在 dashboard 上。从 four golden signals 开始：latency、traffic、errors、saturation。

## 4. Traces

在一个有许多服务的系统里，一个用户请求会经过其中很多个。Trace 把这一个请求从头到尾跟下来——回答 logs 和 metrics 回答不了的问题：在这一切之中，时间或故障究竟出在哪里？

### Trace — 一个请求穿过各服务的路径

> 包裹的追踪记录：在这里揽收，在那里分拣，空运过去，最后送达——一个包裹经过每一双手的完整旅程。

在现代系统里，一个请求会跳过很多服务——gateway 调用订单服务，订单服务调用支付，支付再调用数据库。**Trace** 记录一个请求的整段旅程，把它缝合起来，让你看到它跳过的每一站。

它回答的问题，logs 和 metrics 都回答不了：不是"发生了什么"或"有多少"，而是"*这一个具体的请求*在整个系统里走的是什么路径？"

_Diagram: 一个 trace 就是一个请求：用户 → gateway → 订单 → 支付 → 数据库，每一跳都缝在同一个 ID 之下。_

#### Trace (请求路径)

- **是什么:** 一个请求穿过每个服务的完整路径的记录。
- **回答:** "在这个请求的路径上，问题出在哪里？"
- **例子:** Gateway → 订单 → 支付 → 数据库，全都在同一个 trace ID 之下。
- **代价:** 每个服务都得把这个 ID 传下去，否则路径就断了。
- **关联:** 由 **spans** 组成；它的 ID 就是 **correlation ID**。

### Span — 时间花在了哪里

> 一份分成几段的旅行行程，每段都有自己的时长——一眼就能看出吃掉一整天的是那三小时的中转，而不是航班本身。

Trace 由 **spans** 组成——每一步一个，各自记录那一段花了多久。摊开成**瀑布图**（waterfall），spans 会准确显示一个慢请求把时间花在了哪里：数据库的 span 用了 900ms，其他所有加起来才 50。

没有它，"请求很慢"就是一个横跨许多服务的谜；有了它，你能直接指出罪魁祸首。Spans 把含糊的"慢"变成了精确的位置。

_Diagram: 一张 span 瀑布图：在一个 950 ms 的请求里，一次数据库查询就吃掉了 900 ms。_

#### Span (trace 的一步)

- **是什么:** trace 里被计时的一步：开始、结束、时长。
- **原理:** Spans 可以嵌套，并按时间铺开成瀑布图。
- **例子:** 数据库的 span 用了 900ms，其余全部加起来 50ms。罪魁祸首一目了然。
- **为什么:** 把"某处很慢"变成一个精确的位置。
- **关联:** **trace** 的构件。

### Distributed Tracing — 你如何调试分布式系统

> 在接力赛里把一根掉落的接力棒一路倒查回去，找出究竟是哪一次交接出了错——光看最终结果是看不出来的。

当一个请求失败或慢得像爬，而工作分散在各个服务之间时，trace 往往是找出问题所在的唯一办法。这就是 **distributed tracing**。

Metrics 告诉你系统慢；logs 告诉你每个服务说了什么；trace 把一个请求的路径串起来，指出究竟是哪个服务、哪一步出了问题。对任何分布式的东西来说，tracing 就是那个把"里面某个地方出错了"变成"就是这里"的工具。

_Diagram: Metrics 说“某处慢”，logs 说每个服务说了什么，而 trace 指出确切坏掉的那一步。_

#### Distributed Tracing (跨服务的 tracing)

- **问题:** 工作分散在各个服务之间；最终结果看不出是哪一步坏了。
- **思路:** 把每个请求穿过所有服务的过程作为同一个 trace 来跟踪。
- **例子:** 结账在失败：trace 显示出问题的是支付服务那一步。
- **何时使用:** 只要一个请求经过的服务超过一个。
- **关联:** 由 **trace** 和 **span** 构成；是 **notice → locate → explain** 的第二步。

> **关于 traces 的问题:** "当一个请求在好几个服务之间变慢或失败时，我能不能跟着它的完整路径，看出究竟是哪一步该负责？"

> Trace 跟着一个请求穿过每个服务，被切分成带计时的 spans——这样你就能准确看到，在分布式系统里，时间或故障究竟出在哪里。

## 5. 三大支柱合在一起

Logs、metrics 和 traces 被称为 observability 的三大支柱，因为各自回答的是不同的问题。力量在于把它们一起用，而不是只挑一个。

### Three Pillars — 各自回答不同的问题

> 用三样工具调查一个问题：一张图表显示什么时候发生了变化，一张地图显示在哪里，一份详细报告显示究竟是什么——单独都没用，合起来才有决定性。

**Observability 的三大支柱**把工作分了工。**Metrics** 回答"*有没有*哪里不对，趋势如何？"——便宜、始终开着的全景。**Traces** 回答"在所有服务之中，问题出*在哪里*？"——把范围缩小到某一步。**Logs** 回答"那里*究竟*发生了什么？"——现场的全部细节。

任何一个单独都不够；每一个都接着其他几个停下的地方往下走。

_Diagram: 三大支柱：metrics——有没有问题，traces——在哪里，logs——究竟是什么。合起来撑起 observability。_

#### Three Pillars of Observability (metrics、traces、logs)

- **问题:** 没有哪一种信号能回答事故中的所有问题。
- **思路:** Metrics——"有问题吗？"，traces——"在哪里？"，logs——"究竟是什么？"。
- **例子:** 只有 metrics：你知道情况不好，却不知道在哪。只有 logs：你淹没在细节里，手里没有地图。
- **何时使用:** 对生产环境里的每一个服务。
- **关联:** 按 **notice → locate → explain** 的顺序依次走；由 **correlation ID** 串起来。

### Notice → Locate → Explain — 自然的流程

> 医生在体温单上看到发烧，接着检查找出是哪个器官，再做那项能指出病名的具体检验——先是宽泛的信号，再收窄，最后精确。

实际中你是按顺序走过它们的。一个 **metric** 或告警告诉你出事了（错误率跳高）。一个 **trace** 告诉你在哪里（支付服务那一步在失败）。那个位置上的一条 **log** 告诉你究竟是什么（支付服务商返回了超时）。

从宽泛到收窄再到精确：**metric 发现，trace 定位，log 解释**。懂得这个流程，就懂了调试生产环境的大半。

_Diagram: 调查漏斗：metric 发现，trace 定位，log 解释。_

#### Notice → Locate → Explain (metric → trace → log)

- **问题:** 事故中不清楚该从哪个信号入手。
- **思路:** 从宽泛到精确：先 metric，再 trace，最后 log。
- **例子:** 错误率跳高 → trace：支付那一步在失败 → log：服务商返回了超时。
- **注意:** 一上来就在 logs 里 grep——没有地图，却想大海捞针。
- **关联:** 只有当信号由 **correlation ID** 串起来时才快。

### Correlation ID — 把一切串起来的那根线

> 在每一份文件、照片和报告上都写上同一个案件编号——这样调查员就能把一起事件的所有东西拉到一起，而不必逐堆分别去找。

支柱之间一旦连起来，就强大得多。给一个请求的 metrics、trace 和每一行 log 都附上同一个 **request ID**（或 **trace ID**），你就能从"这个请求失败了"直接跳到它的 trace 和它确切的 logs。这就是 **correlation**（关联）。

没有 correlation，你面对的是三堆互相独立的干草垛；有了它，一拉就把一起事故的完整故事带到你面前。支柱之间的连接，让它们成为一个体系，而不是三件工具。

_Diagram: metric、trace 和每个服务的 logs 里都有同一个 request_id——一个请求的完整故事，一步到位。_

#### Correlation ID (request ID、trace ID)

- **问题:** Metrics、traces 和 logs 躺在三堆互相独立的干草垛里。
- **思路:** 每个请求一个共享的 ID——放在 trace 里，也放在每一行 log 上。
- **例子:** 搜 `request_id=abc123`，你就能得到这个请求的 trace，加上 gateway 和支付的 logs。
- **代价:** 这个 ID 必须传过每个服务，并写进每一条 log。
- **关联:** 把**三大支柱**粘在一起；最方便的做法是把它作为 **structured logging** 里的一个字段。

> **关于支柱的问题:** "我能不能从一个发现问题的 metric，走到定位它的 trace，再走到解释它的 logs——并且用共享的 ID 把这三者绑到同一个请求上？"

> Metrics 发现，traces 定位，logs 解释——从宽泛到收窄再到精确。用共享的 request ID 把它们关联起来，三件工具就成了一个关于哪里出了错的完整故事。

## 6. Alerting 与 SLO

Observability 让你能调查；alerting 告诉你何时开始。难的不是发现问题——而是决定哪些问题值得把一个人叫醒。

### Symptom-based Alerting — 针对用户能感受到的东西告警

> 烟雾报警器应该在真的起火时响，而不是每次有人烤面包就响——否则人们会把电池抠掉，反而错过真正的那一次。

**告警**（alert）是某个东西越过一条线时自动发出的通知。关键在于针对**用户真正能感受到的症状**告警——结账在失败、网站很慢——而不是针对每一次内部的小抽动。

服务器内存用到 80%，只要用户一切正常，就不是问题；订单失败数激增就是问题，即使每台服务器看起来都健康。针对面向用户的结果告警，你叫醒人的时候就都是真正重要的事。

_Diagram: 不会伤到用户的内部信号放到 dashboard 上。用户能感受到的症状，才值得叫醒一个人。_

#### Symptom-based Alerting (针对面向用户的症状告警)

- **问题:** 针对每一次内部的小抽动告警，会为不重要的事把人吵醒。
- **思路:** 只在用户真正能感受到的结果上呼叫人。
- **例子:** 内存 80% 而用户很满意——不告警。订单失败数激增——告警，即使服务器看起来一片绿。
- **何时使用:** 凡是要给人发通知的东西。
- **关联:** 那条线由 **SLO** 来定；它让你免于 **alert fatigue**。

### SLI / SLO / SLA — 定义什么叫够好

> 一家快递公司承诺"99% 的包裹两天内送达"——一条清晰、可衡量的标准，说明什么算可接受的服务，事先就说好了。

三个缩写把"多好才算够好"正式化了。**SLI**（service level indicator，服务水平指标）是度量（在 300ms 内完成的请求所占的百分比）。**SLO**（service level objective，服务水平目标）是你为它定的目标（应该达到 99.9%）。**SLA**（service level agreement，服务水平协议）是对客户的合同承诺，做不到要承担后果。

定下一个明确的 SLO，就把可靠性从一种模糊的感觉，变成了一个能用来要求系统的数字——也变成了一条何时该行动的清晰界线。

_Diagram: SLI——你度量的东西，SLO——目标，SLA——合同对客户的承诺。_

#### SLI / SLO / SLA (指标、目标、协议)

- **SLI:** 度量：在 300ms 内完成的请求占比。
- **SLO:** SLI 的目标：应该达到 99.9%。
- **SLA:** 对客户的合同承诺，做不到要承担后果。
- **为什么:** "足够可靠"变成了一个数字——也变成了一条何时该行动的清晰界线。
- **关联:** SLI 由 **metrics** 和 **golden signals** 构建；SLO 是 **alerts** 的那条线。

### Alert Fatigue — 无声的杀手

> 一辆为琐事不停哔哔响的车，会让司机学会无视所有哔声——于是真正重要的那次警告，也跟着其余的一起被屏蔽了。

告警太多本身就是一种失败：当人们为不重要的事被呼叫，他们就会开始完全无视告警，而真正的那一条就在噪声里被漏掉——这就是 **alert fatigue**（告警疲劳）。

每一条告警都应该是**可执行的**，并且值得人此刻就投入注意力；如果不是，它该放在 dashboard 上，而不是 pager 里。少而精的告警胜过一大片，因为一个没人信任的告警，比没有告警还糟。

_Diagram: 一大片嘈杂的告警会让所有人学会无视全部——真正的那条就被淹没了。少数几条精准的告警才能一直被信任。_

#### Alert Fatigue (pager 噪声)

- **是什么:** 因为告警太多，人们不再对告警做出反应。
- **为什么有害:** 真正的告警连同噪声一起被无视。
- **例子:** Pager 每小时都为琐事哔哔响——没人会为真正重要的那一条起床。
- **解法:** 每条告警都可执行且紧急；其余的都放到 dashboard 上。
- **关联:** 靠 **symptom-based alerting** 和 SLO 来治；是 **log volume** 的近亲。

> **关于 alerting 的问题:** "这条告警触发的，是用户真正能感受到、并且需要人现在就处理的事——还是会让所有人学会无视 pager 的噪声？"

> 针对用户能感受到的症状告警，用 SLO 定义"够好"，并防范 alert fatigue——因为一个没人信任的告警，比没有告警还糟。

## 7. 用好它

Observability 是内建的，不是事后补上的。关键在于边做边埋点、保持信号干净，并把你的注意力花在那几件最能说明问题的事上。

### Instrument as You Build — 别等火烧起来之后

> 盖房子的时候就把烟雾探测器接好——而不是站在浓烟里，后悔自己没装。

加 observability 最糟的时机，就是在故障期间，那时你才发现系统什么都没告诉你。所以你要边做边把**埋点**（instrumentation）做进去：为新功能发出一个 metric，记下它的关键决策，确保一个请求能被一路 trace 过去。

趁代码还新鲜时加一点点埋点，能省下以后好几个小时的盲猜。把"我在生产环境里怎么看到它？"当作构建它的一部分，而不是事后才想起来的东西。

_Diagram: 上：边做边把信号内建进去——事故自己就有了答案。下：没有信号——事故期间你只能瞎猜。_

#### Instrument as You Build (内建，而非事后补上)

- **问题:** 你是在故障期间才发现信号里的缺口——太晚了。
- **思路:** 一个 metric、关键 logs 和 tracing，是每个新功能的一部分。
- **例子:** 一个新的支付功能上线时就带着错误 metric，记录它的决策，并把 trace ID 传下去。
- **代价:** 趁代码还新鲜时多做一点工作——换来的是以后省下好几个小时的瞎猜。
- **关联:** **black box** 的解药。

### Start Small and Grow — 从 golden signals 开始

> 新开店的店主起初只盯着那几个重要的数字——销售额、客流量、投诉——只有当出现具体问题时才加上更细的追踪。

你第一天不需要全面覆盖。从 **four golden signals** 和几处关键决策点上的少量 logs 开始，然后在真实事故暴露出**盲区**（blind spot）的地方，再补上细节。

每一次故障，都是一堂"你真希望当时记录了什么"的课——所以让你的 observability 顺着系统真正让你吃惊的地方生长，而不是一开始就把所有东西都埋上点。

_Diagram: 从 golden signals 开始，然后循环：事故暴露出盲区 → 你补上细节 → 覆盖范围增长。_

#### Start Small and Grow (从事故中扩大覆盖)

- **问题:** 一开始就给所有东西埋点，又慢、又贵、又吵。
- **思路:** 从 golden signals 开始；在一次真实故障让你吃惊的地方补上细节。
- **例子:** 一次事故显示，服务商的超时是看不见的——你就恰好在那里加一个 metric 和一条 log。
- **何时使用:** 任何服务，从第一天起。
- **关联:** 从 **four golden signals** 起步；把 **log volume** 控制住。

### 这些概念如何连在一起

> 飞机的仪表盘：十几个表盘，但全都关于同一次飞行——飞行员是把它们放在一起读的。

本课里的一切，都是同一块仪表盘的一部分。一个运行中的系统发出三种信号：**metrics** 发现，**traces** 定位，**logs** 解释。**Correlation ID** 把这三者绑到同一个请求上。Metrics 和 **golden signals** 喂给 **SLI 和 SLO**，而它们驱动 **symptom-based alerts**——少而精，所以没有 **alert fatigue**。而仪表盘本身会随着你**边做边埋点**，以及在真实事故之后补上细节而不断生长。

_Diagram: 系统发出三种信号；流程是 metric → trace → log；correlation ID 把它们粘在一起；metrics 喂给 SLO 和告警。_

#### 发布服务之前

- **它能告诉我什么**——在生产环境里——还是说它坏的时候就是个 black box？
- **Golden signals**——我有没有在追踪 latency、traffic、errors 和 saturation？
- **Logs**——有结构、有级别，并聚焦于重要的决策和故障吗？
- **Tracing**——我能跟着一个请求穿过它所经过的各个服务吗？
- **Correlation**——metrics、logs 和 traces 是否共享同一个 request ID？
- **告警和 SLO**——我是针对用户能感受到的东西呼叫人，并对照一个明确的目标吗？

#### 说明你观测得好的迹象

- 出问题时，系统会**告诉你该往哪看**，而不是让你瞎猜。
- 你按 **metric → trace → log** 走，从发现到定位再到解释。
- 一个共享的 **request ID** 把一起事故的信号串在一起。
- 你的**告警**针对面向用户的症状触发，而且人们依然信任它们。
- 你有明确的 **SLO**，并且是**边做边埋点**的，而不是在故障期间才补。

## 速查表：全部 22 个概念

### 基础

- **Flying by Instruments** (生产环境): 你没法暂停生产环境——只能看到系统发出的东西。
- **Observability** (o11y): 用系统的数据回答没预见到的问题。Monitoring 盯的是已知的东西。
- **Black Box** (不透明的系统): 一个什么都不发出的系统：出故障时，你只能猜。

### Logs

- **Log** (事件记录): 一个事件的带时间戳的记录。回答"究竟发生了什么"。
- **Structured Logging** (把 logs 当数据): 把事件记成数据字段——可以查询的 logs。
- **Log Levels** (DEBUG · INFO · WARN · ERROR): 一个重要程度标签：调查时调大音量，正常运行时调小。
- **Log Volume** (over-logging): logs 太多意味着噪声和账单。记 log 要有目的。

### Metrics

- **Metric** (时间序列): 随时间变化的一个数字。便宜、始终开着、显示趋势。
- **Counter vs Gauge** (两种形状): Counter 只增不减（读斜率）；gauge 上下摆动（读数值）。
- **Dashboard** (一眼看清 metrics): 关键 metrics 并排摆放：几秒内看清健康状况。
- **Four Golden Signals** (生命体征): Latency、traffic、errors、saturation——服务的生命体征。

### Traces

- **Trace** (请求路径): 一个请求穿过每个服务的路径。回答"在哪里"。
- **Span** (带计时的一步): trace 里被计时的一步；span 瀑布图显示时间花在了哪里。
- **Distributed Tracing** (跨服务的 tracing): 调试分布式系统："某个地方"变成"就是这里"。

### 合在一起

- **Three Pillars** (metrics、traces、logs): Metrics——有没有问题，traces——在哪里，logs——究竟是什么。
- **Notice → Locate → Explain** (metric → trace → log): 调查的流程，从宽泛到精确。
- **Correlation ID** (request ID、trace ID): 一个请求的所有信号共用一个 ID——完整的故事，一步到位。

### Alerting

- **Symptom-based Alerting** (为用户的痛感呼叫): 为用户能感受到的东西叫醒人，而不是为内部的小抽动。
- **SLI / SLO / SLA** (度量、目标、承诺): 度量、为它定的目标，以及对客户的合同承诺。
- **Alert Fatigue** (pager 噪声): 告警太多，就没人听。更少、更精准。

### 用好它

- **Instrument as You Build** (内建，而非事后补上): 信号是构建一个功能的一部分，而不是对火灾的反应。
- **Start Small and Grow** (从事故中生长): 从 golden signals 开始；在一次真实故障让你吃惊的地方补上细节。

> 好的 observability 是内建的：从一开始就有 golden signals，有结构的 logs，可追踪的请求，用 ID 关联起来，再加上几条针对真实 SLO、值得信任的告警。

速成课结束 · 7 章 · 22 个概念

接下来是练习：挑一个服务，把四个 golden signals 加到一个 dashboard 上，在它的关键决策处加一行 structured log，并确保一个请求带着一个你能跟踪的 ID。然后故意把它弄坏，试着只用它发出的东西去诊断。当你只凭信号就修好了某个问题、从头到尾没有挂上过 debugger 的那一刻，价值就落地了。但请把一个想法放在所有其他想法之上：在生产环境里，你靠仪表飞行。把系统建成能自己解释自己——logs 说明是什么，metrics 说明有多少，traces 说明在哪里——于是凌晨三点的故障，就成了一个你能回答的问题，而不是一个你只能瞎猜的谜。
