中階閱讀時間 3 分鐘

DynamoDB 批次操作

當你需要一次讀取或寫入許多項目時,每個項目觸發一次 GetItemPutItem 意味著每個項目一次網路往返 —— 慢,且囉嗦。DynamoDB 的批次 API 把許多項目操作摺疊進一個單一請求BatchGetItem 用於讀取, BatchWriteItem 用於寫入。

它們是吞吐量與延遲上的勝利,而非一致性保證 —— 而那個 區別正是人們栽跟頭的地方。批次不是事務。

什麼是 DynamoDB 批次操作?

DynamoDB 批次操作把許多項目的讀或寫摺疊進一個單一請求:BatchGetItem 獲取最多 100 個項目,BatchWriteItem 放入或刪除最多 25 個,各自上限為 16 MB。它們節省往返,而非容量。關鍵在於,批次不是事務 —— 各個項目獨立地成功或失敗,沒有回滾。

  • BatchGetItem —— 在一次呼叫中跨一個或多個表獲取多達 100 個項目 (或 16 MB)。
  • BatchWriteItem —— 在一次呼叫中進行多達 25 個 put/delete 操作(或 16 MB)。 沒有更新 —— 只有 put 和 delete。
  • 不是原子的。 個別項目可以成功而其他失敗。沒有回滾。
  • 部分失敗是正常的。 被限流的項目會回到 UnprocessedItems / UnprocessedKeys 裡 —— 你必須自己帶退避地重試它們。
  • 與逐個呼叫相同的容量成本 —— 批次節省往返,而非容量 單元。

問題:許多項目,一次往返

假設你營運一個支援臺。一個儀表盤需要按 ID 載入 50 張工單來渲染一個 佇列;一個夜間作業歸檔 1,000 張已解決的工單。一次一個項目地做那件事 就是 50(或 1,000)次順序往返 —— 延遲層層累加,作業慢如爬行。

批次把那些摺疊成寥寥幾次呼叫。50 張工單的讀取變成一次 BatchGetItem;歸檔作業變成一連串每次 25 個刪除的 BatchWriteItem 呼叫。往返次數少得多,搬動的資料一樣多。

批次 API 如何工作

BatchGetItem 接受一組主索引鍵(跨一個或多個表)並返回 匹配的項目。你可以按表請求強一致讀取。它讀不到的任何東西 —— 通常是因為請求擦碰到了吞吐量限制 —— 會回到 UnprocessedKeys 裡,而非讓整個呼叫失敗。

BatchWriteItem 接受一個 PutRequest / DeleteRequest 操作列表。注意 缺了什麼:沒有更新。一次批寫要麼替換整個項目 (put),要麼移除它(delete) —— 要修改特定屬性,你仍需 UpdateItem。它寫不了的項目會回到 UnprocessedItems 裡。

成功被限流退避後重試BatchWriteItem:25put/delete逐項處理已寫入UnprocessedItems

關鍵心智模型:批次是一捆獨立的操作,每個 自行成功或失敗 —— 而非一個全有或全無的單元。

批次不是事務

這就是陷阱。如果你的歸檔作業的批次在中途撞上吞吐量限制,一些 工單被刪除了而一些沒有 —— 且 DynamoDB 不會撤銷那些已經 透過的。沒有回滾、沒有隔離、沒有“25 個全部或一個都不”。

如果你需要全有或全無的語義 —— “把工單移到已歸檔 並且 遞減 未結工單計數器,或者兩者都不做” —— 那是 TransactWriteItems,而非批次。事務成本 更高(每個操作按雙倍計費)且上限為 100 個項目,但它們給你 批次刻意不提供的原子性。

處理未處理項

一個正確的批次呼叫者總是檢查未處理集合並重試它。DynamoDB 在請求整體被接受但某些項目無法被服務時返回 UnprocessedItems/UnprocessedKeys —— 通常是短暫的限流。

