結論先講
Dashboard 不是越多圖表越好——是出事時 30 秒內能看出問題在哪。 放 50 個圖表等於沒放,因為你不知道要看哪個。Four Golden Signals(延遲、流量、錯誤率、飽和度)涵蓋 90% 的監控需求,剩下 10% 用業務指標補。
先搞懂 SLI / SLO / SLA
這三個詞常常被混用,但含義完全不同:
| 概念 | 意思 | 誰訂的 | 範例 |
|---|---|---|---|
| SLI(Service Level Indicator) | 衡量指標的具體定義 | 工程師 | P95 延遲、錯誤率、可用性 |
| SLO(Service Level Objective) | 指標的目標值 | 工程 + PM | P95 < 500ms、錯誤率 < 1% |
| SLA(Service Level Agreement) | 寫進合約的承諾 | 業務 + 法務 | 可用性 99.9%,違約賠償 |
SLO 不是隨便訂的——用壓測數據當 baseline。
我們在 第 05 篇 已經搭好 Grafana,也在壓測系列累積了大量數據。這些數據正是設 SLO 的最佳依據。
從壓測數據訂 SLO
壓測結果(100 VU,正常負載):
P95 延遲: 180ms
錯誤率: 0%
RPS: 450
壓測結果(500 VU,高負載):
P95 延遲: 520ms
錯誤率: 0.3%
RPS: 1200
→ SLO 建議:
P95 延遲: < 500ms(100 VU 的 2.7 倍,500 VU 剛好)
錯誤率: < 1%(500 VU 的 3 倍餘量)
可用性: 99.9%(月停機 < 43 分鐘)
不是拍腦袋說「P95 要 200ms 以下」——是用實際數據決定合理的目標,再加上 buffer。
Four Golden Signals
Google SRE Book 定義的四個核心指標,幾乎所有服務都適用:
1. Latency(延遲)
看什麼:請求的回應時間分佈
重點不是平均值——是百分位數
P50(中位數): 50ms → 「一般使用者的體驗」
P90: 120ms → 「大部分使用者的體驗」
P95: 280ms → 「SLO 通常看這個」
P99: 1200ms → 「最慢的 1% 使用者」
為什麼不看平均值? 因為平均值會被極端值拉高或拉低。P95 = 280ms 但平均 = 800ms,代表有少數請求非常慢——平均值看不出這個分佈。
Prometheus 查詢:
# P95 延遲
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# 按 service 拆分
histogram_quantile(0.95,
sum by (le, service) (
rate(http_request_duration_seconds_bucket[5m])
)
)2. Traffic(流量)
看什麼:每秒請求數(RPS)
# 總 RPS
sum(rate(http_requests_total[5m]))
# 按 endpoint 拆分
sum by (path) (rate(http_requests_total[5m]))流量指標的意義不是「現在多忙」——是「跟平常比正不正常」。突然掉 50% 可能代表前端壞了、DNS 出問題、或者上游服務掛了。
3. Errors(錯誤率)
看什麼:5xx 錯誤佔總請求的比例
# 錯誤率
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))注意:4xx 不算系統錯誤——那是 client 的問題。但如果 4xx 突然暴增,也值得注意(可能是 API 合約改了)。
4. Saturation(飽和度)
看什麼:資源使用率(CPU、記憶體、DB 連線池、磁碟 I/O)
# CPU 使用率
100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 記憶體使用率
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
/ node_memory_MemTotal_bytes * 100
# DB 連線池使用率
pg_stat_activity_count / pg_settings_max_connections * 100第 23 篇 的容量規劃告訴我們:瓶頸會從 AP → DB → 網路逐層轉移。Dashboard 上必須看到每一層的飽和度。
Dashboard 怎麼排版
Overview Dashboard(第一眼看這個)
┌─────────────────────────────────────────────────────┐
│ 🔴 SLO Status: P95 延遲 ✅ | 錯誤率 ✅ | 可用性 ✅ │
├──────────────┬──────────────┬───────────────────────┤
│ 總 RPS │ P95 延遲 │ 錯誤率 │
│ (Stat Panel) │ (Stat Panel) │ (Stat Panel) │
├──────────────┴──────────────┴───────────────────────┤
│ RPS 趨勢(按服務拆分) Time Series │
├─────────────────────────────────────────────────────┤
│ P95 延遲趨勢(按服務拆分) Time Series │
├─────────────────────────────────────────────────────┤
│ 錯誤率趨勢 Time Series │
├────────────────────────┬────────────────────────────┤
│ CPU 使用率 │ 記憶體使用率 │
├────────────────────────┼────────────────────────────┤
│ DB 連線池使用率 │ 磁碟 I/O │
└────────────────────────┴────────────────────────────┘
最上面一排是 Stat Panel:紅綠燈,一眼看出有沒有問題。下面是趨勢圖,看是在惡化還是穩定。
Service Detail Dashboard(點進去看細節)
每個服務一個:
- 該服務的 RPS / P95 / 錯誤率
- 該服務的 endpoint breakdown(哪個 API 最慢)
- 該服務的 CPU / 記憶體
- 該服務的 DB 查詢時間(如果有)
- 最近的 Error log(直接嵌 Loki query)
業務 Dashboard
技術指標之外,加上業務指標:
| 指標 | 為什麼重要 |
|---|---|
| 每分鐘訂單數 | 掉了 = 用戶下不了單 |
| 付款成功率 | 掉了 = 金流有問題 |
| 註冊轉換率 | 掉了 = 註冊流程壞了 |
| API 回應時間(按用戶層級) | VIP 用戶是否被影響 |
告警規則怎麼設
基本原則
- 告警要 actionable:收到告警後,你能做什麼?如果答不出來,就不該告警
- 分級:不是所有告警都要半夜叫人起來
- 用 SLO 設閾值,不要用直覺
告警分級
| 等級 | 條件 | 通知方式 |
|---|---|---|
| P0(緊急) | SLO 已違反:錯誤率 > 5% 持續 5 分鐘 | Slack + 電話 |
| P1(高) | SLO 快違反:P95 > 800ms 持續 10 分鐘 | Slack |
| P2(中) | 資源告警:CPU > 80% 持續 15 分鐘 | Slack(上班時間) |
| P3(低) | 趨勢異常:流量比昨天同時段低 50% | Dashboard 標記 |
Prometheus Alerting Rules 範例
groups:
- name: slo-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "錯誤率超過 5%(目前 {{ $value | humanizePercentage }})"
- alert: HighLatency
expr: |
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "P95 延遲超過 800ms(目前 {{ $value | humanizeDuration }})"
- alert: HighCPU
expr: |
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 15m
labels:
severity: warning
annotations:
summary: "CPU 使用率超過 80%(目前 {{ $value }}%)"壓測數據 vs 生產數據
壓測時你得到的是「理想狀況下的效能上限」。生產環境會更複雜:
| 差異 | 壓測 | 生產 |
|---|---|---|
| 流量模式 | 均勻 | 有尖峰(午餐時間、促銷) |
| 資料量 | 測試資料(少) | 真實資料(多且亂) |
| 外部依賴 | Mock 或本地 | 真實的第三方 API(會慢、會掛) |
| 網路 | 內網 | 跨區域、用戶端網路品質不一 |
壓測數據是 SLO 的起點,不是終點。 上線後要根據真實流量調整 SLO。
我的 Dashboard 演進
第一版:什麼都放(30 個圖表)
→ 出事時反而不知道看哪個
第二版:只放 Four Golden Signals
→ 知道「系統壞了」但不知道「哪裡壞」
第三版:Overview + Service Detail 兩層
→ Overview 看全局,點進去看細節
→ 加上 SLO 紅綠燈
第四版:加上業務指標
→ 技術指標正常但訂單數掉了 → 發現是前端按鈕壞了
常見的坑
1. Alert Fatigue(告警疲勞)
設太多告警 → 每天收 50 封 → 沒人看 → 真正出事時也沒人反應。
解法:每個告警都問自己「收到這個我會做什麼?」答不出來就刪掉。
2. 只看 Dashboard 不看趨勢
「CPU 60% 正常啊」——但上週同一時間是 30%。趨勢比絕對值重要。 設一個「Week-over-Week」面板比較同一指標。
3. 沒有 Runbook
告警響了,但新人不知道要做什麼。每個 P0 / P1 告警都要配一份 Runbook:
## Alert: HighErrorRate
### 可能原因
1. DB 連線池滿 → 檢查 pg_stat_activity
2. 上游服務掛了 → 檢查 dependency dashboard
3. 最近有部署 → 檢查最近 30 分鐘的 deploy history
### 處理步驟
1. 確認影響範圍(哪些 endpoint、多少用戶)
2. 如果是最近部署造成 → rollback
3. 如果是 DB → 擴連線池 / kill long queries下一篇
資料一致性(一):Saga Pattern 取代分散式 Transaction — 可觀測性搞定了,你知道系統「哪裡壞了」。但微服務最棘手的問題不是效能——是資料一致性。「訂單成立但沒扣庫存」這種事在單體不可能發生,在微服務卻天天上演。
本系列文章
完整 68 篇目錄見 系列首頁
← 上一篇:可觀測性(二):集中 Log 不再拼湊三份 log → 下一篇:資料一致性(一):Saga Pattern 取代分散式 Transaction