readConcern选项允许您控制从复制集和复制集碎片读取的数据的一致性和隔离属性。
通过有效地使用写关注点和读关注点,您可以适当地调整一致性和可用性保证的级别,例如等待更强的一致性保证,或者放松一致性要求以提供更高的可用性。
MongoDB驱动程序更新为MongoDB 3.2或更新后的支持指定读的关注。
阅读关注水平
以下是已阅读的关注程度:
level | Description |
---|---|
"local" | 该查询返回来自实例的数据,但不能保证数据已被写入大多数复制集成员(即可能回滚)。 默认:
可用性:Read concern local可用于具有或不具有因果一致的会话和事务。
|
"available" | 该查询返回来自实例的数据,但不能保证数据已被写入大多数复制集成员(即可能回滚)。 默认:如果读操作不与一致会话相关联,则对二级服务器执行读操作。 可用性:可用的读关注无法用于因果一致的会话和事务。 对于切分集群,“可用的”读关注点在各种读关注点中提供了尽可能低的延迟读取。然而,这是以牺牲一致性为代价的,因为从切分集合中读取时,“可用的”read关注点可以返回孤立的文档。为了避免从切分集合读取时返回孤立文档的风险,可以使用不同的读取关注点,比如读取关注点“local”。
New in version 3.6. |
"majority" | 该查询返回已被大多数复制集成员确认的数据。read操作返回的文档是持久的,即使发生故障也是如此。 为了实现读关注“多数”,复制集成员从其在多数提交点的数据内存视图中返回数据。因此,read关注点“多数”在性能成本上与其他read关注点相当。 可用性:
要求:要使用“多数”的读关心级别,副本集必须使用WiredTiger存储引擎。 提示: 对于多文档事务中的操作,只有在事务提交时写入关注“多数”时,读关注“多数”才提供它的保证。否则,“大多数”读关注点不能保证在事务中读取数据。
|
"linearizable" | 该查询返回的数据反映了在开始读操作之前完成的所有成功的、多数已确认的写操作。在返回结果之前,查询可以等待并发执行的写传播到大多数复制集成员。 如果您的大多数复制集成员在读操作之后崩溃并重新启动,那么如果writeConcernMajorityJournalDefault设置为true的默认状态,那么读操作返回的文档将是持久的。 当writeConcernMajorityJournalDefault设置为false时,MongoDB不会在确认写操作之前等待w:“majority”写操作被写到磁盘上的日志中。因此,如果给定副本集中的大多数节点发生暂时丢失(例如崩溃和重新启动),大多数写操作可能会回滚。 可用性:
您不能将$out或$merge阶段与read关注点“linearizable”一起使用。也就是说,如果指定db.collection.aggregate()的read关注点为“linearizable”,则不能在管道中包含这两个阶段。 需求:可线性化的read关注点保证只在read操作指定唯一标识单个文档的查询过滤器时才适用。 Tip 在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。unavailable.
|
"snapshot" | 如果事务不是一个偶然一致的会话的一部分,那么在事务提交时,如果事务关注“大多数”,那么事务操作就可以从大量提交数据的快照中读取数据。 如果事务是因果一致的会话的一部分,那么在事务提交时,如果事务涉及“多数”,那么事务操作将保证已经读取了多数提交数据的快照,该快照提供了与事务开始之前的操作的因果一致性。 可用性:
|
无论读取的关注级别如何,节点上的最新数据可能不会反映系统中数据的最新版本。
2.readConcern支持
2.1 Read Concern Option¶
对于不在多文档事务中的操作,您可以指定readConcern级别,作为支持read concern的命令和方法的选项:
readConcern: { level: <level> }
要为mongo shell方法db.collection.find()指定读关注级别,请使用指针. readconcern()方法:
db.collection.find().readConcern(<level>)
2.2 事务和可用的读关注点
对于多文档事务,您可以在事务级别设置read关注点,而不是在单个操作级别。事务中的操作将使用事务级读关注点。在集合和数据库级别上的任何读关注集都将在事务内部被忽略。如果显式地指定了事务级别的读关注,那么在事务内部也会忽略客户端级别的读关注。
重要:
不要显式地设置单个操作的读关注点。要设置事务的读关注,请参阅读关注/写关注/读首选项。
你可以在事务开始时设置read concern:
- 对于多文档事务,可以读取“快照”、“本地”和“多数”关注级别。
- 作为多文档事务一部分的写命令可以支持事务级别的读取。
如果在事务开始时未指定,事务将使用会话级别的读关注,如果未设置,则使用客户端级别的读关注。
2.3 因果一致的会话和可用的Read关注点
对于因果一致会话中的操作,可以使用“局部”和“多数”级别。然而,为了保证因果一致性,你必须使用“多数”。详情请参阅因果一致性。
如果一个多文档事务与一个偶然一致的会话相关联,那么该事务也可以使用“快照”。
2.4 支持读关注点的操作
以下操作支持读关注:
重要:要设置事务中操作的读关注,您需要在事务级别设置读关注,而不是在单个操作级别。不要显式地设置事务中各个操作的读关注点。
transaction. For more information, see Transactions and Read Concern.
Command/Method | "local" | "available" | "majority" | "snapshot" [3] | "linearizable" |
---|---|---|---|---|---|
count | ✓ | ✓ | ✓ | ✓ | |
distinct | ✓ | ✓ | ✓ | ✓ [2] | ✓ |
find | ✓ | ✓ | ✓ | ✓ | ✓ |
db.collection.find() via cursor.readConcern() | ✓ | ✓ | ✓ | ✓ | ✓ |
geoSearch | ✓ | ✓ | ✓ | ✓ | ✓ |
getMore | ✓ | ✓ | |||
aggregate db.collection.aggregate() | ✓ | ✓ | ✓ | ✓ | ✓ [1] |
Session.startTransaction() | ✓ | ✓ | ✓ |
[1] 您不能将$out或$merge阶段与read关注点“linearizable”一起使用。也就是说,如果指定db.collection.aggregate()的read关注点为“linearizable”,则不能在管道中包含这两个阶段。
[2]“快照”仅对多文档事务可用。在事务中,不能在切分的集合上使用不同的命令或其帮助程序。
如果是多文档事务的一部分,下面的写操作也可以接受读关注:
重要:要设置事务中操作的读关注,您需要在事务级别设置读关注,而不是在单个操作级别。
Command | "local" | "available" | "majority" | "snapshot" [3] | "linearizable" |
---|---|---|---|---|---|
✓ | ✓ | ||||
| ✓ | ✓ | |||
✓ | ✓ | ||||
✓ | ✓ |
[3] “快照”仅对多文档事务可用,对于事务,您在事务级别设置读关注。支持“快照”的操作对应于事务中可用的CRUD操作。有关更多信息,请参见事务并阅读关注点。
3. 注意事项
3.1 读取你自己写的内容
在3.6版本中进行了更改。
从MongoDB 3.6开始,如果写请求确认,您可以使用因果一致的会话来读取自己的写。
在MongoDB 3.6之前,你必须使用{w: "majority"}写关注点来发布你的写操作,然后使用"majority"或"linearizable"读关注点来进行读操作,以确保单个线程可以读它自己的写。
3.2 根据顺序实时读取
与“多数”写关注点相结合,“线性化”读关注点使多个线程能够对单个文档执行读写操作,就像一个线程实时执行这些操作一样;也就是说,这些读写的相应调度被认为是可线性化的。
3.3 性能比较
与“多数”不同,“可线性化”的读关心向次要成员确认读操作是从主成员读取的,主成员能够用{w:“多数”}写关心来确认写。因此,使用线性化读关注点的读取速度可能比使用“多数”或“局部”读关注点的读取慢得多。
在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。maxTimeMS确保操作不会无限期阻塞,而是确保如果无法满足读关注,则操作返回一个错误。
举例:
db.restaurants.find( { _id: 5 } ).readConcern("linearizable").maxTimeMS(10000)
db.runCommand( {
find: "restaurants",
filter: { _id: 5 },
readConcern: { level: "linearizable" },
maxTimeMS: 10000
} )
【4】 在某些情况下,复制集中的两个节点可能会暂时认为它们是主节点,但最多其中一个能够使用{w: "majority"} write concern完成写操作。可以完成{w: "majority"}写操作的节点是当前的主节点,其他节点是以前的主节点,还没有意识到它的降级,通常是由于网络分区。当发生这种情况时,连接到前一个主服务器的客户端可能会观察到过时的数据,尽管已经请求了read preference主服务器,并且对前一个主服务器的新写操作最终将回滚。
3.4 读取操作和集群时间
新版本3.6。
MongoDB 3.6引入了对因果一致性会话的支持。对于与因果一致性会话相关的读操作,MongoDB 3.6引入了afterClusterTime读关注选项,该选项由与因果一致性会话相关的操作的驱动程序自动设置。
重要:
不要手动设置读操作的afterClusterTime。MongoDB驱动程序会自动为与因果一致性会话相关的操作设置这个值。但是,可以提前会话的操作时间和集群时间,比如与另一个客户机会话的操作保持一致。有关示例,请参见示例。
要满足一个afterClusterTime值为T的读请求,mongod必须在它的oplog到达时间T之后执行请求。如果它的oplog没有到达时间T, mongod必须等待服务请求。
使用指定的afterClusterTime的读操作返回的数据同时满足Read关注级需求和指定的afterClusterTime需求。
对于与因果一致性会话无关的读操作,afterClusterTime未设置。
一. Read Concern "local"
带有read关注点“local”的查询返回来自实例的数据,但不能保证数据已被写入大多数复制集成员(即可能回滚)。
Read concern“local”是以下情况的默认值:
- 主读操作
- 如果读操作与因果一致的会话相关联,则对二级服务器执行读操作。
无论读取的关注级别如何,节点上的最新数据可能不会反映系统中数据的最新版本。
1.可用性
Read concern local可用于具有或不具有因果一致的会话和事务。
2. Read Concern "local"
and Transactions¶
在事务级别设置了read关注点,而不是在单个操作级别。要设置事务的读关注点,请参阅事务和读关注点。
3. 举例
考虑写入操作Write0到一个三成员副本集的时间轴:
请注意
为了简化,这个例子假设:
- Write0之前的所有写操作都已成功复制到所有成员。
- Writeprev是Write0之前的前一个写。
- 写0之后没有发生其他写操作。
Time | Event | Most Recent Write | Most Recent w: “majority” write |
---|---|---|---|
t0 | Primary applies Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t1 | Secondary1 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t2 | Secondary2 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t3 | Primary is aware of successful replication to Secondary1 and sends acknowledgement to client | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t4 | Primary is aware of successful replication to Secondary2 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t5 | Secondary1 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev |
t6 | Secondary2 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 |
然后,下面的表总结了具有“本地”读关注点的读操作在T时刻看到的数据状态。
Read Target | Time T | State of Data |
---|---|---|
Primary | After t0 | Data reflects Write0. |
Secondary1 | Before t1 | Data reflects Writeprev |
Secondary1 | After t1 | Data reflects Write0 |
Secondary2 | Before t2 | Data reflects Writeprev |
Secondary2 | After t2 | Data reflects Write0 |
二 Read Concern "available"
新版本3.6。
带有read关注点“available”的查询返回来自实例的数据,但不能保证数据已被写入大多数复制集成员(即可能回滚)。
读关注点“available”是针对次要服务器的读操作的默认值,如果读操作没有与因果一致的会话关联的话。
对于sharded集群,“available”read关注点为分区提供了更大的容忍度,因为它不会等待以确保一致性保证。也就是说,对于更新的元数据,read关注点“available”既不与shard的主服务器联系,也不与配置服务器联系。但是,这意味着如果碎片正在进行块迁移,那么具有“可用”read关注点的查询可能会返回孤立的文档。
如果碎片正在进行块迁移,则可能返回孤立的文档。
对于未切分的集合(包括独立部署或复制集部署中的集合),“本地”和“可用”读关注的行为是相同的。
无论读取的关注级别如何,节点上的最新数据可能不会反映系统中数据的最新版本。
1. Availability
可用的读关注无法用于因果一致的会话和事务。
2. 例子
考虑写入操作Write0到一个三成员副本集的时间轴:
提示:
为了简化,这个例子假设:
- Write0之前的所有写操作都已成功复制到所有成员。
- Writeprev是Write0之前的前一个写。
- 写0之后没有发生其他写操作。
Time | Event | Most Recent Write | Most Recent w: “majority” write |
---|---|---|---|
t0 | Primary 适用Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t1 | Secondary1适用write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t2 | Secondary2适用write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t3 | Primary感知到成功复制到Secondary1,并向客户机发送确认 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t4 | 主节点感知到成功复制到Secondary2 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t5 | Secondary1收到通知(通过常规的复制机制)更新其最新w:“majority”写入的快照 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev |
t6 | Secondary2收到通知(通过常规复制机制)更新其最新w:“majority”写入的快照 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 |
然后,下表总结了具有“available”read关注点的read操作在T时刻看到的数据状态。
Read Target | Time T | State of Data |
---|---|---|
Primary | After t0 | Data reflects Write0. |
Secondary1 | Before t1 | Data reflects Writeprev |
Secondary1 | After t1 | Data reflects Write0 |
Secondary2 | Before t2 | Data reflects Writeprev |
Secondary2 | After t2 | Data reflects Write0 |
三、Read Concern "majority"
对于与多文档事务无关的读操作,读关注点“多数”保证读到的数据已被大多数复制集成员确认(即读到的文档是持久的,保证不会回滚)。
对于多文档事务中的操作,只有在事务提交时写入关注“多数”时,读关注“多数”才提供它的保证。否则,“大多数”读关注点不能保证在事务中读取数据。
无论读取的关注级别如何,节点上的最新数据可能不会反映系统中数据的最新版本。
1. Performance
每个复制集成员在内存中维护一个数据在主提交点的视图;主要提交点由主节点计算。为了实现读关注点“多数”,节点从这个视图返回数据,并且在性能成本上与其他读关注点相当。
2. Availability
Read concern“majority”可用于具有或不具有因果一致的会话和事务。
您可以禁用具有三个成员的主-副-仲裁(PSA)体系结构的部署的read concern“majority”;但是,这对更改流(仅在MongoDB 4.0和更早的版本中)和分片集群上的事务有影响。有关更多信息,请参见禁用读关注多数。
3. Example
考虑写入操作Write0到一个三成员副本集的时间轴:
注意
为了简化,这个例子假设:
- Write0之前的所有写操作都已成功复制到所有成员。
- Writeprev是Write0之前的前一个写。
- 写0之后没有发生其他写操作。
Time | Event | Most Recent Write | Most Recent w: “majority” write |
---|---|---|---|
t0 | Primary applies Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t1 | Secondary1 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t2 | Secondary2 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t3 | Primary is aware of successful replication to Secondary1 and sends acknowledgement to client | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t4 | Primary is aware of successful replication to Secondary2 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t5 | Secondary1 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev |
t6 | Secondary2 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 |
然后,下面的表总结了具有“多数”读关注的读操作在T时刻看到的数据状态。
Read Target | Time T | State of Data |
---|---|---|
Primary | Before t3 | Data reflects Writeprev |
Primary | After t3 | Data reflects Write0 |
Secondary1 | Before t5 | Data reflects Writeprev |
Secondary1 | After t5 | Data reflects Write0 |
Secondary2 | Before or at t6 | Data reflects Writeprev |
Secondary2 | After t6 | Data reflects Write0 |
4. 存储引擎支持
对于WiredTiger存储引擎来说,Read concern“majority”是可用的。
提示
serverStatus命令返回存储引擎。supportsCommittedReads字段,该字段指示存储引擎是否支持“多数”读关注点。
5. Read Concern "majority"
and Transactions
请注意
您在事务级别设置了read关注点,而不是在单个操作级别。要设置事务的读关注点,请参阅事务和读关注点。
对于多文档事务中的操作,只有在事务提交时写入关注“多数”时,读关注“多数”才提供它的保证。否则,“大多数”读关注点不能保证在事务中读取数据。
6. Read Concern "majority"
and Aggregation¶
从MongoDB 4.2开始,您可以为包含$out阶段的聚合指定read关注点级别“majority”。
在MongoDB 4.0和更早的版本中,您不能包含$out阶段来使用“多数”读关心的聚合。
7. Read Your Own Writes
在3.6版本中进行了更改。
从MongoDB 3.6开始,如果写请求确认,您可以使用因果一致的会话来读取自己的写。
在MongoDB 3.6之前,你必须使用{w: "majority"}写关注点来发布你的写操作,然后使用"majority"或"linearizable"读关注点来进行读操作,以确保单个线程可以读它自己的写。
请注意
如果您使用的是除3人PSA以外的部署,则不需要禁用read concern majority。
对于三成员PSA架构,如果任何数据承载节点出现故障,缓存压力将会增加。为了防止存储缓存压力固定一个部署与PSA架构,您可以禁用读关心通过设置:
- --enableMajorityReadConcern命令行选项为false。
replication.enableMajorityReadConcern
配置文件设置为false。
要检查是否禁用了read关注点“majority”,可以在mongod实例上运行db.serverStatus()并检查存储引擎。supportsCommittedReads字段。如为假,则阅读关系“多数”被禁用。
重要的
一般来说,除非必要,避免禁用“多数”读关心。但是,如果您有一个具有主-次-仲裁(PSA)体系结构的三成员副本集,或者一个具有三成员PSA碎片的分片集群,则禁用它以防止存储缓存压力使部署无法进行。
改变流
禁用“多数”读关注会禁用对MongoDB 4.0及更早版本的更改流的支持。对于MongoDB 4.2+,禁用read concern“majority”对变更流可用性没有影响。
事务
禁用“多数”读关注会影响对切分集群上事务的支持。具体地说:
- 如果事务涉及的碎片已禁用了读关注“多数”,则事务不能使用读关注“快照”。
- 如果事务的任何读或写操作涉及到已禁用读的切分,则向多个切分写入错误的事务与“多数”有关。
但是,它不会影响复制集上的事务。对于副本集上的事务,您可以为多文档事务指定读关注“多数”(或“快照”或“本地”),即使已禁用读关注“多数”。
四、Read Concern "linearizable"
新版本3.4。
该查询返回的数据反映了在开始读操作之前完成的所有成功的、多数已确认的写操作。在返回结果之前,查询可以等待并发执行的写传播到大多数复制集成员。
如果您的大多数复制集成员在读操作之后崩溃并重新启动,那么如果writeConcernMajorityJournalDefault设置为true的默认状态,那么读操作返回的文档将是持久的。
当writeConcernMajorityJournalDefault设置为false时,MongoDB不会在确认写操作之前等待w:“majority”写操作被写到磁盘上的日志中。因此,如果给定副本集中的大多数节点发生暂时丢失(例如崩溃和重新启动),大多数写操作可能会回滚。
您可以仅为主节点上的读操作指定可线性化的读关注点。
可线性化的read关注点保证只在read操作指定唯一标识单个文档的查询筛选器时应用。
提示
在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。maxTimeMS确保操作不会无限期阻塞,而是确保如果无法满足读关注,则操作返回一个错误。
1. 有原因地一致的会话
Read concern linearizable不能用于因果一致的会话。
2. 聚合的限制
您不能将$out或$merge阶段与read关注点“linearizable”一起使用。也就是说,如果指定db.collection.aggregate()的read关注点为“linearizable”,则不能在管道中包含这两个阶段。
3. Real Time Order
与“多数”写关注点相结合,“线性化”读关注点使多个线程能够对单个文档执行读写操作,就像一个线程实时执行这些操作一样;也就是说,这些读写的相应调度被认为是可线性化的。
4. Read Your Own Writes
在3.6版本中进行了更改。
从MongoDB 3.6开始,如果写请求确认,您可以使用因果一致的会话来读取自己的写。
在MongoDB 3.6之前,你必须使用{w: "majority"}写关注点来发布你的写操作,然后使用"majority"或"linearizable"读关注点来进行读操作,以确保单个线程可以读它自己的写。
5. 性能比较
与“多数”不同,“可线性化”的读关心向次要成员确认读操作是从主成员读取的,主成员能够用{w:“多数”}写关心来确认写。因此,使用线性化读关注点的读取速度可能比使用“多数”或“局部”读关注点的读取慢得多。
在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。maxTimeMS确保操作不会无限期阻塞,而是确保如果无法满足读关注,则操作返回一个错误。
举例:
db.restaurants.find( { _id: 5 } ).readConcern("linearizable").maxTimeMS(10000)
db.runCommand( {
find: "restaurants",
filter: { _id: 5 },
readConcern: { level: "linearizable" },
maxTimeMS: 10000
} )
在某些情况下,复制集中的两个节点可能会暂时认为它们是主节点,但最多其中一个能够使用{w: "majority"} write concern完成写操作。可以完成{w: "majority"}写操作的节点是当前的主节点,其他节点是以前的主节点,还没有意识到它的降级,通常是由于网络分区。当发生这种情况时,连接到前一个主服务器的客户端可能会观察到过时的数据,尽管已经请求了read preference主服务器,并且对前一个主服务器的新写操作最终将回滚。
五、Read Concern "majority"
对于与多文档事务无关的读操作,读关注点“多数”保证读到的数据已被大多数复制集成员确认(即读到的文档是持久的,保证不会回滚)。
对于多文档事务中的操作,只有在事务提交时写入关注“多数”时,读关注“多数”才提供它的保证。否则,“大多数”读关注点不能保证在事务中读取数据。
无论读取的关注级别如何,节点上的最新数据可能不会反映系统中数据的最新版本。
1. Performance
每个复制集成员在内存中维护一个数据在主提交点的视图;主要提交点由主节点计算。为了实现读关注点“多数”,节点从这个视图返回数据,并且在性能成本上与其他读关注点相当。
2. Availability
Read concern“majority”可用于具有或不具有因果一致的会话和事务。
您可以禁用具有三个成员的主-副-仲裁(PSA)体系结构的部署的read concern“majority”;但是,这对更改流(仅在MongoDB 4.0和更早的版本中)和分片集群上的事务有影响。有关更多信息,请参见禁用读关注多数。
3. 例子
考虑写入操作Write0到一个三成员副本集的时间轴:
请注意
为了简化,这个例子假设:
- Write0之前的所有写操作都已成功复制到所有成员。
- Writeprev是Write0之前的前一个写。
- 写0之后没有发生其他写操作。
Time | Event | Most Recent Write | Most Recent w: “majority” write |
---|---|---|---|
t0 | Primary applies Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t1 | Secondary1 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t2 | Secondary2 applies write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Writeprev Secondary1: Writeprev Secondary2: Writeprev |
t3 | Primary is aware of successful replication to Secondary1 and sends acknowledgement to client | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t4 | Primary is aware of successful replication to Secondary2 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Writeprev Secondary2: Writeprev |
t5 | Secondary1 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Writeprev |
t6 | Secondary2 receives notice (through regular replication mechanism) to update its snapshot of its most recent w: “majority” write | Primary: Write0 Secondary1: Write0 Secondary2: Write0 | Primary: Write0 Secondary1: Write0 Secondary2: Write0 |
然后,下面的表总结了具有“多数”读关注的读操作在T时刻看到的数据状态。
Read Target | Time T | State of Data |
---|---|---|
Primary | Before t3 | Data reflects Writeprev |
Primary | After t3 | Data reflects Write0 |
Secondary1 | Before t5 | Data reflects Writeprev |
Secondary1 | After t5 | Data reflects Write0 |
Secondary2 | Before or at t6 | Data reflects Writeprev |
Secondary2 | After t6 | Data reflects Write0 |
4. Storage Engine Support
对于WiredTiger存储引擎来说,Read concern“majority”是可用的。
提示
serverStatus命令返回存储引擎。supportsCommittedReads字段,该字段指示存储引擎是否支持“多数”读关注点。
5. Read Concern "majority"
and Transactions
请注意
您在事务级别设置了read关注点,而不是在单个操作级别。要设置事务的读关注点,请参阅事务和读关注点。
对于多文档事务中的操作,只有在事务提交时写入关注“多数”时,读关注“多数”才提供它的保证。否则,“大多数”读关注点不能保证在事务中读取数据。
6. Read Concern "majority"
and Aggregation
从MongoDB 4.2开始,您可以为包含$out阶段的聚合指定read关注点级别“majority”。
在MongoDB 4.0和更早的版本中,您不能包含$out阶段来使用“多数”读关心的聚合。
7. Read Your Own Writes
在3.6版本中进行了更改。
从MongoDB 3.6开始,如果写请求确认,您可以使用因果一致的会话来读取自己的写。
在MongoDB 3.6之前,你必须使用{w: "majority"}写关注点来发布你的写操作,然后使用"majority"或"linearizable"读关注点来进行读操作,以确保单个线程可以读它自己的写。
8. Disable Read Concern Majority
适用于3人主-副-仲裁架构
如果您有一个具有主-次-仲裁(PSA)体系结构的三成员副本集,或者一个具有三成员PSA碎片的分片集群,您可以禁用read concern“majority”。
请注意
如果您使用的是除3人PSA以外的部署,则不需要禁用read concern majority。
对于三成员PSA架构,如果任何数据承载节点出现故障,缓存压力将会增加。为了防止存储缓存压力固定一个部署与PSA架构,您可以禁用读关心通过设置:
--enableMajorityReadConcern
command line option tofalse
.replication.enableMajorityReadConcern
configuration file setting tofalse
.
要检查是否禁用了read关注点“majority”,可以在mongod实例上运行db.serverStatus()并检查存储引擎。supportsCommittedReads字段。如为假,则阅读关系“多数”被禁用。
重要的
一般来说,除非必要,避免禁用“多数”读关心。但是,如果您有一个具有主-次-仲裁(PSA)体系结构的三成员副本集,或者一个具有三成员PSA碎片的分片集群,则禁用它以防止存储缓存压力使部署无法进行。
改变流
禁用“多数”读关注会禁用对MongoDB 4.0及更早版本的更改流的支持。对于MongoDB 4.2+,禁用read concern“majority”对变更流可用性没有影响。
事务
禁用“多数”读关注会影响对切分集群上事务的支持。具体地说:
- 如果事务涉及的碎片已禁用了读关注“多数”,则事务不能使用读关注“快照”。
- 如果事务的任何读或写操作涉及到已禁用读的切分,则向多个切分写入错误的事务与“多数”有关。
但是,它不会影响复制集上的事务。对于副本集上的事务,您可以为多文档事务指定读关注“多数”(或“快照”或“本地”),即使已禁用读关注“多数”。
六、Read Concern "linearizable"
新版本3.4。
该查询返回的数据反映了在开始读操作之前完成的所有成功的、多数已确认的写操作。在返回结果之前,查询可以等待并发执行的写传播到大多数复制集成员。
如果您的大多数复制集成员在读操作之后崩溃并重新启动,那么如果writeConcernMajorityJournalDefault设置为true的默认状态,那么读操作返回的文档将是持久的。
当writeConcernMajorityJournalDefault设置为false时,MongoDB不会在确认写操作之前等待w:“majority”写操作被写到磁盘上的日志中。因此,如果给定副本集中的大多数节点发生暂时丢失(例如崩溃和重新启动),大多数写操作可能会回滚。
您可以仅为主节点上的读操作指定可线性化的读关注点。
可线性化的read关注点保证只在read操作指定唯一标识单个文档的查询筛选器时应用。
提示
在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。maxTimeMS确保操作不会无限期阻塞,而是确保如果无法满足读关注,则操作返回一个错误。
1. 有原因地一致的会话
Read concern linearizable不能用于因果一致的会话。
2. 聚合的限制
您不能将$out或$merge阶段与read关注点“linearizable”一起使用。也就是说,如果指定db.collection.aggregate()的read关注点为“linearizable”,则不能在管道中包含这两个阶段。
3. Real Time Order¶
与“多数”写关注点相结合,“线性化”读关注点使多个线程能够对单个文档执行读写操作,就像一个线程实时执行这些操作一样;也就是说,这些读写的相应调度被认为是可线性化的。
4. Read Your Own Writes¶
在3.6版本中进行了更改。
从MongoDB 3.6开始,如果写请求确认,您可以使用因果一致的会话来读取自己的写。
在MongoDB 3.6之前,你必须使用{w: "majority"}写关注点来发布你的写操作,然后使用"majority"或"linearizable"读关注点来进行读操作,以确保单个线程可以读它自己的写。
5. 性能比较
与“多数”不同,“可线性化”的读关心向次要成员确认读操作是从主成员读取的,主成员能够用{w:“多数”}写关心来确认写。因此,使用线性化读关注点的读取速度可能比使用“多数”或“局部”读关注点的读取慢得多。
在大多数数据承载成员不可用的情况下,总是将maxTimeMS与可线性化的读关系一起使用。maxTimeMS确保操作不会无限期阻塞,而是确保如果无法满足读关注,则操作返回一个错误。
举例:
db.restaurants.find( { _id: 5 } ).readConcern("linearizable").maxTimeMS(10000)
db.runCommand( {
find: "restaurants",
filter: { _id: 5 },
readConcern: { level: "linearizable" },
maxTimeMS: 10000
} )
在某些情况下,复制集中的两个节点可能会暂时认为它们是主节点,但最多其中一个能够使用{w: "majority"} write concern完成写操作。可以完成{w: "majority"}写操作的节点是当前的主节点,其他节点是以前的主节点,还没有意识到它的降级,通常是由于网络分区。当发生这种情况时,连接到前一个主服务器的客户端可能会观察到过时的数据,尽管已经请求了read preference主服务器,并且对前一个主服务器的新写操作最终将回滚。
七、Read Concern "snapshot"
新版本4.0。
“快照”只适用于多文档事务。
- 如果事务不是一个偶然一致的会话的一部分,那么在事务提交时,如果事务关注“大多数”,那么事务操作就可以从大量提交数据的快照中读取数据。
- 如果事务是因果一致的会话的一部分,那么在事务提交时,如果事务涉及“多数”,那么事务操作将保证已经读取了多数提交数据的快照,该快照提供了与事务开始之前的操作的因果一致性。
1. 操作
有关接受读关注点的所有操作的列表,请参阅支持读关注点的操作。
2. 有关接受读关注点的所有操作的列表,请参阅支持读关注点的操作。
多文档事务支持读取关注点“快照”以及“本地”和“多数”。
请注意
您在事务级别设置了read关注点,而不是在单个操作级别。要设置事务的读关注点,请参阅事务和读关注点。
对于分片集群上的事务,如果事务中的任何操作涉及到已禁用了read concern“majority”的碎片,则不能对事务使用read concern“snapshot”。对于事务,您只能使用read concern“local”或“majority”。如果使用“快照”,则事务错误和中止。有关更多信息,请参见禁用阅读关注多数。
八、Write Concern
Write concern描述从MongoDB请求的写入操作到独立mongod、复制集或切分集群的确认级别。在切分的集群中,mongos实例将写关注点传递给切分。
请注意
对于多文档事务,您可以在事务级别设置写关注点,而不是在单个操作级别。不要显式地为事务中的各个写操作设置写关系。
1. 写关注规范
Write关注点可以包括以下字段:
{ w: <value>, j: <boolean>, wtimeout: <number> }
- 请求确认写操作已传播到指定数量的mongod实例或具有指定标记的mongod实例的w选项。
- j选项请求确认写入操作已被写入磁盘日志,
- wtimeout选项指定时间限制以防止写入操作无限期阻塞。
1.1 w选项
w选项请求确认写操作已传播到指定数量的mongod实例或具有指定标记的mongod实例。
使用w选项,以下w: <value> write concerns are available:
Value | Description |
---|---|
| Requests acknowledgment that the write operation has propagated to the specified number of
Requests acknowledgment that the write operation has propagated to the standalone
Requests no acknowledgment of the write operation. However, If you specify
Note Hidden, delayed, and priority 0 members can acknowledge Delayed secondaries can return write acknowledgment no earlier than the configured See Acknowledgment Behavior for when |
| Requests acknowledgment that write operations have propagated to the calculated majority of the data-bearing voting members (i.e. primary and secondaries with For example, consider a replica set with 3 voting members, Primary-Secondary-Secondary (P-S-S). For this replica set, calculated majority is two, and the write must propagate to the primary and one secondary to acknowledge the write concern to the client. Note Hidden, delayed, and priority 0 members with Delayed secondaries can return write acknowledgment no earlier than the configured After the write operation returns with a See Acknowledgment Behavior for when |
| Requests acknowledgment that the write operations have propagated to For an example, see Custom Multi-Datacenter Write Concerns. See Acknowledgment Behavior for when |
1.2 j选项
j选项请求MongoDB确认写入操作已经写入到磁盘上的日志。
如果j: true,请求确认在w: <value>中指定的mongod实例已写入磁盘日志。j: true本身不能保证写操作不会因为副本集主故障转移而回滚。 在版本3.2:用j: true修改后,MongoDB只在请求的成员数量(包括主成员)写入日志之后才返回。以前,在一个复制集中,j: true write concern只需要主写日志,而不管w: <value> write concern。 |
请注意
- 指定一个写关注点(包括j: true)到一个运行没有日志记录的mongod实例会产生一个错误。
- 如果启用了日志记录,w:“多数”可能意味着j:是真的。writeConcernMajorityJournalDefault复制集配置设置确定行为。有关详细信息,请参见确认行为。
1.3 超时
此选项指定写入关注的时间限制(以毫秒为单位)。wtimeout只适用于大于1的w值。
wtimeout导致写操作在指定的限制之后返回一个错误,即使所需的写关注最终会成功。当这些写操作返回时,MongoDB不会撤销在写操作超出wtimeout时间限制之前执行的成功数据修改。
如果您没有指定wtimeout选项,并且写关心的级别无法达到,那么写操作将无限期阻塞。将wtimeout值指定为0等同于不使用wtimeout选项的写关注点。
2. Acknowledgment Behavior
w选项和j选项确定mongod实例何时确认写操作。
2.1 独立的
一个独立的mongod在将写操作应用到内存中或写入到磁盘日志后确认一个写操作。下表列出了单机的确认行为和相关的写问题:
j is unspecified | j:true | j:false | |
---|---|---|---|
w: 1 | In memory | On-disk journal | In memory |
w: "majority" | On-disk journal if running with journaling | On-disk journal | In memory |
请注意
当writeConcernMajorityJournalDefault设置为false时,MongoDB不会在确认写操作之前等待w:“majority”写操作被写到磁盘上的日志中。因此,如果给定副本集中的大多数节点发生暂时丢失(例如崩溃和重新启动),大多数写操作可能会回滚。
2.2 复制集
指定给w的值决定了在返回成功之前必须确认写入的复制集成员的数量。对于每个合格的复制集成员,j选项确定该成员是在内存中应用写操作后确认写操作,还是在对磁盘日志进行写操作后确认写操作。
w:“大多数”
复制集的任何带有数据的投票成员都可以对“多数”写操作的写确认做出贡献。
下表列出了成员何时可以根据j值确认写操作:
j is unspecified | 确认取决于writeConcernMajorityJournalDefault的值::
|
---|---|
j: true | 确认需要向磁盘日志写入操作。 |
j: false | 确认需要在内存中执行写入操作。 |
请注意
当writeConcernMajorityJournalDefault设置为false时,MongoDB不会在确认写操作之前等待w:“majority”写操作被写到磁盘上的日志中。因此,如果给定副本集中的大多数节点发生暂时丢失(例如崩溃和重新启动),大多数写操作可能会回滚。
请注意
具有成员的隐藏、延迟和优先级为0的成员[n]。大于0的投票可以确认“多数”写操作。
延迟的二级服务器可以不早于配置的slaveDelay返回写应答。
w: <number>
任何数据成员的副本集可以贡献写确认w: <number>写操作。
下表列出了成员何时可以根据j值确认写操作:
j is unspecified | 确认需要在内存中执行写入操作(j: false)。 |
---|---|
j: true | 确认需要向磁盘日志写入操作。 |
j: false | 确认需要在内存中执行写入操作. |
请注意
隐藏、延迟和优先级为0的成员可以确认w: <number>写操作。
延迟的二级服务器可以不早于配置的slaveDelay返回写应答。
3.Calculating Majority for Write Concern
从版本4.2.1开始,rs.status()返回writeMajorityCount字段,该字段包含计算得到的大多数数字。
对于写关心的“多数”计算如下值中较小的值:
- 所有投票成员的多数(包括仲裁者)vs。
- 所有有数据的投票成员的数目。
警告
如果计算出的多数票数目等于所有具有数据的投票成员的数目(例如具有3个成员的主-副-仲裁服务器的部署),则写入关注“多数票”可能超时,或者如果具有数据的投票成员停机或无法联系到,则永远不会得到确认。如果可能,使用一个有数据的投票成员,而不是仲裁者。
例如,考虑:
有3个投票成员的副本集,初级-次级-次级(P-S-S):
- 所有投票成员的多数票是2票。
- 所有有数据的投票成员的数目是3。
计算出的多数是2,最小是2和3。写必须传播到主服务器和一个次服务器,以向客户端确认写关系“大多数”。
有3个投票成员的副本集,初级仲裁者(P-S-A)
- 所有投票成员的多数票是2票。
- 所有有数据的投票成员的数目是2。
计算出的多数是2,最小是2和2。由于写操作只能应用于包含数据的成员,所以写操作必须传播到主节点和次节点,以向客户端确认写关注点“大多数”。
提示
避免使用与(P-S-A)或其他拓扑有关的“多数”写操作,因为这些拓扑要求所有具有数据的投票成员都可用来确认写操作。希望使用“多数”写关注点的持久性保证的客户应该部署一个不需要所有数据支持的投票成员可用的拓扑(例如P-S-S)。