moveChunk 会引发写入冲突,因其迁移期间源分片持续接收写入并记录oplog,而目标分片在catching_up阶段批量回放变更;若应用高频写入同一chunk范围,易因网络延迟、目标负载高或journal刷盘慢导致重复应用、丢失或状态不一致,触发ConflictingOperationInProgress错误。

为什么 moveChunk 会引发写入冲突
分片迁移本身不直接修改文档内容,但 moveChunk 操作期间,源分片和目标分片对同一 chunk 的写请求会走不同路径:源分片仍接收新写入并记录 oplog,目标分片在追赶阶段(catching_up)批量回放这些变更。若此时应用持续高频写入该 chunk 范围内的数据,可能因网络延迟、目标分片负载高或 journal 刷盘慢,导致部分写操作在目标端重复应用、丢失或状态不一致——表现为 ConflictingOperationInProgress 错误或后续 find 返回陈旧/缺失数据。
用 writeConcern 控制迁移期间的写一致性
默认情况下,moveChunk 不阻塞写入,但你可以通过调整写入端的 writeConcern 来降低冲突风险。关键不是改迁移命令本身,而是约束业务写入行为:
- 对高敏感集合,写入时显式指定
{ w: "majority", j: true },确保变更在多数副本(含迁移中目标分片)落盘后才返回成功——这会自然拉长写入延迟,变相“节流” - 避免使用
{ w: 1 }或{ w: 0 },否则写入可能只落在源分片,而目标分片尚未同步,造成短暂读写分离失配 - 注意:该设置需在应用层或驱动连接字符串中配置,
mongos不会自动升级客户端的writeConcern
启用 migration throttle 并调优参数
MongoDB 本身不提供“迁移限速开关”,但可通过以下组合实现等效节流效果:
- 在
mongos配置中设置chunkSize为较小值(如1MB),让单次迁移数据量变小,缩短单个moveChunk执行时间,减少冲突窗口 - 手动控制迁移节奏:停用均衡器(
sh.stopBalancer()),用sh.moveChunk()逐个迁移 chunk,并在每次调用后加sleep(5000)(单位毫秒)等待目标分片稳定 - 监控
config.migrations中"state": "catching_up"的数量,超过 3 个就暂停下一轮迁移——说明目标分片已出现追赶延迟
容易被忽略的底层细节
真正影响写入冲突频率的,往往不是迁移命令本身,而是分片节点的磁盘 I/O 和 journal 配置。例如,目标分片若使用机械盘且 storage.journal.commitIntervalMs 设为默认 100ms,它在 catching_up 阶段每秒最多只能提交约 10 批 oplog;而源分片若为 SSD+30ms 提交间隔,写入吞吐可能是其 3 倍以上。这种硬件级不匹配,比任何上层节流都更致命。上线前务必检查所有分片的 storage.engine.wiredTiger.engineConfig.journalCompressor 和磁盘队列深度(iostat -x 1 中的 avgqu-sz)。


