只重新提交未處理的項目,帶 指數退避與抖動。 把批次當作即發即忘會靜默地丟失寫入 —— 那種 數月後才浮現為資料缺失的 bug。

DynoTable 裡的批寫

先用 DynamoDB 定價計算器估算一個批次 作業會花多少錢 —— 一個批次消耗的容量與它捆綁的 逐個寫入相同,只是請求次數更少。

在 DynoTable 裡,你在本地暫存你的編輯,並在提交它們之前審查它們 —— 跨許多行的批次更改會作為分組請求發出,而非每次一個 API 呼叫。批次刪除作為批寫發出,且未處理項的重試已為你 處理好。

在 DynoTable 中審查暫存的編輯,之後再把它們作為一個批次提交。
在 DynoTable 中審查暫存的編輯,之後再把它們作為一個批次提交。

陷阱與後續步驟

  • 總是帶退避地重試 UnprocessedItems/UnprocessedKeys —— 它們是 預期之內的,而非異常。
  • 無部分失敗回滾。 需要原子性?使用 事務
  • 批寫裡沒有更新 —— BatchWriteItem 只做 put/delete;要更改 屬性請動用 UpdateItem
  • 留意每次呼叫的上限 —— 25 個寫 / 100 個讀 / 16 MB。超出會讓整次呼叫以 ValidationException 失敗 (BatchGetItem 中條目過多BatchWriteItem)。為更大的 作業分頁;參見分頁

想在不為重試迴圈寫指令碼的情況下執行批次讀寫? 下載 DynoTable,直接編輯你的表。

往返數學

序列 GetItem 呼叫會支付每跳延遲。 BatchGetItem 捆綁最多 100 鍵或每個請求 16 MB — 以先達到的限制為準。

圖案按鍵大約。往返@ 50 鍵筆記
連續劇GetItem5050 5050最簡單的程式碼;最差尾部延遲
一個 BatchGetItem5050 1RCU 總數與 50 次相同
兩批120120 2第二批攜帶20把鑰匙

容量成本不變 — 批次節省了掛鐘時間和用戶端 CPU,而不是遠端控制單元。對於寫入,每批 25 次的 1,000 次刪除相當於 40 次 BatchWriteItem 呼叫而不是 1,000 個單獨刪除。

強一致批次讀取

請求對映中的每個表BatchGetItem接受ConsistentRead: true。對於相同項目,強讀取的成本仍然是最終讀取 RCU 的 2 倍。混合一次批次呼叫中一致且最終的表就可以了——每個表條目攜帶自己的旗幟。

分塊大型作業

當歸檔 1,000 個平均每個 3 KB 的項目時,單批讀取保持在 100 項上限,但可能超過 16 MB(100 × 3 KB = 300 KB — 安全)。存檔 50 KB 的項目,每次呼叫都會達到大約 320 個項目的兆位元組上限,即使計數限制為 100。頁面使用顯式迴圈寫入:

for each chunk of 25 keys:
  BatchWriteItem
  retry UnprocessedItems with backoff until empty

DynoTable的分階段提交批次符合條件的寫入並重試未處理的項目自動地——否則你會用不穩定的睡眠來編寫這種模式。

批次決策與事務決策

需要API最大物品數關於部分失敗
盡力批次裝載BatchWriteItem25 次操作重試未處理
全有或全無的賬本轉移TransactWriteItems100 次操作整個 txn 回滾
閱讀許多已知的金鑰BatchGetItem100 個按鍵重試未處理的金鑰
原子讀+寫TransactWriteItems25 次交易操作(有記錄的限制適用)全部或全部

使用以下命令從普通 JSON 生成放置/刪除有效負載 DynamoDB JSON converter 播種批次時來自固定裝置的負載。

檢查消耗的容量

根據請求,批次響應可以包含每個表 ConsumedCapacity。記錄它在回填期間 - 隨著未處理集的增加,節流率不斷上升在就業完全停滯之前。交叉檢查持續的 WCU 與 pricing calculator 如果批次執行在時間表。

已更新