結論先講

跨服務 debug 的核心是 Trace ID。 用戶回報問題時,從前端的錯誤回應拿到 Trace ID → 在 Jaeger 查到完整的呼叫鏈 → 找到出錯的那個 span → 去 Loki 用同一個 Trace ID 搜 log → 看到 error message + stack trace → 定位問題。沒有 Trace ID,你只能在 5 個服務的 log 裡面大海撈針。


沒有 SOP 的 Debug 流程

1. 用戶回報:「下單失敗」
2. 你:先看 Order Service 的 log → 沒看到 error
3. 你:也許是 Payment Service?→ 看 Payment log → 也沒有
4. 你:等等,是不是 User Service 的驗證掛了?→ 看 User log
5. 你:找到一個 error!但時間對不上...
6. 你:ssh 到另一台機器看 log → 又一個 error,哪個才是?
7. 2 小時後:終於找到是 Inventory Service 庫存不足回了 400,
   但 Order Service 沒有正確處理這個 400...

有 SOP 的 Debug 流程

Step 1:拿到 Trace ID

用戶的錯誤回應:
{
  "error": "Order creation failed",
  "traceId": "abc123def456"      ← 這個就是你的線索
}

如果前端沒有回傳 traceId:
  → 從用戶的操作時間 + user ID 去 log 裡找
  → 這就是為什麼 [[micro-service/44-observability-logging|第 44 篇]] 說結構化 log 很重要

Step 2:在 Jaeger 查呼叫鏈

打開 Jaeger UI,貼上 Trace ID:

Trace: abc123def456
Duration: 342ms

API Gateway        ─────────────────────────────── 342ms
  └─ Order Service ────────────────────────── 338ms
       ├─ User Service (verify token) ──── 12ms ✅
       ├─ Inventory Service (check)  ──── 25ms ✅
       ├─ Inventory Service (deduct) ──── 45ms ❌ HTTP 409
       └─ (後面的 Payment Service 沒有被呼叫)

一眼看到:Inventory Service 的 deduct 回了 409 Conflict。

如同 第 43 篇 介紹的分散式追蹤,Jaeger 讓你看到整個請求在各服務間的流轉。

Step 3:在 Loki 查詳細 Log

用同一個 Trace ID 去 Loki 搜:

{service="inventory-service"} |= "abc123def456"

結果:

{
  "timestamp": "2026-04-15T10:23:45.123Z",
  "level": "error",
  "service": "inventory-service",
  "traceId": "abc123def456",
  "message": "Insufficient stock for SKU-12345: requested 2, available 0",
  "sku": "SKU-12345",
  "requested": 2,
  "available": 0
}

問題定位完成:SKU-12345 庫存不足,但 Order Service 沒有正確處理 409 回應,導致用戶看到 generic 的「下單失敗」而不是「商品已售完」。

Step 4:確認 Metrics

打開 Grafana,看 Inventory Service 的 dashboard(如同 第 45 篇 建的那種):

409 的數量在過去 1 小時暴增 → 某個熱門商品被搶購
→ 不是 bug,是商品真的賣完了
→ 但 Order Service 的 error handling 需要修

Step 5:修復

// Order Service — 修復前
try {
  await inventoryService.deduct(sku, quantity);
} catch (err) {
  throw new Error('Order creation failed');  // ← generic error
}
 
// Order Service — 修復後
try {
  await inventoryService.deduct(sku, quantity);
} catch (err) {
  if (err.response?.status === 409) {
    throw new OutOfStockError(sku);  // ← 明確的錯誤
  }
  throw err;
}

Correlation ID 的設計

Trace ID 是 tracing 系統自動產生的。但你可能還需要一個 Correlation ID——從最源頭(API Gateway 或前端)就塞入,一路傳遞:

前端發請求:
  POST /api/orders
  X-Request-ID: req_abc123     ← 前端產生的
  X-Correlation-ID: session_xyz ← 用戶的 session ID

API Gateway 收到:
  加上 X-Trace-ID: trace_def456  ← tracing 系統產生的
  轉發給 Order Service

Order Service:
  log 裡同時記錄三個 ID:
  {
    "requestId": "req_abc123",
    "correlationId": "session_xyz",
    "traceId": "trace_def456",
    "message": "Creating order..."
  }

有了這三個 ID,你可以:

  • traceId 追蹤單一請求的完整呼叫鏈
  • requestId 找到前端對應的那次請求
  • correlationId 找到同一個用戶 session 的所有操作

實作:自動傳遞 Trace ID

// Express middleware:自動從 header 拿 trace ID,沒有就產生一個
const { v4: uuid } = require('uuid');
 
function traceMiddleware(req, res, next) {
  req.traceId = req.headers['x-trace-id'] || uuid();
  res.setHeader('x-trace-id', req.traceId);
 
  // 之後呼叫其他服務時也帶上
  req.serviceHeaders = {
    'x-trace-id': req.traceId,
    'x-request-id': req.headers['x-request-id'] || uuid(),
  };
 
  next();
}
 
// 呼叫 Payment Service 時帶上 trace ID
async function callPaymentService(orderData, traceHeaders) {
  return axios.post('http://payment-service/payments', orderData, {
    headers: traceHeaders,   // ← trace ID 跟著傳過去
  });
}

Debug SOP 總結

觸發條件:用戶回報問題 / 告警通知

Step 1: 拿到 Trace ID
  → 從錯誤回應、log、或用 user_id + 時間範圍搜尋

Step 2: Jaeger 查呼叫鏈(30 秒)
  → 找到出錯的 service 和 span
  → 確認是 timeout、4xx、5xx、還是整個沒被呼叫

Step 3: Loki 查詳細 log(1 分鐘)
  → 用 trace ID 過濾,找到完整 error message
  → 看 stack trace 定位到程式碼

Step 4: Grafana 看 metrics(1 分鐘)
  → 這是個別案例還是大規模問題?
  → error rate 有沒有上升?latency 有沒有異常?

Step 5: 判斷 + 修復
  → 個別案例 → 資料問題,修資料
  → 大規模問題 → 程式 bug,hotfix
  → 效能問題 → 擴容或優化

總時間:5-15 分鐘(vs 沒有 SOP 的 1-3 小時)

團隊怎麼落地這個 SOP

  1. 寫成 Runbook:放在 wiki 裡,新人第一天就讀
  2. On-call rotation:每週輪一個人負責處理告警,強迫每個人都學會用這套流程
  3. Postmortem:每次大事故後檢討——「如果我們早 10 分鐘發現,損失會少多少?」
  4. 定期演練:故意在 staging 注入錯誤,讓團隊練習用 SOP 找問題

下一篇

成本計算 — Debug 的時間成本說完了,來算真正的雲端成本。你的 Go 服務跟 Django 服務跑同樣的 500 用戶,需要的 CPU 差多少?每個月的帳單差多少?


本系列文章

完整 68 篇目錄見 系列首頁

← 上一篇:開發者體驗(一):本地跑 5 個微服務吃掉所有 RAM → 下一篇:每個 Request 多少錢:從壓測數據算雲端成本