DynamoDB bulk put items 的批量写入语义:部分失败、幂等与重试该问什么
AWS 周报确认 DynamoDB bulk put items 是从 S3 读取文件的托管异步作业,每条记录可携带自己的条件表达式,且取消作业不会回滚已写入的条目;但部分失败的报告粒度、自动重试的范围与幂等保证,材料中没有说明。本文按“先固定已知事实、再按失败半径提问”的顺序,给出向官方确认这三类语义的问题清单,以及答案到手前可以先定下的设计约束。
- 条件表达式是逐记录生效的,因此同一个文件里部分成功、部分失败属于设计内的结果,不应按异常处理。
- “取消不回滚”意味着重跑要自己处理已写入的数据;幂等应落在条件表达式或版本号上,不能依赖作业状态。
- 最该先问清的是重试的单元——作业、文件还是单条记录,它直接决定失败半径和重跑成本。
先给结论:按 AWS 在 2026 年 11 月 9 日周报中的描述,DynamoDB bulk put items 是一个从 S3 读取文件、写入已存在表的托管异步作业,并且每条记录可以携带自己的条件表达式。这两点合在一起,已经足以说明“部分失败”不是异常路径,而是这个功能的正常输出之一。真正缺失的是三件事:失败记录怎么返回、重试由谁发起、幂等由什么保证。本文不复述功能,而是把这三个问题拆成可以直接发出去的提问。
材料能确认的与不能确认的#
先把边界划清。以下事实来自 AWS 周报正文(AWS Weekly Roundup,2026-11-09),属于发布方陈述,不是本机验证结果。
| 事项 | 状态 |
|---|---|
| 从 S3 读取 line-delimited DynamoDB JSON 或 Amazon Ion 文件,写入已存在的表 | 周报确认 |
| 以托管、异步作业的形式执行 | 周报确认 |
| 每条记录可带独立条件表达式,一个文件可混合普通写、仅插入、版本保护写 | 周报确认 |
| 写入使用专用系统容量,成本低于等效的按请求写入 | 周报确认(未给具体单价) |
| 取消作业不会回滚已写入的条目 | 周报确认 |
| Accelerated 层:1 亿条 1 KB 记录不到 1 小时 | 周报转述 Database 博客的“示意性”时间,属二手转述,非实测 |
| 部分失败的错误报告格式与粒度 | 待核实 |
| 自动重试是否存在、重试单元与次数上限 | 待核实 |
| 幂等保证、并发写冲突处理 | 待核实 |
| 单作业大小上限、并发作业数、区域可用性、精确计费口径 | 待核实 |
注意最后四行的写法:材料没提供,不等于官方没说明。它只意味着本文没有依据去描述这些行为,需要查对应的 API 文档或直接问支持。
为什么“部分失败”必须先问,而不是最后问#
条件表达式是逐记录生效的。一个文件里混了三种写入意图时,同一批数据里出现“这几条写进去了、那几条条件不满足”,是由数据本身决定的,不是作业出了故障。如果调用方把“作业完成”等同于“全部写入”,后续的补偿逻辑就会建立在错误前提上。
所以要问的第一组问题是关于失败如何被表达:
- 条件不满足的记录,是作为失败返回,还是作为“跳过”计入另一类统计?两者对账方式完全不同。
- 失败明细以什么载体返回——作业结果里的结构化列表,还是另写一个 S3 对象?如果是后者,路径规则是什么?
- 失败记录是否保留原始输入行号或主键,以便和源文件对齐?没有这个,续跑只能整文件重来。
- 作业状态是否区分“执行完成”和“全部写入成功”?如果只有前者,监控就需要额外的判据。
- 条件失败是否计入计费容量?这决定了“用一个宽松条件过滤掉大量记录”是不是一个廉价操作。
幂等要问的是“哪一层幂等”#
“幂等”在这个场景里容易被说成一句话,实际至少有三层,混在一起问会得到含糊的答案。
第一层:作业级重放
同一个 S3 文件被提交两次,结果是否与提交一次相同?这一层取决于记录内容和条件表达式,而不只取决于服务。周报明确说取消不回滚,那么“取消后重跑”就必然会遇到已经写入的条目,重跑时它们是覆盖、是被条件拦住,还是报冲突,需要在文档里找到明确表述。
第二层:记录级条件
用条件表达式做幂等是老办法,但它的有效范围有限。仅插入场景(属性不存在才写)能挡住重复;覆盖写如果记录里带更新时间戳或自增版本号,重放会改变最终值;版本保护写(比较版本号再更新)在重放时会因条件不满足而失败——这既是保护,也会在一次整文件重跑中制造大量“失败”,把真正的数据问题和重放噪音混在一起。
下面只是 DynamoDB 条件写入的通用形式,用来说明思路,不是 bulk put items 的接口示例,也未执行;该作业是否原样接受这种表达式,须以文档为准。
// 占位示意,未执行
{
"PK": { "S": "order#1001" },
"SK": { "S": "v0" },
"version": { "N": "3" },
"status": { "S": "paid" }
}
// 条件:仅当记录不存在时写入
ConditionExpression: "attribute_not_exists(PK) AND attribute_not_exists(SK)"
第三层:调用方自己的去重
如果作业不保证“每条记录最多写一次”,那么幂等就得由数据模型承担:稳定的业务主键、单调版本号、以及一个能判断“这条是否已经处理过”的条件。这一层不能外包给服务。
重试的问题清单#
重试的单元决定失败半径,这是最该先问的一项。按重要性排:
- 自动重试的单元是作业、文件,还是单条记录?单条记录重试意味着失败半径最小,但也意味着重试逻辑在服务内部,调用方不可控。
- 重试次数上限与退避策略是什么?多次重试后仍失败的记录如何上报?
- 部分失败后能否只提交失败子集?如果必须整文件重来,重跑一次的成本(容量与时间)是多少?
- 重试是否重复消耗专用容量?计费按提交的记录数还是按实际写入的记录数?
- 作业被取消后重跑,已写入条目的处理是覆盖还是跳过?周报只说“不回滚”,没有说重跑语义。
- 限流或容量不足导致的失败,与条件不满足导致的失败,是否在结果中区分?两者该触发完全不同的应对。
在答案到手前的设计约束#
不必等文档齐全才动手,有几条约束在任何一种答案下都成立:
- 不要用作业状态做唯一判据。把“作业完成”和“数据核对通过”当成两件事,后者用主键抽样或计数比对完成。
- 把幂等写进条件,而不是写进流程。流程会被绕过,条件不会。
- 缩小文件粒度。一个文件对应一个可重放的业务批次,失败时重跑范围可控。代价是作业数变多,需要权衡并发上限(待核实)。
- 保留 S3 源文件作为事实源。作业不回滚,源文件就是唯一的原始记录;删除前先确认对账已完成。
- 把“条件失败”单独打点。它是数据信号,不该和基础设施失败混在同一个告警里。
边界说明#
本文没有调用该功能,也没有运行任何代码;所有行为描述以周报正文为限,Accelerated 的时间数字是周报对另一篇博客的转述,属于示意值,不构成性能承诺。接口名称、错误结构、配额与区域支持情况在本次材料中均未提供,需要以官方文档为准。如果你的场景对“最多写一次”有硬要求,在拿到明确的重试与幂等说明之前,建议先用条件表达式兜底,而不是依赖作业语义。
常见问题(FAQ)
bulk put items 会自动重试失败的记录吗?
用条件表达式就能保证幂等吗?
作业状态显示完成,就代表所有记录都写入了吗?
参考来源
以上为本文写作时的参考资料,引用观点以原文为准。