主題
0.2 · 衡量指標素養
TL;DR · 本章重點
- 吞吐量(Throughput)與延遲(Latency)是兩個不同的軸:前者問「每秒處理多少」、後者問「單一請求等多久」。
- 用平均延遲彙報效能是錯的:平均被快速請求拉低、看不到尾端使用者的痛苦。要看 P50 / P95 / P99 / P999 分布。
- 尾端延遲(tail latency)會被「扇出」(fan-out — 一個請求觸發 N 個下游、要等全部回應)放大:一個請求若打到 100 個後端各回應一次,整體延遲 = 「100 個之中最慢那個」的延遲。
- SLA(對外合約)vs SLO(對內目標):違反 SLA 賠錢、違反 SLO 警報。典型寫法:「99.9% 的請求在過去 5 分鐘 P99 < 200ms」。
- Amazon 的觀察:延遲最差的請求往往來自帳號資料、消費量最大的高價值客戶 —— 所以把 P999 列為內部 SLO。
為什麼這章是 Ch1 的前置?
DDIA 第 1 章從第三節開始就直接用「QPS」「P99」「fan-out」「SLA」這些詞,沒有給定義就拿來計算 Twitter 的負載模型。這章先把這些詞講清楚。
1) Throughput vs Latency 是兩個正交維度
最常見的混淆:
「我們系統很快」
「快」是什麼意思?
兩者沒有直接關係。一個極端例子:
| 系統 | Throughput | Latency |
|---|---|---|
| 銀行夜間批次:跑 1 億筆交易 | 極高(10⁸/晚) | 極高(單筆 ~8 小時) |
| 心跳監控:每 5 秒一個請求 | 極低(0.2 req/s) | 極低(10ms) |
DDIA Ch1 的 Twitter 例子裡,「4.6k req/s 發推文」是 throughput,「家庭時間軸應該在 X ms 內回應」是 latency——兩個指標要分別設定 SLO。
一句話記住
Throughput 是「容量」問題;Latency 是「體驗」問題。
2) 為什麼平均延遲是個騙人指標
假設你的服務 10 個請求的延遲是:
10, 12, 14, 11, 13, 10, 12, 11, 14, 2000 (ms)1
- 平均 = 211 ms
- 中位數(P50)= 12 ms
如果你向老闆彙報「平均延遲 211 ms」,他會以為系統有嚴重問題。 如果你彙報「中位數 12 ms」,他會以為一切正常。
兩個彙報都騙人。 真相是:9 個使用者體驗超好(10–14 ms),但有 1 個等了 2 秒——那個人可能就是你今天會接到客訴電話的對象。
用 百分位數 看分布
把全部請求按延遲排序,然後問:
- P50(中位數):把全部請求排序後,第 50% 名那個的延遲。典型使用者的體驗。
- P95:第 95% 名。前 5% 慢的人有多慢。
- P99:第 99% 名。前 1% 慢的人有多慢。
- P999:第 99.9% 名。前 0.1% 慢的人有多慢——通常是你的高價值客戶(資料多、操作複雜)。
延遲分布(按 P99 視角看):
▲ P99 = 2000ms
P50 = 12ms │
│ │
▼ │
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
↑ ↑
9 個典型使用者 1 個倒楣使用者1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Amazon 的觀察(DDIA Ch1)
延遲最差的請求往往來自帳號資料最多、購買也最多的高價值客戶——他們的購物車有更多商品、推薦演算法要計算更多東西。
所以 Amazon 把 P999 列為內部 SLO——不能讓這群最賺錢的客戶體驗惡化。
3) 尾端延遲會被 fan-out 放大
這是 DDIA Ch1 反覆強調、但很多人第一次讀會卡住的概念。
場景
你的首頁要顯示 100 個推薦商品。後端架構:
Client
│
▼
API Gateway
│
├──→ 推薦服務 A
├──→ 推薦服務 B
├──→ ... 共 100 個下游
└──→ 推薦服務 X1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
每個下游 P99 = 200ms、P50 = 20ms。 問題:整體頁面延遲是多少?
直覺錯誤
很多人會回答「P99 = 200ms」。錯。
頁面要等全部 100 個下游都回應才能渲染(這叫 fan-out)。整體延遲 = 100 個延遲中的最大值。
機率計算
每個下游有 1% 機率落在 P99 區(≥200ms)。100 個之中至少 1 個落在 P99 區的機率:
P(至少一個慢) = 1 - P(全部都快)
= 1 - (0.99)^100
= 1 - 0.366
≈ 63%1
2
3
4
2
3
4
也就是說:每 3 次頁面請求,就有 2 次會卡在 200ms 以上。
這個 63% 假設下游延遲彼此獨立——實務上常被打破
(1 - 0.01)^100 的計算前提是「100 個下游的延遲是 100 次獨立伯努利試驗」。實務上常違反:
- 共用瓶頸:100 個下游共用一台 DB / Redis / 訊息中介 → GC pause、CPU spike、網路擁塞時一起變慢(正相關)
- 共用節點:跨服務但部署在同一物理機 → host noise、kernel scheduler 共用
- 負載相關:尖峰時段所有下游壓力都大 → P99 比例本身可能超過 1%
正相關時實際慢請求機率會比 63% 更高(極端情況:100% 正相關 → 等於單一服務的 P99 = 1%,回到「漂亮的 1%」)。負相關罕見,但理論上會把 63% 拉低。
DDIA 用 63% 是要建立直覺——「fan-out 把單一服務的尾巴放大成全域問題」這件事在現實中只會比理論模型更嚴重,不會更輕。
結論
單一服務 P99 看起來很漂亮(1% 慢),但 fan-out 100 個之後,幾乎每個使用者都會被 P99 後端影響。
這叫 tail latency amplification。
要解決就要做:
- 降低 P99(不是 P50)
- 減少 fan-out 數量
- 對慢的下游做 hedged request(同時打兩個、用先回的)
4) SLA 與 SLO 是兩個東西
實務上極常混用,但意義不同:
| 名詞 | 全名 | 對誰 | 違反後果 |
|---|---|---|---|
| SLA | Service Level Agreement | 對外(合約) | 賠款、退費、終止合約 |
| SLO | Service Level Objective | 對內(團隊目標) | 觸發 alert、暫停部署 |
| SLI | Service Level Indicator | 量測值本身 | 一個數字,例如「目前 P99 = 178ms」 |
典型寫法
過去 5 分鐘內,99.9% 的
GET /api/v1/users/:id請求 P99 < 200ms
拆解:
- SLI:P99 延遲(一個數字)
- SLO:< 200ms(目標閾值)
- 可靠度:99.9% 的時間窗口滿足上述條件(剩 0.1% 叫 error budget)
Error Budget 的妙用
99.9% = 一個月可以有 43 分鐘違反 SLO。
- 已經用掉 40 分鐘?凍結部署,先穩定再說。
- 還沒用掉?放心做激進實驗,反正有 budget。
這把「可靠性」從哲學問題變成可量化的權衡——Google SRE 書的核心觀念,DDIA Ch1 也提到。
5) 怎麼正確量延遲
這節是 DDIA 沒講但實務坑很多。
陷阱 1:分位數無法用算術平均合併
10 台機器,每台 P99 都是 100ms。整體 P99 ≠ 100ms——不能用算術平均、不能取最大、不能取加總。
正確做法是把所有 raw 樣本合起來重新排序取 P99;不過實際上沒人會跨機器搬 raw 樣本,工程上用可合併的分位數估計資料結構:
- HdrHistogram:固定誤差、高效能、Java/Go 都有實作
- t-digest:高分位(P99 / P999)精準度更好——Prometheus / Datadog / Honeycomb / DDSketch 都建立在這類思路上
這也是為什麼 Prometheus 的 histogram_quantile() 算的是 bucket 推估、而不是真實 P99——理解這個誤差來源、才不會被「Grafana 顯示 P99 = 178ms」誤導。
陷阱 2:Coordinated Omission
如果你的 load generator 用「每秒發 100 個請求」的方式跑,遇到服務慢下來時,你會少發請求——這讓你的延遲統計漏掉了最慢的時段。
正確做法:用「每 10ms 發一個請求,不管前一個有沒有回應」的開放式負載。Gil Tene 的演講 How NOT to Measure Latency 是這個主題的經典。
陷阱 3:在哪一層量?
Client → CDN → LB → API → Service → DB1
- 在 API 那一層量:只看到應用層延遲,沒看到網路 RTT。
- 在 Client 那一層量:看到端到端延遲,但混雜了客戶網路抖動。
實務上兩邊都量:API 層用 P99 設 SLO,Client 端用 RUM(Real User Monitoring)看真實體驗。
6) 與 DDIA Ch1 的對應
讀完這章後,回到 Ch1,你會發現:
| Ch1 段落 | 對應這章的哪個概念 |
|---|---|
| 「Twitter 4.6k req/s vs 300k req/s」 | Throughput(第 1 節) |
| 「家庭時間軸的 fan-out」 | Fan-out 與 tail latency 放大(第 3 節) |
| 「P50 / P95 / P999」 | Percentile(第 2 節) |
| 「Amazon 把 P999 列為 SLO」 | SLA / SLO 區分(第 4 節) |
| 「設計目標:Reliability、Scalability、Maintainability」 | 這三個都需要先有量化指標才能討論 |
想更深入?
| 資源 | 內容 |
|---|---|
| Google SRE Book Ch4: Service Level Objectives | SLI / SLO / SLA 的權威定義 |
| Gil Tene: How NOT to Measure Latency (YouTube) | 1 小時,量延遲的所有陷阱 |
| HdrHistogram | 正確聚合 percentile 的開源工具 |
| Brendan Gregg: USE Method | Utilization / Saturation / Errors,效能分析框架 |
章末測驗
章末測驗 · p0-metrics
Q1. 應用 你的服務 1000 個請求延遲分布如下:999 個是 10ms、1 個是 5000ms。請問平均延遲與 P99 延遲各是多少?
Q2. 應用 某服務的 P99 延遲是 100ms。客戶端要 fan-out 給 50 個這樣的後端、等全部回應才能渲染頁面。整體頁面延遲至少落在 100ms 以上的機率最接近?
Q3. 基礎 下列哪個敘述最準確區分 SLA 與 SLO?
Q4. ◆ 面試 你跑 load test 量延遲,發現使用 wrk2 結果和 wrk 差很多——wrk2 報的 P99 高很多。最可能的原因是?
Q5. ◆ 面試 為什麼 Amazon 把 P999(而非 P99)列為內部 SLO?
The Next Chapter
0.3 SQL 與關聯模型速覽
也可以直接跳到 Ch1 可靠、可擴展、可維護,回頭遇到不熟的詞再回來查。
Continue Reading→