如何避免Cosmos DB的GET查询受长时间更新影响,读取到半更新数据?
Cosmos DB批量更新避免读取半更新中间态的解决方案
以下是几个生产可用的低开销方案,可根据你的业务场景选择:
- 方案1:新增批次标记字段,查询时过滤稳定版本
给所有涉及批量更新的文档新增batch_version整数字段,提前维护一个全局的对外公开稳定版本号。每次发起批量更新前,先生成一个比当前稳定版本号更大的新版本号,所有更新操作都将对应文档的batch_version设为新版本号。整批更新100%完成后,再将全局稳定版本号更新为新的版本号。所有常规查询默认增加WHERE batch_version = [当前稳定版本号]的过滤条件,永远只会读到整批更新完成后的全量数据,不会出现半更新的情况。
该方案额外RU开销极低,仅需在更新和查询逻辑中新增固定字段的写入和过滤,是跨分区批量更新场景下的最优解。 - 方案2:基于内置时间戳的快照读
利用Cosmos DB文档内置的_ts(最后更新时间戳,单位秒)字段实现快照读:批量更新开始前先记录当前的时间戳T0,所有常规查询默认增加WHERE _ts <= T0的过滤条件,只会读取批量更新开始前的稳定快照数据。等整批更新全部完成后,再将查询过滤的时间戳阈值更新为批量更新结束后的时间戳即可。
该方案无需修改文档结构,适合临时批量操作的场景,缺点是如果日常有单文档小更新,这些小更新也会被延迟到下一次阈值调整时才可见。 - 方案3:同分区下使用存储过程实现原子事务
如果你的批量更新涉及的所有文档都属于同一个逻辑分区,可以直接通过Cosmos DB存储过程(SPROC)实现整批更新的原子事务:存储过程内的所有写入操作要么全部成功要么全部回滚,天然不存在半更新的中间状态,无需额外修改查询逻辑。注意该方案仅适用于单分区内的批量更新,跨分区场景下Cosmos DB不支持分布式事务。 - 方案4:同会话下使用会话一致性保证
如果仅需要发起批量更新的客户端自身不会读到半更新数据,可以将客户端的一致性级别设置为会话一致性,等所有批量更新请求全部返回成功后再发起查询,同一个会话内天然保证“读取自己的写入”,不会出现中间状态。该方案仅适用于单客户端的场景,无法保证其他客户端的查询结果一致性。
补充说明:你之前考虑的两次查询对比ETag的方案RU开销是普通查询的2倍以上,大数据量下完全不可用;Cosmos DB本身不提供表级/容器级的锁机制,锁止查询的方案没有可实现性,无需继续尝试。
内容的提问来源于stack exchange,提问作者blomster
相关产品推荐
相关产品推荐

