· 閱讀時間 8 分鐘

一張新的 DynamoDB 資料表每秒能寫入多少筆才會被節流?

AWS 文件記載,一張全新的 資料表開箱即可提供 "up to 4,000 write request units per second"。至今大家仍在引用的那份實測——Capital One 和 ScyllaDB 都連結過去的那一份——量測於 2019 年,那時還沒有預熱輸送量、還沒有可設定的上限、現行的擴展規則也還不存在。就我們所知,此後沒有人再發表過任何量測。

所以我們自己跑了一次。2026-08-27,對著一張幾分鐘前才在 us-east-1 建立的資料表,把寫入負載從每秒 1,000 個請求一路拉到 8,000:

施加負載實際達成遭節流的請求數
1,000/s1,000/s0
2,000/s2,000/s0
3,000/s3,000/s0
4,000/s4,000/s0
5,000/s4,132/s25,992
6,000/s4,131/s55,966
8,000/s4,134/s115,922

文件記載的基準成立,而且略為保守:服務在 4,000/s 以下全數接受,一次拒絕都沒有,接著無論我們怎麼加壓,都釘死在每秒 4,130 ±2 次寫入。三個時間窗、三種施加速率,同一個天花板,差距在 0.05% 以內。讀取則從頭到尾沒有被節流過——我們把一張已灌入資料的資料表推過每秒 12,700 次最終一致讀取,再往上的缺口是我們自己的用戶端造成的,不是 DynamoDB。

一張資料表、一天、一個區域、鍵均勻隨機的約 1 KB 項目——完全看不到 的影子。這個範圍就是這裡每一個數字底下誠實的小字。本文其餘部分講的是我們如何量測,包括這套基準測試在成功之前先失敗了三次,而三次失敗沒有一次是 DynamoDB 的錯。

節流是 400,而且它先點名了錯的嫌犯

天花板一撞上,你收到的那則錯誤值得細讀:

ThrottlingException: Throughput exceeds the current capacity of your table or index.
DynamoDB is automatically scaling your table or index so please try again shortly.
If exceptions persist, check if you have a hot key:
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html

三項觀察,全都經過量測:

  • 它是 HTTP 400,不是 5xx。你的重試策略和你的儀表板都得知道這件事。只重試 5xx 的用戶端會把這些請求丟在地上;只對 5xx 告警的監控,會在你三分之一的寫入被彈回時,仍然顯示服務一片綠。
  • 每個超出基準的時間窗裡,第一次節流出現在 0.9–3.8 秒之間——服務會先給你一小段緩衝的爆發額度,天花板才開始生效;施加速率越高,它咬得越早。
  • 熱門鍵那句提示是預設文案,不是診斷。我們的鍵是均勻隨機的 UUID,根本沒有熱門鍵。在小規模下,這則訊息的第一嫌犯就只是資料表層級的天花板。

延遲對這一切無動於衷:每個時間窗裡,同區域的寫入 p50 延遲都是 4–5 ms,被節流與否都一樣。拒絕對服務來說很便宜——它不會變慢,它只是說不。

你無法用一台筆電量測這件事

我們的第一套儀器是最順手的那個:一台在馬德里的筆電上跑的 Node 指令碼。它把節奏乾淨地控在每秒 1,000 次寫入,到 2,000 就垮了——不是因為 DynamoDB 推了回來,而是因為約 100 ms 的跨大西洋往返意味著每秒 2,000 個在途請求需要數百條並行的 socket,而事件迴圈被淹沒了。服務一次都沒有節流。我們量測的是自家的 Wi-Fi。

第二次嘗試把執行器搬進同一個區域,用單一個 Lambda 函式。同區域的往返約 5 ms,一個 3 GB 的函式能以 10 ms 的 p50 乾淨地維持每秒 2,000 個請求。再往上就在 1,100/s 左右打平,CPU 滿載:請求簽章與回應處理是單執行緒的 JavaScript,一個執行器根本沒辦法一秒簽 4,000 個請求。配置的記憶體:3 GB。用掉的記憶體:253 MB。瓶頸從來不是 RAM——Lambda 的 CPU 份額隨它的記憶體設定放大,我們買的是運算,不是儲存。

所以最終的儀器是一支由八個 Lambda 組成的機隊,每個負責總施加速率的八分之一,全部對著一個共用的牆鐘 T0 啟動,好讓它們的時間窗對齊。八個執行器各自跑在舒適的 1,000/s,就給了我們 8,000/s 的施加負載還留有餘裕,而總量是被計數請求的加總——任何地方都沒有外推。

三次執行陣亡才換來一次成功,而 DynamoDB 每次都是無辜的

機隊的第一次執行結束時,有一個執行器回報它在 T0 之後 882 秒才啟動——一場二十秒的約會遲到了十五分鐘。第二次執行死於讀取逾時。第三次在關掉重試之後,八個執行器同時大聲失敗。與此同時,CloudWatch 顯示每一個 Lambda 都乾淨、準時、無誤地跑完了四分鐘的量測。

元兇是筆電與 Lambda 之間的那條連線。一次同步呼叫會在整段執行期間,把一條完全靜默的 HTTPS 連線一直開著——而家用路由器會在幾分鐘後悄悄殺掉靜默的連線。CLI 看到 socket 已死,做了最糟糕的一件事:它默默重試,重跑了一個量測 Lambda,而那個 Lambda 發現自己的 T0 早已遠去。一套會在你看不見的地方跑兩次的基準測試框架不是框架;它是一台附帶 AWS 帳單的亂數產生器。

