目录
进入MongoDB中文手册(4.2版本)目录
readConcern选项使您可以控制从副本集和副本集分片读取的数据的一致性和隔离性。
通过有效使用 写策略(write concerns)和读策略(read concerns),您可以适当地调整一致性保证和可用性保证的级别,例如等待更强的一致性保证(consistency guarantees),或者放宽一致性要求以提供更高的可用性。
更新的MongoDB驱动程序为MongoDB 3.2或更高版本支持指定读策略。
1 读策略级别(Read Concern Levels)
提供以下已读策略级别:
级别 | 描述 |
---|---|
“local” | 该查询从实例返回数据,但不保证该数据已被写入大多数副本集成员(即可能会回滚)。 默认为: * 从主节点(primary)读取 * 如果读取与因果一致的会话(causally consistent sessions)相关联,则从次节点(secondaries)读取。 可用性: 读策略的local可用于具有或不具有因果一致的会话和事务。 有关更多信息,请参见"local"参考页。 |
“available” | 该查询从实例返回数据,但不保证该数据已被写入大多数副本集成员(即可能会回滚)。 默认为: 如果读取与因果一致的会话不相关,则从次节点(secondaries)读取。 可用性: 读策略的available是无法用于因果关系是一致的会话和事务。 对于分片群集,"available"读策略提供了各种读策略中可能的最低延迟读取。但是,这是以牺牲一致性为代价的,因为从分片集合中进行读取时,“available"读策略可能会返回孤儿文档(orphaned documents)。为了避免在从分片集合中读取时返回孤儿文档的风险,请使用其他读取策略,例如读取策略 “local”。 有关更多信息,请参见"available” 参考页。 3.6版的新功能。 |
“majority” | 该查询返回大多数副本集成员已确认的数据。读取操作返回的文档即使在发生故障的情况下也是持久化的。 为了满足读策略的“majority”,副本集成员在多数提交点(the majority-commit point)返回其内存视图(in-memory view)的数据。这样,读策略 “majority"在性能成本上可与其他读策略相媲美。 可用性: * 读策略"majority"可用于具有或不具有因果一致的会话和事务。 * 您可以在部署具有三名成员的主次仲裁器(PSA:primary-secondary-arbiter)架构时禁用读策略"majority”。但是,这对变更流(change streams)(在MongoDB 4.0和更早版本中)和分片群集上的事务有影响。有关更多信息,请参见禁用多数读策略(Disable Read Concern Majority)。 要求: 要使用的读策略 “majority”,副本集必须使用WiredTiger存储引擎。 注意: 对于多文档事务中的操作,仅当事务以写策略“majority”提交时,读策略"majority"才能得以保证 。否则,读策略"majority"不能保证事务中读取的数据。 有关更多信息,请参见"majority" 参考页。 |
“linearizable” | 该查询返回的数据反映了在读取操作开始之前完成的所有成功的多数确认的写入数据。查询可能会等待并发执行的写操作传播到大多数副本集成员,然后返回结果。 如果大多数副本集成员崩溃并在读取操作后重新启动,则如果将writeConcernMajorityJournalDefault设置为默认状态true,则读取操作返回的文档将是持久化的。 如果writeConcernMajorityJournalDefault设置为false,MongoDB的不会在写操作确认之前等待w: “majority"写操作被写入到磁盘上的日志中。这样,在给定副本集中的大多数节点发生瞬时丢失(例如崩溃和重新启动)的情况下,majority写操作可能会回滚。 可用性: * 读策略"linearizable"是无法用于因果关系是一致的会话和事务。 * 您可以仅为主节点上的读操作指定读策略"linearizable”。 您不能将$out或$merge阶段与阅策略"linearizable"结合使用。也就是说,如果您为db.collection.aggregate()指定了读策略"linearizable" ,则不能在管道中包括任何一个阶段。 要求: 读策略"linearizable"保证仅在读取操作指定唯一标识单个文档的查询过滤器时才适用。 提示: 万一大多数数据承载成员不可用,总是将maxTimeMS和读策略"linearizable"一起使用。 maxTimeMS确保操作不会无限期地阻塞,并确保如果读策略无法执行,则该操作将返回错误。 有关更多信息,请参见"linearizable" 参考页。 |
“snapshot” | 如果事务不是因果一致的会话的一部分,则在使用写策略"majority"提交事务时,事务的操作将确保从多数提交的数据快照中读取数据。 如果事务是因果一致的会话的一部分,则在在使用读策略"majority"提交事务时,则可以保证事务操作从多数提交数据的快照中读取数据,该快照提供了与紧接事务开始之前的操作的因果一致性。 可用性: *读策略"snapshot"仅可用于多文档事务。 *对于分片群集上的事务,如果事务中的任何操作涉及已禁用读策略“majority”的分片,则不能对事务使用读策略"snapshot"。事务只能使用读策略"local"或"majority"。 |
无论读策略级别如何,节点上的最新数据都可能不是系统中最新版本的数据。
有关每个阅读策略级别的更多信息,请参见:
2 读策略的支持
2.1 读策略选项
对于不在多文档事务中的操作,可以将读策略级别指定为支持读策略的命令和方法的选项:
readConcern: { level: <level> }
要指定mongo shell的db.collection.find()方法的读策略级别,请使用cursor.readConcern()方法:
db.collection.find().readConcern(<level>)
2.2 事务和可用的读策略
对于多文档事务,可以在事务级别而不是在单个操作级别设置读策略。事务级别中的操作将使用事务的读策略。事务内部将忽略在集合和数据库级别设置的任何读策略。如果显式指定了事务级别的读策略,则在事务内部也将忽略客户端级别的读策略。
重要
不要为单个操作明确设置读策略。要设置事务的读读策略,请参阅 读策略/写策略/读参考。
您可以在事务开始时设置读策略:
- 对于多文档事务,可用读策略级别 “snapshot”,"local"和 “majority”;
- 多文档事务中的写入命令可以支持事务级别的读策略。
如果未在事务开始时指定,则事务将使用会话级别的读策略;如果未设置,则使用客户端级别的读策略。
有关更多信息,请参见事务读策略。
2.3 因果一致性和读策略
读策略级别"local"和 “majority"可用于因果一致会话的操作。但是,为了保证因果一致性,必须使用"majority”。有关详细信息,请参见因果一致性。
如果多文档事务与因果一致的会话相关联,则该事务也可以使用"snapshot"。
2.4 支持读策略的操作
以下操作支持读策略:
重要
要为事务中的操作设置读策略,请在事务级别(而不是在单个操作级别)设置读策略。不要为事务中的各个操作明确设置读策略。有关更多信息,请参见 事务和读策略。
命令/方法 | “local” | “available” | “majority” | “snapshot” | “linearizable” |
---|---|---|---|---|---|
count | ✓ | ✓ | ✓ | ✓ | |
distinct | ✓ | ✓ | ✓ | ✓ | ✓ |
find | ✓ | ✓ | ✓ | ✓ | ✓ |
db.collection.find() 使用cursor.readConcern() | ✓ | ✓ | ✓ | ✓ | ✓ |
geoSearch | ✓ | ✓ | ✓ | ✓ | ✓ |
getMore | ✓ | ✓ | |||
aggregate db.collection.aggregate() | ✓ | ✓ | ✓ | ✓ | ✓ |
Session.startTransaction() | ✓ | ✓ | ✓ |
- 您不能将$out或$merge阶段与读策略"linearizable"结合使用。也就是说,如果您为 db.collection.aggregate()指定了读取关注"linearizable",则不能在管道中包括任何一个阶段。
- 读策略"snapshot"仅适用于多文档事务。在事务中,不能在分片集合上使用distinct命令或其帮助程序。
如果是多文档事务的一部分,则以下写操作也可以接受读策略:
重要
要为事务中的操作设置读策略,请在事务级别(而不是在单个操作级别)设置读策略。
命令 | “local” | “available” | “majority” | “snapshot” | “linearizable” |
---|---|---|---|---|---|
delete db.collection.deleteMany() db.collection.deleteOne() db.collection.remove() | ✓ | ✓ | |||
findAndModify db.collection.findAndModify() db.collection.findOneAndDelete() db.collection.findOneAndReplace() db.collection.findOneAndUpdate() | ✓ | ✓ | |||
insert db.collection.insert() db.collection.insertOne() db.collection.insertMany() | ✓ | ✓ | |||
update db.collection.update() db.collection.updateMany() db.collection.updateOne() db.collection.replaceOne() | ✓ | ✓ |
- 读策略"snapshot"只对多文档事务可用,对于事务级别,可以设置事务的读策略。支持"snapshot"的操作对应于事务中可用的CRUD(增删改查)操作。有关更多信息,请参见 事务和读策略。
3 注意事项
3.1 读自己写入的数据
在版本3.6中更改。
从MongoDB 3.6开始,如果写请求确认,则可以使用因果一致的会话来读取自己的写入。
在MongoDB 3.6之前,您必须发出具有写策略{ w: “majority” }的写入操作, 然后对读取操作使用读策略"majority"或"linearizable",以确保单个线程可以读取自己的写入数据。
3.2 根据顺序实时读取
结合写策略"majority", 读策略"linearizable"使多个线程可以在单个文档上执行读写操作,就好像单个线程实时执行了这些操作一样。也就是说,这些读写时序可以认为是线性的。
3.3 性能比较
不同于读策略"majority","linearizable"会与次节点成员确认读操作正在从主节点进行读取,主节点能够用写策略{ w: “majority” }确认写操作。因此,使用读策略"linearizable"的读操作可能比使用读策略"majority"或"local"的读慢得多 。
万一大多数数据承载成员不可用,总是将maxTimeMS与读策略"linearizable"一起使用。maxTimeMS确保操作不会无限期地阻塞,而是确保如果无法执行读策略,则该操作将返回错误。
例如:
db.restaurants.find( { _id: 5 } ).readConcern("linearizable").maxTimeMS(10000)
db.runCommand( {
find: "restaurants",
filter: { _id: 5 },
readConcern: { level: "linearizable" },
maxTimeMS: 10000
} )
- 在某些情况下,副本集中的两个节点可能会短暂地认为它们是主要节点,但至多其中一个节点将能够完成写策略{ w: “majority” }的写操作。可以完成{ w: “majority” }的写操作的节点是当前主节点,另一个节点是以前的主节点,由于网络分区,该主节点尚未意识到其降级。发生这种情况时,尽管请求读取新的主节点,但连接到原来的主节点的客户端可能仍会观察到过时的数据 ,并且最终将回滚原来主节点的新写入数据。
3.4 读操作和afterClusterTime
3.6版的新功能。
MongoDB 3.6引入了对因果一致的会话的支持。对于与因果一致的会话相关联的读取操作,MongoDB 3.6引入了驱动程序自动设置与因果一致的会话相关联的操作的读策略选项afterClusterTime。
重要
不要为读取操作手动设置afterClusterTime。MongoDB驱动程序会针对与因果一致的会话相关联的操作自动设置此值。但是,您可以提前会话的操作时间和群集时间,以便与另一个客户端会话的操作保持一致。有关示例,请参见示例。
为了满足afterClusterTime值为T的读取请求,mongod必须在它的oplog到达时间T后执行请求。如果它的oplog尚未到达时间T,则mongod必须等待服务请求。
指定afterClusterTime的读操作返回的数据同时满足读策略级别要求和指定afterClusterTime要求。
对于与因果一致会话无关的读取操作,不会设置afterClusterTime。
进入MongoDB中文手册(4.2版本)目录