iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0

茶室的投影螢幕亮著,滿是密密麻麻的折線圖。

洛基走進來時,大師正背對著門口,雙手抱胸盯著螢幕。有些線條平穩,有些劇烈波動,還有幾條已經變成警告的紅色。

「兩小時前系統上線了,」大師頭也不回,「現在健康嗎?」

洛基走近螢幕,看到一些熟悉的指標名稱:ConsumedReadCapacityUnitsWriteThrottleEvents...

「呃...有些紅色的線,」洛基不太確定,「應該有問題?」

大師轉過身:「如果我問你:『系統是否健康』,你會怎麼回答?」

洛基想了想:「看錯誤日誌?如果沒有錯誤,應該就正常。」

「當你看到錯誤日誌時,」大師在白板上畫了一條時間軸,「使用者已經受影響了。」

時間軸:

10:00  系統正常
10:15  容量使用率 85%(沒注意到)
10:20  開始限流(使用者受影響)
10:25  大量錯誤(開始看日誌)← 你在這裡才發現問題
10:30  手動擴容(問題已持續 10 分鐘)

洛基看著時間軸,理解了問題的嚴重性。

大師繼續:「監控的目的,不是『發現問題』,而是『在問題發生前發現徵兆』。」

他在白板上寫下一個詞:「可觀測性(Observability)」


為什麼需要監控?

洛基坐下來,翻開筆記本。

大師問:「前面二十七天,我們學了完整的 DynamoDB 技術——設計、查詢、索引、Streams。為什麼現在要學監控?」

洛基思考:「因為...上線後要知道系統狀況?」

「更具體一點,」大師引導,「如果沒有監控,會發生什麼?」

洛基想到剛才的時間軸:「問題發生了,但我不知道。等使用者回報時,已經影響很多人了。」

「還有呢?」

「即使知道有問題,」洛基補充,「也不知道『為什麼』有問題。是容量不夠?還是程式碼錯誤?」

大師點頭:「這就是監控的兩個核心價值。」

他在白板上列出:

監控的核心價值:

1. 提前預警
   - 在問題影響使用者『前』發現徵兆
   - 容量使用率 80% → 告警 → 擴容 → 避免限流

2. 快速診斷
   - 問題發生時,迅速定位根本原因
   - 不是「猜測」問題,而是「看數據」找答案

洛基看著這兩點,突然理解為什麼大師一開始問「系統是否健康」——沒有監控,根本無法回答這個問題。


DynamoDB 的關鍵監控指標

「DynamoDB 有哪些指標需要監控?」洛基問。

大師切換投影螢幕,顯示 CloudWatch 的指標列表,密密麻麻數十個指標。

「太多了,」大師說,「我們聚焦最關鍵的五類。」

他在白板上分類:

類別 1:容量消耗

指標名稱 說明 為何重要 告警閾值
ConsumedReadCapacityUnits 實際消耗的 RCU 知道讀取流量有多大 > 配置容量的 80%
ConsumedWriteCapacityUnits 實際消耗的 WCU 知道寫入流量有多大 > 配置容量的 80%

洛基皺眉:「為什麼 80% 就要告警?不是還有 20% 的餘裕嗎?」

「因為兩個原因,」大師解釋,「第一,流量可能突然增加。第二,Auto Scaling 需要時間反應——從偵測到擴容完成,可能需要 3-5 分鐘。」

「所以要提前告警,」洛基理解了,「留時間緩衝。」

類別 2:限流事件

指標名稱 說明 影響/為何重要 告警閾值/可能原因
ReadThrottleEvents 讀取被限流的次數 使用者請求被拒絕 > 0(任何限流都應該告警)
WriteThrottleEvents 寫入被限流的次數 資料寫入失敗 容量不足、熱分區、Burst capacity 耗盡

「限流是最嚴重的問題,」大師強調,「使用者直接受影響。所以閾值設為 0——只要發生一次,就要立即告警。」

類別 3:錯誤率

洛基想起第 16 天的錯誤處理:「UserErrorsSystemErrors?」