最後成功的那個形狀有三條規則,往後任何長時間的遠端量測我們都會照做:

  • 射後不理,結果走帶外通道。執行器以非同步方式呼叫(連線在幾毫秒內就關閉),並把各自的結果以項目寫進一張小的 DynamoDB 資料表;驅動端輪詢那八列結果。沒有任何連線活得比一個請求更久。
  • 每一層都關掉重試。量測用的用戶端每個請求只嘗試一次——重試會默默吸收掉我們正是為了計數而存在的那些節流——呼叫路徑上的重試也一併關掉,這樣就沒有任何執行器可能被執行兩次。
  • 用看門狗取代掛死。每個執行器都讓自己的排程與一個死線賽跑;只要有什麼卡住,它就回傳部分計數,外加一份「它究竟卡在哪裡」的快照,而不是在沉默中逾時。一次會自我解釋的失敗執行只花掉一次讀取;一次掛死的執行要花掉一個晚上。

每個請求也都帶著 8 秒的逾時。那次掛住的執行之所以掛住,是因為單一個沒有逾時的在途請求,把最後的排空步驟永遠卡住了。約 400 萬個請求裡,一次沒有上限的等待就足夠了。

讀取的表現如何

讀取階段跑在第二張灌入 1,000 個項目的全新資料表上,使用 GetItem(每個約 1 KB,0.5 個讀取單位):

施加負載實際達成遭節流
4,000/s4,000/s0
8,000/s7,941/s0
12,000/s11,119/s0
16,000/s12,762/s0

一次節流都沒有,從頭到尾。文件記載的每秒 12,000 次讀取基準成立,而我們找不到它的邊緣:在施加 16,000/s 時,八個執行器裡有五個先撞上自己用戶端這一側的飽和,所以 12,762/s 是我們這支機隊的上限,不是 DynamoDB 的上限。我們把這點直說,而不是把它包裝成服務限制。同區域的讀取 p50 是 2–4 ms。

還有兩個較小、但值得記住的數字:一張全新的隨需資料表從 CreateTableACTIVE,在這次基準測試中花了 22 秒,在較早的一次探測中花了 7.4 秒——請按這個變異數編列預算,而不是按最佳情況。另外,整場基準測試共 672,116 次計費寫入和 108 萬次讀取,成本是 $0.97。儀器可以重複使用;這場實驗只值一杯咖啡。

半小時的壓力不會讓天花板加倍

AWS 的成長規則說,隨需容量最多可以容納你先前尖峰的兩倍。我們想親眼看到這件事發生,所以在天花板那一輪之後,我們對一張資料表連續施加 8,000 寫入/秒的負載共 34 分鐘不中斷,並把實際達成速率以每 10 秒分桶。形狀是這樣:

承壓分鐘數天花板
0–8~4,000/s(基準,紋風不動)
9–25~5,000/s
26~6,000/s
27–34~7,000/s
在 8,000/s 供給下持續 34 分鐘、逐分鐘的實際寫入/秒

成長是以突兀的約 1,000/s 階梯到來的,不是一道斜坡——這一分鐘平在一個速率上,下一分鐘平在下一個速率上。第一道天花板在整整 8 分鐘的持續超額需求下都黏著不動。而 34 分鐘之後,資料表提供了 7,000/s:是它起點的 1.75 倍,仍然不及施加的 8,000,也不及乾淨的翻倍。如果你的上線需要一張新資料表撐過約 4,000 寫入/秒,就提前把它預熱,或明確設定它的隨需輸送量上限——成長機制是真的,但它既不是瞬間的,也不會照你的時程慷慨。這個行為也很穩定:2019 年那份實測裡,承受 9,000/秒供給的資料表在測試結束時已成長到約 7,000/秒——和我們的資料表七年後到達的平台一模一樣。那一輪花了 $12.67,是我們那天做過最貴的一件事。

如果你要自己量測雲端服務,有哪些能帶著走

  • 把負載產生器放在與目標相同的區域。否則你量的是自己的網路路徑,不是那個服務。
  • 一個 Node 行程無論配多少記憶體,都在每秒約 2,000 個已簽章請求觸頂;把負載分片到多個執行器,再把計數過的結果加總。
  • 在量測路徑上,每一層都關掉重試。重試存在的目的,正是要藏起基準測試存在的目的。
  • 絕不要讓一條靜默的連線橫跨整段長時間執行。以非同步方式呼叫、用帶外通道交付結果、輪詢。
  • 給每個請求一個逾時,給每個執行器一隻看門狗,讓它回傳部分資料外加一份卡住狀態的快照。
  • 為每個執行器設一個硬性的操作次數上限,好讓節奏控制的錯誤直接中止而不是把帳單推高,並且在 finally 裡把這次執行建立的一切都拆掉——資料表、角色、函式、日誌。

這些數據餵進了哪些參考頁面

完整資料集——每個時間窗、每個執行器、各項延遲百分位數、逐字的錯誤字串——現在支撐著我們 DynamoDB 限制參考頁面裡那些實測表格,與我們稍早發表的項目大小與分頁上限探測並列。如果你每天都要和 DynamoDB 打交道,DynoTable 就是我們為它打造的桌面用戶端——同一個團隊,同一種在複述任何宣稱之前先對著實際服務查核的習慣。

不必透過主控台就能操作 DynamoDB

一款快速的 DynamoDB 桌面用戶端,可執行 DynamoDB 無法執行的真正 SQL — JOINs、GROUP BY、聚合 — 並支援視覺化編輯與使用你自己的 Bedrock 金鑰的 AI 代理。

30 天免費試用,無需信用卡 — 之後為無時間限制的免費方案。