DynamoDB更新80万条数据时updateTable耗时及流开关优化咨询
updateTable修改流配置的耗时说明
调用updateTable接口调整DynamoDB流开关状态不是即时生效的,整体耗时通常在30秒到数分钟区间:
- 接口调用成功后,表会先进入
UPDATING状态,这个阶段表的正常读写不受影响,但流配置的变更不会实际生效 - 只有等表状态重新回到
ACTIVE,流的开关状态才会真正切换,如果不等状态就绪就执行更新操作,流依然会被触发 - 绝对不能在单条
updateItem操作前后重复调用流开关接口:一来每次等状态切换的时间开销会把80万条数据的更新时长拉到完全不可接受的程度,二来短时间内多次触发表配置变更很容易触发DynamoDB管控接口限流,直接导致请求报错。
80万条数据批量更新的落地方案
你原本计划的单条更新前后反复开关流的方案完全不具备可行性,下面按推荐优先级给出可落地的实现方式:
方案1:下游函数层做事件过滤(最优,无业务风险)
不需要修改表的任何配置,直接从流触发的下游逻辑侧过滤无效事件:- 给本次批量更新的所有写入请求统一添加一个临时标识字段,比如
bulkUpdateFlag: 1 - 在4个被流触发的函数的DynamoDB事件源映射上配置过滤规则,直接丢弃携带这个临时标识的流事件,从入口层就避免函数被触发
- 批量更新全部完成后,后续正常业务写入不带这个标识,就会正常触发流和下游函数
这个方案没有表级操作风险,不需要等待配置生效,也不会影响线上正常业务,实现成本最低。
- 给本次批量更新的所有写入请求统一添加一个临时标识字段,比如
方案2:用批量能力替代单条循环更新
80万条数据用单条updateItem循环执行本身效率极低:- 可以改用
batchWriteItem接口做批量写入,单次请求最多支持处理25条数据,写入效率比单条更新高数倍 - 如果是全表维度的固定逻辑更新,直接用DynamoDB的S3批量导入能力完成更新,这种导入方式默认不会触发DynamoDB流事件,完全不需要开关流,80万条数据通常十几分钟就能跑完,稳定性远高于自定义脚本循环写入。
- 可以改用
方案3:临时关流的正确实现(仅适合可接受流断档的场景)
如果评估后确实需要通过关流避免下游触发,注意全程只做一次关流、一次开流操作,不要重复调用接口,参考实现如下:
var dynamodb = new AWS.DynamoDB(); async function waitTableActive() { while(true) { const tableDesc = await dynamodb.describeTable({ TableName: 'yourTableName' }).promise(); if (tableDesc.Table.TableStatus === 'ACTIVE') return; await new Promise(resolve => setTimeout(resolve, 5000)); } } async function runBulkTask() { // 提交关流请求 await dynamodb.updateTable({ TableName: 'yourTableName', StreamSpecification: { StreamEnabled: false } }).promise(); // 等待关流真正生效 await waitTableActive(); // 此处执行80万条数据的全部更新逻辑 // your bulk update code here // 全部更新完成后提交开流请求 await dynamodb.updateTable({ TableName: 'yourTableName', StreamSpecification: { StreamEnabled: true } }).promise(); } runBulkTask().catch(err => console.log(err, err.stack));
注意:关流后重新开启的流,只会包含开流时间点之后产生的数据变更,关流期间的所有操作都不会进入流记录,如果下游有依赖流做跨系统数据同步的逻辑,需要提前评估这部分数据断档的影响。
内容的提问来源于stack exchange,提问作者Hulubina
相关产品推荐
相关产品推荐

