MongoDB 5.0多文档事务错误码112排查与复现咨询
MongoDB 5.0 写入冲突问题解答
问题1:为何集群日志无WriteConflict(112)错误记录?如何配置仅记录此类错误?
日志未记录的原因
- 错误返回层级问题:你看到的错误是由
mongos路由节点返回的,但实际的WriteConflict发生在分片节点(mydatashard:27017),若你只查看了mongos或其他非目标分片的日志,自然找不到对应记录。 - 默认日志策略:MongoDB 5.0中,WriteConflict(112)属于预期的并发冲突类 transient 错误,默认不会将这类客户端可见的冲突写入节点日志,仅会直接返回给发起请求的客户端。
配置仅记录错误码112的日志
MongoDB 4.4+支持通过logFilter过滤特定错误码,结合日志组件级别调整实现精准记录,需在发生冲突的分片节点上配置:
动态配置(无需重启节点)
在分片节点的mongosh中执行:
db.adminCommand({ setParameter: 1, // 调整命令、写入组件的日志级别,确保能捕获到冲突事件 logComponentVerbosity: { command: { verbosity: 1 }, write: { verbosity: 1 } }, // 过滤仅记录错误码112的日志 logFilter: { filter: { code: 112 }, action: "log" } })
配置文件持久化(mongod.conf)
systemLog: verbosity: 0 component: command: verbosity: 1 write: verbosity: 1 filter: - filter: { code: 112 } action: log
配置后,仅错误码112的WriteConflict日志会被输出,其他无关日志不会被记录。
问题2:如何正确复现错误码112(WriteConflict)场景?
你当前的复现方式得到251(NoSuchTransaction)错误,是因为事务在更新阶段已因冲突被终止,导致commit时返回事务不存在的错误。要复现112错误,需让冲突发生在事务内的操作执行阶段,而非commit阶段。
正确复现步骤
- 先准备测试数据:
db.cities.insert({name: "test", x: 0})
- 使用两个会话模拟并发冲突:
会话1(先执行):
var session1 = db.getMongo().startSession(); session1.startTransaction({ readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } }); var coll = session1.getDatabase('test').getCollection('cities'); // 查询文档获取快照,持有锁资源 coll.findOne({ name: "test" }); // 等待5秒,给会话2执行更新的时间 sleep(5000); // 执行更新,此时会话2的更新已触发冲突 coll.update({ name: "test" }, { $set: { x: 1 } }); try { session1.commitTransaction(); } catch(e) { print(JSON.stringify(e)); } session1.endSession();
会话2(在会话1执行findOne后立即启动):
var session2 = db.getMongo().startSession(); session2.startTransaction({ readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } }); var coll = session2.getDatabase('test').getCollection('cities'); // 直接执行更新,与会话1的快照锁产生冲突 coll.update({ name: "test" }, { $set: { x: 2 } }); try { session2.commitTransaction(); } catch(e) { print(JSON.stringify(e)); } session2.endSession();
关键注意事项
- 若使用分片集群,需确保测试文档被路由到同一个分片(比如将
name设为分片键,或文档哈希值落在同一分片)。 - 冲突的核心是两个操作同时修改同一文档,且其中一个操作持有快照或锁资源,导致另一个操作触发WriteConflict。
内容的提问来源于stack exchange,提问作者R2D2
相关产品推荐
相关产品推荐

