DynamoDB 節流——為什麼會發生,以及如何修正
節流是 DynamoDB 在告訴你有個限制被打到了——但限制有四種、例外有三種, 而針對其中一個成因的修正會讓另一個更糟。拉高表格容量對熱鍵毫無作用; 改用隨需對熱鍵一樣毫無作用,而且它照著自己那套規則仍然會節流。這份 指南是那把傘:你實際打到的是哪一個限制、指標要怎麼分辨它們,以及每個 成因所對應的修正。
為什麼 DynamoDB 會節流我的請求?
四個有記載的原因之一:某個單一分割區超出了它每秒 3,000 個讀取單位或 1,000 個寫入單位那個固定的每分割區上限(一個熱鍵——兩種容量模式下都會 發生);表格超出了它佈建的 RCU/WCU(佈建模式);帳戶超出了它區域層級 的輸送量配額;或者一張隨需表格在 30 分鐘內成長得比它先前峰值的兩倍還 快。修正方式取決於是哪一個,所以在你調整任何尺寸之前,先診斷。
四種節流情境
AWS 自己的疑難排解頁面 把節流恰好分成四種情況:
- 超出鍵範圍(分割區)輸送量——兩種模式皆然。 每個分割區的設計 上限是每秒 3,000 個讀取單位與 1,000 個寫入單位 (分割區索引鍵文件), 而項目大小也會計入。沒有任何表格層級的設定能拉高這個值;只有鍵設計 能把它分散開。這就是熱分割區的情況, 而表格可能在節流的同時看起來嚴重未被使用。
- 超出佈建輸送量——佈建模式。 消耗量打贏了表格(或某個 GSI)的 佈建 RCU/WCU,而那約 5 分鐘的 突發容量 緩衝也已經花光。修正的階梯是在容量這一側: 自動擴展、更高的佈建量,或是 切換模式。
- 超出帳戶層級配額。 區域性的帳戶配額為總輸送量設下上限——預設 每張表格 40,000 個讀取與 40,000 個寫入單位,而佈建模式下每個帳戶 80,000 RCU 與 80,000 WCU (配額); 這些是初始預設值,可以透過 Service Quotas 調整,而隨需表格沒有帳戶 層級的輸送量配額。
- 超出隨需的最大輸送量。 隨需能即時容納到先前峰值的兩倍;在 30 分鐘內成長超過兩倍,它就可能節流 (隨需文件)。 新的隨需表格開箱就能撐住每秒 4,000 次寫入與每秒 12,000 次讀取。 對於一次有計畫的跳階尖峰(發表、促銷、遷移),與其指望爬升是漸進的, 不如先用暖輸送量把表格預熱。
三種例外,以及那個點名成因的欄位
ProvisionedThroughputExceededException——佈建模式的容量節流: 「你超出了一張表格或一個以上全域次要索引所允許的最大佈建輸送量」。 細節在專屬的錯誤頁面。ThrottlingException——控制平面操作發得太快,以及在隨需表格上, 任何速率過高的資料平面操作(那就是兩倍峰值規則背後的那個例外——見 隨需錯誤頁面與 ThrottlingException)。RequestLimitExceeded——帳戶層級的輸送量限制:屬於「聯絡 AWS Support」的地帶,在它的錯誤頁面 有涵蓋。
這三種都被標記為可重試,而且三種現在都帶有形式為「資源 + 操作 + 限制」
的結構化 ThrottlingReason 值——TableReadProvisionedThroughputExceeded、
IndexWriteKeyRangeThroughputExceeded、TableWriteAccountLimitExceeded
等等(錯誤參考)。
要讀的是那個 reason,而不只是例外類別:它點名了資源(表格或索引)、操作
的方向,以及你打到的是四個限制中的哪一個——而那正好就是診斷本身。文件
自己逼出來的一個保留說法:AWS 的頁面對於帳戶限制的節流究竟是以
RequestLimitExceeded 出現,還是以帶著 AccountLimitExceeded reason 的
ThrottlingException 出現,說法並不一致,所以請把你的處理邏輯綁在那個
reason 字串上。
在你被節流之前,是什麼吸收了負載
有兩個內建機制會軟化限制,而知道它們的邊界就能解釋「昨天還好好的」:
- 突發容量為尖峰保留最多五分鐘(300 秒)的未使用讀取與寫入容量 ——但 DynamoDB 也可能「不事先通知」就把它拿去做背景維護,而且 AWS 明白指出細節可能會變。別為突發容量做設計;把它當成運氣。
- 自適應容量 會自動且即時地把 輸送量挪向熱分割區,並且能把一個被頻繁存取的項目隔離到它自己的分割區 上——但只「在流量不超過你表格的總佈建容量或分割區最大容量的前提下」。 它重新平衡的是傾斜;它從來不會抬高 3,000/1,000 的每分割區天花板, 而且當表格有 LSI 時它不會切分項目集合。目前的 AWS 疑難排解頁面倚重 分裂散熱(split-for-heat)——分割區在持續的熱度下裂開——這需要時間, 而且對單一個熱鍵沒有幫助。
從指標診斷
CloudWatch 把請求與事件分開,而這個區別本身就完成了診斷 (指標參考):
ThrottledRequests只要一次請求裡有任何一個事件被節流,就把那次 請求算一次——一張有三個 GSI 的表格上的PutItem是一次請求,卻是四個 寫入事件。在一次批次中,只有每一個項目都被節流時它才會增加。ReadThrottleEvents/WriteThrottleEvents計算每一個被節流的事件 ——一次 10 個項目的BatchGetItem就是 10 個GetItem事件。要看到某個 GSI 的寫入節流,你必須同時用TableName與GlobalSecondaryIndexName去查詢那個指標——這就是 GSI 反壓從表格層級儀表板裡藏起來的方式。- 較新的依成因區分的事件指標
(
WriteProvisionedThroughputThrottleEvents、ReadKeyRangeThroughputThrottleEvents、…AccountLimitThrottleEvents、…MaxOnDemandThroughputThrottleEvents)把計數依照同樣那四個成因拆開 ——如果你的區域有顯示它們,它們就直接回答了「是哪個限制」這個問題。
有一個陷阱:SDK 會自動重試被節流的請求——標準重試模式預設會做總共 3 次 嘗試(2026 年那次選擇加入的重試改版,會把 DynamoDB 用戶端移到 4 次嘗試 並縮短延遲)。因此輕微的節流會以延遲、而不是以錯誤的形式出現;要盯的是 節流指標,而不只是你的例外日誌。
GSI 反壓:指向錯誤表格的那種節流
如果有任何 GSI 吸收不了寫入放大,「DynamoDB 就會節流對基礎表格的寫入,
以維持資料一致性」
(GSI 節流文件)
——即使基礎表格還有容量可用。那個例外的 ResourceArn 指向的是索引,但
失敗的那個操作是你對基礎表格的寫入。每一個索引都需要它自己的容量規劃
(以及它自己的自動擴展政策);
為什麼 GSI 會節流基礎表格寫入
逐步講解了其中的機制。
讓修正對上成因
| 成因 | 什麼能修好它 | 什麼修不好 |
|---|---|---|
| 熱鍵/熱分割區 | 能分散負載的鍵設計(熱分割區);留給分裂散熱的時間 | 拉高表格容量、改用隨需 |
| 佈建容量 | 自動擴展、更高的最小值,或隨需 | 只靠重試——它們只會加重負載 |
| GSI 反壓 | 擴展索引;改用稀疏索引或調整投影 | 擴展基礎表格 |
| 帳戶配額 | 透過 Service Quotas 調高 | 表格層級的設定 |
| 隨需的跳階尖峰 | 預熱(暖輸送量);把爬升分散到 30 分鐘以上 | 等待——兩倍峰值的重設很慢 |
在 DynoTable 中做這件事
大多數自己造成的節流,都始於那些成本比看起來高的讀取:一次帶篩選的
Scan 無論如何都會消耗完整的讀取量。DynoTable 的執行前成本預覽會顯示
一段陳述式會變成 Query 還是 Scan、它打到哪個索引,以及在你花掉之前
的讀取成本估計——最便宜的節流修正,就是那次你沒有跑的昂貴讀取。
Scan 對 Query 指南涵蓋了其中的差異;免費的
項目大小計算器會把一個真實項目
換算成上面那些限制所用的 RCU/WCU 數字。
陷阱與後續步驟
- 重試會放大過載。 退避已經內建在 SDK 裡,但在 SDK 重試之上再疊一層 緊湊的應用層重試迴圈,只會對那個正在苦撐的分割區加倍施壓。
- 批次會藏起部分節流。 只要還有項目成功,
BatchWriteItem就會回傳 未處理的項目而不是拋出例外——要檢查UnprocessedItems,而不只是例外。 - 表格層級的檢視會對 GSI 說謊。 永遠要逐索引繪製節流事件;基礎表格 的儀表板在反壓期間看起來很乾淨。
- 容量的修正以分鐘計;鍵設計則是永久的。 自動擴展約 5 分鐘才反應, 配額調高要開一張支援工單,但一個熱鍵會跟著你到每一種容量模式——把力氣 花在會複利的地方:分割區索引鍵如何運作。
下載 DynoTable 在每次查詢跑去消耗你的容量之前,先看它的 Scan 對 Query 計畫與讀取成本。