「對,」大師說,「但含義不同。」

指標名稱 說明 常見原因/影響 處理方式
UserErrors 客戶端錯誤(4xx) ValidationException(參數錯誤)、ConditionalCheckFailedException(條件不符)、ResourceNotFoundException(表不存在) 通常是程式碼邏輯問題,需要檢查應用層
SystemErrors DynamoDB 內部錯誤(5xx) AWS 服務問題 自動重試,如果持續發生需要聯繫 AWS

UserErrors 高,通常是我們的程式碼有問題,」洛基總結,「SystemErrors 高,是 AWS 那邊有問題。」

類別 4:延遲

大師展示延遲指標:

指標名稱 說明 正常範圍(p99) 告警條件
SuccessfulRequestLatency 成功請求的延遲(毫秒) GetItem: < 10ms / Query: < 20ms / Scan: 依資料量而定較高 p99 延遲持續超過正常範圍

「為什麼要看 p99 而不是平均值?」洛基問。

「因為平均值會掩蓋問題,」大師在白板上舉例:

假設 100 個請求:
- 99 個請求:5ms
- 1 個請求:500ms

平均值 = (99×5 + 500) / 100 = 9.95ms ← 看起來正常
p99 = 500ms ← 發現有 1% 的請求異常慢

洛基理解了:「平均值被大多數正常請求拉平了,但 p99 能抓出異常值。」


設定告警:讓系統主動通知你

「這些指標,」洛基看著白板上的列表,「我要一直盯著看嗎?」

大師笑了:「當然不是。這就是為什麼要設定告警。」

他展示告警設定:

告警名稱 監控指標 閾值 評估週期 為什麼這樣設定
讀取容量告警 ConsumedReadCapacityUnits > 80% 連續 2 個 5 分鐘 留緩衝給 Auto Scaling
限流告警 ReadThrottleEvents > 0 1 個 5 分鐘 任何限流都要立即處理
系統錯誤告警 SystemErrors > 5 1 個 5 分鐘 偶發可忍受,持續則嚴重
延遲告警 SuccessfulRequestLatency (p99) > 50ms 連續 3 個 5 分鐘 避免誤報,確認趨勢

洛基注意到「連續 2 個」、「連續 3 個」的設定:「為什麼不是一次超過就告警?」

「避免誤報,」大師解釋,「流量可能短暫突增,導致某一分鐘超過閾值,但隨即恢復正常。連續多次超過,才代表真正的問題。」

「但限流是『1 個 5 分鐘』,」洛基指出。

「因為限流影響使用者,」大師說,「寧可誤報,也不要錯過。」


Contributor Insights:找出熱分區

大師切換螢幕,顯示一個新的圖表。

「假設,」他說,「CloudWatch 告警顯示 ReadThrottleEvents 發生了,但你檢查容量使用率,只有 60%。」

洛基皺眉:「60% 就限流?不應該啊...」

他突然想起:「等等,熱分區?」

「正確,」大師說,「總容量使用率低,但某個特定的 Partition Key 流量過大,導致該分區限流。」

「那要怎麼找出是哪個 PK?」洛基問。

大師指向螢幕:「Contributor Insights。」

螢幕上顯示:

Top Contributors (2210-04-20 10:00-11:00)

Partition Key                      | 請求次數 | 消耗容量 | 限流次數
----------------------------------|---------|---------|----------
EVENT#MARS-SCIENCE-CONF-001       | 8,500   | 850 RCU | 120
EVENT#REGULAR-MEETING-123         | 500     | 50 RCU  | 0
EVENT#WORKSHOP-AI-045             | 400     | 40 RCU  | 0
...

洛基看著第一行:「火星科學大會...佔了 85% 的請求,而且被限流 120 次!」

「這就是熱分區,」大師說,「單一 PK 流量過大。其他活動的請求都正常,但這個活動的請求被限流了。」

「所以總使用率 60%,但熱分區已經超載,」洛基理解了,「Contributor Insights 能精確找出是哪個 PK 造成問題。」

