进阶阅读约 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 如果批次运行在时间表。

更新于