readconcern="snapshot" 仅在满足 majority 写关注的副本集事务中生效,要求至少 3 个健康可投票节点、writeconcernmajorityjournaldefault: true(或显式指定 w: "majority"),且必须在 starttransaction() 中声明,不支持普通查询;分片集群还需启用 enableshardingsnapshotreads 并确保 config server 为副本集。

readConcern="snapshot" 要求副本集必须启用majority读写
不满足这个前提,readConcern="snapshot" 会直接报错 Read concern 'snapshot' is only supported on replica sets with majority write concern enabled。这不是配置问题,而是 MongoDB 的硬性要求:必须有足够多的节点能持久化数据(即支持 w: "majority"),快照隔离才可能成立。
检查方式很简单:
- 连接到主节点执行
rs.status(),确认至少有 3 个健康成员(2 个不够,多数派需 ≥2) - 运行
rs.conf(),检查每个成员的priority和votes都非零,且没有被隐藏或延迟 - 确保写操作默认使用 majority:执行
db.runCommand({getCmdLineOpts: 1})查看replication.replSet是否含writeConcernMajorityJournalDefault: true(4.4+ 默认开启;若为 false,需显式指定{writeConcern: {w: "majority"}})
必须在事务内使用 snapshot readConcern 才生效
readConcern="snapshot" 单独用于普通查询(如 db.collection.find().readConcern("snapshot"))会被忽略,不报错但也不提供快照语义——它只在事务中起作用。这是最容易误解的一点:快照隔离不是“单次查询级别”的特性,而是“事务级别”的一致性保证。
正确用法是:
session.startTransaction({readConcern: {level: "snapshot"}});
db.collection.find({x: 1}).toArray(); // 看到事务开始时刻的快照
db.collection.updateOne({x: 1}, {$inc: {y: 1}});
session.commitTransaction();
注意两点:
- 不能在事务外对同一个集合做写操作,否则可能破坏快照一致性(MongoDB 不阻止,但语义失效)
-
readConcern: {level: "snapshot"}必须在startTransaction()里传入,不能后续用session.setReadConcern()补设 - 事务内所有读都自动继承该快照时间点,无需每条查询重复设置
snapshot 与 majority readConcern 的关键区别
很多人以为 readConcern="majority" 就够用了,但它只保证读到“已被多数节点确认提交”的数据,不保证事务间无幻读或可重复读。而 "snapshot" 在事务中提供真正意义上的快照隔离(SI),比如:
- 事务 A 读取文档 X 后,事务 B 修改并提交 X,事务 A 再次读 X 仍看到原值(可重复读)
- 事务 A 查询
{status: "pending"}得到 5 条,事务 B 插入一条新 pending 文档并提交,事务 A 再查仍是 5 条(无幻读) - 这背后依赖 WiredTiger 的多版本并发控制(MVCC)和 oplog 时间戳对齐,所以仅限 4.0+ 副本集(非分片集群)或 4.2+ 分片集群
性能代价明显:每次 snapshot 事务都需要在内存中维护一个一致的时间戳视图,高并发长事务会增加存储引擎压力。如果业务只需要避免脏读,"majority" 更轻量。
分片集群下 snapshot 的限制更严格
在分片集群中启用 readConcern="snapshot",不仅要求每个分片是满足 majority 写的副本集,还要求整个集群开启 enableShardingSnapshotReads(4.2+ 默认关闭)。未开启时,即使事务内设了 snapshot,实际行为退化为 "majority"。
开启方法是在 mongos 上执行:
sh.setShardingConfigServer({enableShardingSnapshotReads: true})
但这只是开关之一,还需确认:
- 所有分片的
minOplogEntriesPerBatch配置合理(默认值通常 OK) - config server 必须是副本集(不能是单节点),且同样满足 majority 写要求
- 跨分片事务中,
readConcern="snapshot"仅对已分片的集合有效;对未分片集合(存在于 primary shard),行为取决于该 shard 的配置
实际部署中,多数业务没走到这一步就卡在副本集配置或事务嵌套深度上了——snapshot 是个强一致性开关,不是插件式功能,打开前得先理清你的复制拓扑和写入模式。