大師點頭:「找到熱 PK 後,才能決定解決方案——增加容量、分散 PK、加快取...這個我們之後再說。」


實戰診斷:限流問題

「現在,」大師清空白板,「模擬一個實際案例。」

突然,Hippo 的聲音響起:「警告:系統偵測到 WriteThrottleEvents 異常。當前告警數:1。」

投影螢幕自動切換,顯示告警詳情。

洛基愣了一下,然後意識到:「這是即時告警?」

「對,」大師說,「Hippo 整合了 CloudWatch 告警。當指標超過閾值,會主動通知。」

螢幕上顯示:

場景:星際活動報名系統

症狀:
- CloudWatch 告警:WriteThrottleEvents > 0
- 使用者回報:報名時出現「請稍後再試」錯誤

你要怎麼診斷?

洛基拿出筆記本,開始系統化思考。

「首先,」他說,「檢查 ConsumedWriteCapacityUnits vs ProvisionedWriteCapacityUnits。」

大師在白板上寫下數據:

ConsumedWriteCapacityUnits: 800 WCU
ProvisionedWriteCapacityUnits: 1000 WCU
使用率:80%

「80%...正好在告警閾值,」洛基分析,「但還沒超過配置容量。如果是容量不足,應該超過 100%。」

「繼續,」大師鼓勵。

洛基想到剛才學的:「會不會是熱分區?查看 Contributor Insights。」

「Hippo,」大師說,「顯示 Contributor Insights 數據。」

「正在查詢...」Hippo 回應,螢幕切換:

Top Contributors (寫入)

Partition Key                  | 寫入次數 | 限流次數
------------------------------|---------|----------
REGISTRATION#EVENT#HOT-CONF   | 3,200   | 85
REGISTRATION#EVENT#NORMAL-001 | 100     | 0
REGISTRATION#EVENT#NORMAL-002 | 90      | 0

「分析完成,」Hippo 補充,「HOT-CONF 佔總寫入流量 91.4%,建議檢查 PK 設計。」

洛基眼睛一亮:「HOT-CONF 這個活動的報名請求,佔了大部分寫入,而且被限流 85 次!」

「原因是什麼?」大師問。

洛基回想 PK 設計:「等等...REGISTRATION#EVENT#HOT-CONF 這個 PK,所有報名同一個活動的請求,都寫入同一個 Partition?」

「對,」大師說,「這是設計問題。熱門活動的報名請求,全部集中到同一個分區。」

洛基立刻想到解決方案:「應該用 USER#{userId} 當 PK,而不是 REGISTRATION#EVENT#{eventId}。這樣寫入會分散到各個使用者的分區。」

「完全正確,」大師滿意地點頭,「這個案例展示了診斷的完整流程。」

他在白板上總結:

診斷流程:

1. 發現症狀(告警或使用者回報)
   ↓
2. 檢查總體容量使用率
   ↓
3. 如果使用率不高但仍限流 → 檢查 Contributor Insights
   ↓
4. 找出熱 PK
   ↓
5. 分析為何該 PK 會熱(設計問題?突發流量?)
   ↓
6. 決定解決方案(重新設計 / 增加容量 / 加快取)

實戰診斷:高延遲問題

「再來一個案例,」大師換了場景。

場景:活動查詢功能

症狀:
- CloudWatch 告警:SuccessfulRequestLatency (p99) > 200ms
- 使用者回報:列表載入很慢

診斷?

洛基開始系統化思考。

「首先,」他說,「確認是哪種操作慢了——GetItem、Query、還是 Scan?」

大師給出數據:

操作分解:
- GetItem 平均延遲:5ms
- Query 平均延遲:15ms
- Scan 平均延遲:350ms ← 異常

Scan 的使用量:佔總請求的 15%

洛基馬上發現問題:「有人在用 Scan!而且 p99 達 350ms。」

「為什麼會有 Scan?」大師問。

洛基想了想:「可能是...某個查詢沒有使用正確的索引?」

大師展示應用程式碼:

// 問題程式碼

