WriteConflict 错误是WiredTiger引擎因多写操作争用同一文档或内存页引发的锁冲突,非网络或权限问题;需协同优化batch size(更新场景100–200)、writeConcern(非关键数据用{w:1})及磁盘IO(分离journal路径、监控wt:log延迟)。

WriteConflict 错误到底在报什么
WriteConflict 不是网络超时,也不是权限错误,而是 WiredTiger 存储引擎在底层检测到两个或多个写操作试图同时修改同一文档(或同一页面内的多个文档)引发的资源争用。它通常伴随 InterruptedDueToReplStateChange 或 WriteConflict 字样出现在日志里,驱动层可能抛出 MongoBulkWriteException 或 WriteConcernTimeout ——但根因不是副本集同步慢,是单节点内部锁竞争激烈。
bulkWrite 分批策略怎么设才不踩坑
盲目把 bulkWrite 的 batch size 拉到 5000 并不能缓解 WriteConflict,反而可能加重——WiredTiger 对单个 batch 内的文档会按内存页组织,同一批里若含大量 _id 邻近(如时间戳前缀)或分片键相近的文档,极易被塞进同一页面,触发密集锁争用。
- 先用
explain("executionStats")看单次 bulkWrite 是否命中大量keysExamined与docsExamined不匹配(说明更新/删除操作反复查找) - 对含高频更新字段(如
status、updated_at)的集合,batch size 控制在100–200更稳;插入为主场景可放宽到400 - 避免混用
updateOne和insertOne:前者需先查再改,后者直写,混合后整个 batch 耗时被拉长,窗口内冲突概率上升 - 显式加
ordered: false,让失败项不阻塞其余操作,但注意驱动返回的writeErrors需主动检查,不能忽略
为什么分批后还要调 writeConcern
副本集里 WriteConflict 高发时,常有人误以为“等从节点确认太慢”,于是把 writeConcern 降成 { w: 0 }。这只会掩盖问题——w: 0 不减少锁争用,只跳过确认环节,冲突依然发生,且无法感知失败。
- 真正该做的是:对非关键数据(如日志、埋点),用
{ w: 1 }(只等主节点 journal 落盘),这是崩溃恢复的安全底线 - 别全局配
w: "majority":它强制等多数节点 oplog 同步,若某从节点延迟高,主节点会卡住写入队列,加剧锁排队 - 如果必须用
w: "majority",确保所有从节点oplogSize≥ 24 小时变更量,否则追不上就会持续触发WriteConflict衍生错误
容易被忽略的底层 IO 影响
很多人调完 batch size 和 writeConcern 还是高频报 WriteConflict,这时要查磁盘——journal 刷盘慢会导致 WiredTiger 写入线程长时间阻塞,间接拉长锁持有时间,放大冲突概率。
- 确认
journal路径和dbPath是否分离:共用一块 SATA SSD 就算配置再好也扛不住 - 用
mongostat观察wt:log延迟是否持续 > 10ms;iowait是否超 30%;有则说明磁盘已成瓶颈 - NVMe 设备上把 I/O 调度器切为
none,XFS 文件系统挂载加nobarrier(仅限带电容保护的盘)可降低刷盘延迟 - 不要动
storage.journal.commitIntervalMs到30以下:小于这个值 journal 日志碎片化严重,反而更卡
WriteConflict 的本质是资源争用,不是配置缺失。批量大小、writeConcern、磁盘 IO 是三个咬合齿轮,调其中一个不碰另外两个,大概率白忙。


