async function searchEventsByTopic(topic) {
  // ❌ 錯誤:沒有為 topic 建立 GSI,所以用 Scan
  const result = await docClient.scan({
    TableName: "Events",
    FilterExpression: "topic = :topic",
    ExpressionAttributeValues: { ":topic": topic },
  });

  return result.Items;
}

洛基看出問題:「應該為 topic 建立 GSI,用 Query 而不是 Scan。」

「對,」大師說,「這是常見錯誤——沒有為查詢需求建立對應的索引,只好用 Scan,導致效能低落。Hippo 請準備一份高延犀診斷清單。」

白板立即顯示:

https://ithelp.ithome.com.tw/upload/images/20251014/20178813WxUQ1VGBQQ.jpg

監控儀表板:全貌一覽

洛基看著白板上密密麻麻的診斷流程和檢查清單。

「這些指標和告警,」他問,「實際運作時,我要怎麼快速掌握系統狀況?」

大師切換螢幕,顯示一個整合儀表板:

DynamoDB 健康儀表板

┌─────────────────────────────────────┐
│ 容量使用率                           │
│ ████████░░ 82% (告警)               │
│                                     │
│ 限流事件(過去 1 小時)              │
│ ReadThrottle: 12 次 ⚠️              │
│ WriteThrottle: 0 次 ✓               │
│                                     │
│ 錯誤率(過去 1 小時)                │
│ UserErrors: 45 次                   │
│ SystemErrors: 0 次 ✓                │
│                                     │
│ 延遲 (p99)                          │
│ GetItem: 8ms ✓                      │
│ Query: 22ms ⚠️                      │
│ Scan: 420ms ⚠️                      │
│                                     │
│ Top 熱門 PK (Contributor Insights)  │
│ 1. EVENT#MARS-CONF  ████████ 65%   │
│ 2. EVENT#WORKSHOP   ██ 15%         │
│ 3. EVENT#MEETUP     ██ 12%         │
└─────────────────────────────────────┘

洛基看著儀表板:「一眼就能看出問題——容量 82% 接近告警、有讀取限流、Query 和 Scan 延遲偏高、火星大會佔了 65% 流量。」

「這就是可觀測性的價值,」大師說,「不是等問題發生,而是主動掌握系統健康狀況。」


洛基闔上筆記本。

從進門時看到滿是紅線的儀表板,到現在能夠系統化診斷問題,他經歷了一個思維轉變。

以前,他覺得「會寫程式、會設計表結構」就夠了。現在他理解,技術只是第一步——系統上線後,監控才是真正讓系統「活下去」的關鍵。

「你一開始問我『系統是否健康』,」洛基說,「我答不出來,因為沒有數據。」

「現在呢?」大師問。

洛基指向儀表板:「現在我能回答——容量使用率 82%,接近上限需要擴容;有讀取限流,要檢查熱分區;Query 和 Scan 延遲偏高,要優化查詢設計。」

「這就是監控的意義,」大師說,「把『猜測』變成『數據』,把『被動反應』變成『主動預警』。」

洛基想起開場時的時間軸——沒有監控,問題發生 10 分鐘後才發現;有了監控,問題發生前就能預警。

他突然意識到另一個重點:「監控不只是發現問題,更重要的是『提供診斷的依據』。如果沒有 Contributor Insights,我根本不知道是哪個 PK 造成熱分區。」

大師微笑:「對。監控數據,就是診斷的線索。」

「明天,」他繼續說,「我們會學習容量規劃與成本優化——如何根據監控數據,做出正確的容量配置決策。」

洛基點點頭。他現在理解,技術、設計、監控、成本優化...這些都是環環相扣的。

系統設計不是寫完程式就結束,而是一個持續觀察、診斷、優化的循環。


時間設定說明:故事中使用星際曆(SY210 = 西元 2210 年),程式碼範例為確保正確執行,使用對應的西元年份。


上一篇
Day 27:Streams 與事件驅動架構
下一篇
Day 29:容量規劃與成本優化
系列文
DynamoDB銀河傳說首部曲-打造宇宙都打不倒的高效服務30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言