写关注
写关注描述了从MongoDB请求的对独立运行 mongod
、副本集或分片的集群的写入操作的确认级别。 在分分片的集群中, mongos
实例会将写关注(write concern)传递给分片。
注意
副本集和分片集群支持设置全局默认的写关注。未指定显式写关注的操作会继承全局默认写关注设置。有关详细信息,请参阅 setDefaultRWConcern
。
要了解有关为 MongoDB Atlas 中托管的部署设置写关注的更多信息,请参阅使用 MongoDB Atlas 构建弹性应用程序
写关注说明
写关注可包括以下字段:
{ w: <value>, j: <boolean>, wtimeout: <number> }
w
选项
w
选项会请求确认写入操作已传播到指定数量的 mongod
实例或带有指定标记的 mongod
实例。如果写关注缺少 w
字段,MongoDB 则会将 w
选项设为默认写关注。
注意
如果使用 setDefaultRWConcern
来设置默认写关注,则须指定 w
字段值。
通过使用 w
选项,可使用以下 w: <value>
写关注:
值 | 说明 |
---|---|
要求确认计算得出的多数承载数据的有投票权成员已将更改持久写入其本地oplog 。然后,成员在从本地 oplog 读取更改时异步应用更改。 在版本 8.0 中进行了更改:MongoDB 不会像以前的版本那样,在确认写入之前等待成员应用更改。 副本集中有数据投票权的节点是主节点和 有关详细信息,请参阅 { w: "majority" } 写入后读取。
示例,考虑一个具有3 个投票成员、主节点-从节点-从节点 (PSS) 的副本集。对于此副本集,计算出的多数为 2,并且写入必须传播到主节点 (primary node in the replica set)节点和一个从节点的从节点(secondary node from replica set) ,以向客户端确认写关注(write concern)。 大于 0 延迟的从节点在所配置的 在写入操作返回并向客户端发送 如果您为多文档事务指定
| |
要求确认写入操作已传播到指定数量的
例如,有一 3 成员副本集,其中包含 1 个主节点和 2 个从节点。指定 隐藏、延迟和优先级 0成员可以确认 延迟的从节点在所配置的
| |
要求确认写入操作已传播到满足 如果自定义写关注仅要求主节点进行确认,且在将写入操作复制到任一从节点之前主节点便已退出,则可回滚数据。
|
j
选项
j
选项会要求 MongoDB 确认写入操作已写入磁盘日志。
注意
将包含
j: true
的写关注指定给正在运行但未记录日志的mongod
实例会产生错误。如果已启用日志功能,
w: "majority"
则可能表示j: true
。writeConcernMajorityJournalDefault
副本集配置设置决定了此行为。详情请参阅确认行为。包含或暗示
j: true
的写关注会导致日志立即同步。请参阅日志记录过程。
wtimeout
此选项指定写关注的时间限制(以毫秒为单位)。wtimeout
只适用于w
值大于 1
的情况。
wtimeout
即使所需写关注最终会成功,也会导致写入操作在达到指定限制后返回一个错误。当这些写入操作返回时,MongoDB不会撤消在写关注超过 wtimeout
时间限制之前已执行的成功数据修改。
如果未指定 wtimeout
选项且写关注的级别无法实现,写入操作则会无限期阻塞。将 wtimeout
值指定为 0
等同于不带 wtimeout
选项的写关注。
隐式默认写关注
从 MongoDB 5.0 开始,隐式默认写关注为 w: majority
。然而,针对包含仲裁节点的部署则有特殊考虑:
副本集的投票多数是 1 加投票成员数量的一半,四舍五入。如果数据承载投票成员的数量不超过投票多数,则默认写关注为
{ w: 1 }
。在所有其他场景中,默认写关注为
{ w: "majority" }
。
具体来说,MongoDB 使用以下公式来确定默认写关注:
if [ (#arbiters > 0) AND (#non-arbiters <= majority(#voting-nodes)) ] defaultWriteConcern = { w: 1 } else defaultWriteConcern = { w: "majority" }
例如,考虑以下部署以及各自的默认写关注:
Non-Arbiters | 仲裁节点 | 投票节点 | 多数投票节点 | 隐式默认写关注 |
---|---|---|---|---|
2 | 1 | 3 | 2 |
|
4 | 1 | 5 | 3 |
|
在第一个示例中:
有 2 个非仲裁节点和 1 个仲裁节点,共有 3 个投票节点。
多数投票节点(1 加 3 的一半,四舍五入)为 2。
非仲裁节点的数量 (2) 等于多数投票节点 (2),导致隐式写关注为
{ w: 1 }
。
在第二个示例中:
共有 5 个投票节点,其中有 4 个非仲裁节点和 1 个仲裁节点。
多数投票节点(1 加 5 的一半,四舍五入)为 3。
非仲裁节点的数量 (4) 大于多数投票节点 (3),导致隐式写关注为
{ w: "majority" }
。
确认行为
w 选项和 j 选项决定 mongod
实例确认写入操作的时间。
独立运行的实例
独立 mongod
在向内存中应用写入操作后或在写入磁盘上日志后,会确认该写入操作。下表列出独立实例的确认行为以及相关的写关注:
j 未指定 | j:true | j:false | |
---|---|---|---|
| inMemory | On-disk journal | inMemory |
| 磁盘日志(如果与日记一起运行) | On-disk journal | inMemory |
注意
将 writeConcernMajorityJournalDefault
设为 false
时,MongoDB 不会等待 w: "majority"
写入磁盘日志后才确认写入操作。因此,"majority"
写入操作可能会在给定副本集中的大多数节点出现短暂丢失时(例如,崩溃和重启时)进行回滚。
副本集
指定给 w 的值决定了在返回成功之前必须确认写入的副本集成员数。对于每个有资格的副本集成员,j 选项决定了该成员引在向内存应用写入操作之后还是写入磁盘上日志之后确认写入操作。
w: "majority"
副本集的任一承载数据的有投票权成员均可参与对
"majority"
写入操作进行写入确认。下表列出了该成员何时可根据 j 值来确认写入操作:
j
未指定确认取决于
writeConcernMajorityJournalDefault
的值:如果为
true
,则确认时要求对磁盘上日志 (j: true
) 进行写入操作。writeConcernMajorityJournalDefault
默认为true
如果为
false
,则确认需要在内存中进行写入操作(j: false
)。
j: true
确认时要求对磁盘上日志进行写入操作。
j: false
确认要求在内存中进行写入操作。
通常,如果设立了
j: false
,则无需将操作写入磁盘上日志。 但是,如果设置了writeConcernMajorityJournalDefault: true
,则即使设立了j: false
,也需要设立操作写入日志。如果设立了
j: false
和writeConcernMajorityJournalDefault: true
,则写入操作将异步写入日志。在将日志刷新到磁盘之前,设立了
w: majority
的写入不会被确认为完成。w: majority
无论j
设置如何,写入操作都会等待"majority"
读取快照完成。 这是因为,如果设立了writeConcernMajorityJournalDefault: true
,则多数读取快照基于多数日志写入。写入操作向客户端应用程序返回并向
w: majority
确认后,如果设立了majority
读关注(read concern),则应用程序可以读取写入结果。
有关行为详情,请参阅
w: "majority"
行为。w: <number>
副本集的任一承载数据的成员均可参与 w: <数量> 写入操作的写入确认。
下表列出了该成员何时可根据 j 值来确认写入操作:
j
未指定确认要求在内存中进行写入操作 (
j: false
)。j: true
确认时要求对磁盘上日志进行写入操作。
j: false
确认要求在内存中进行写入操作。
注意
已隐藏、已延迟和优先级为 0 的节点可确认 w: <number>
写入操作。
延迟的从节点在所配置的 secondaryDelaySecs
之前无法返回写入确认。
在 { w: "majority" } 写入后读取
从MongoDB 8.0开始, { w: "majority" }
写入会在大多数承载数据的节点持久写入 oplog 条目后返回确认。然后,节点在从本地 oplog 读取更改时异步应用这些更改。在早期版本中,MongoDB 会等到节点应用写入后才返回确认。
在 { w: "majority" }
写入返回确认后,立即对从节点进行查询,可能会在从节点应用写入更改之前从集合中读取数据。
如果您的应用程序从辅助数据库读取并需要立即访问在 { w: "majority" }
写入中所做的更改,请在因果一致的会话中运行这些操作。
更多信息
因果一致的会话和写关注
使用因果一致的客户端会话时,只有在以下情况下,客户端会话才能保证因果一致性:
关联的读取操作使用
"majority"
读关注,而关联的写入操作使用
"majority"
写关注。
有关详细信息,请参阅因果一致性。
w: "majority"
行为
将
writeConcernMajorityJournalDefault
设为false
时,MongoDB 不会等待w: "majority"
写入磁盘日志后才确认写入操作。因此,"majority"
写入操作可能会在给定副本集中的大多数节点出现短暂丢失时(例如,崩溃和重启时)进行回滚。members[n].votes
大于0
的已隐藏、已延迟和优先级为 0 的节点可确认"majority"
写入操作。延迟的从节点在所配置的
secondaryDelaySecs
之前无法返回写入确认。
从 MongoDB 5.0 开始,处于
STARTUP2
状态的副本集节点不参与对写入操作的多数节点确认。
数据库不支持写关注local
本地数据库不支持写关注。MongoDB 会静默忽略为针对本地数据库中集合的操作所配置的全部写关注。
计算写关注的 majority
提示
rs.status()
返回 writeMajorityCount
字段,其中包含计算出的多数性数量。
写关注的多数 "majority"
会按以下值中较小的值来计算:
所有有投票权成员(包括仲裁节点)的 majority 与
所有承载数据的有投票权成员的数量。
警告
如果计算出的 majority 数值等于所有承载数据的投票节点(例如有 3-节点的“主节点-从节点-仲裁节点”部署),写关注 "majority"
可能会超时,或在承载数据的投票节点关闭或无法访问时永不进行确认。如果可能,请使用承载数据的投票节点而不是仲裁节点。
例如,考虑:
具有 3 个投票成员的副本集,即主节点-从节点-从节点 (P-S-S):
所有有投票权成员的 majority 为 2。
所有承载数据的有投票权成员的数量为 3。
The calculated majority is 2, the minimum of 2 and 3. The write must propagate to the primary and one of the secondaries to acknowledge the write concern"majority"
to the client.具有 3 个有投票权成员(即,主节点-从节点-仲裁节点 (P-S-A))的副本集
所有有投票权成员的 majority 为 2。
所有承载数据的投票成员的数量为 2。
The calculated majority is 2, the minimum of 2 and 2. Since the write can only be applied to data-bearing members, the write must propagate to the primary and the secondary to acknowledge the write concern"majority"
to the client.提示
避免将
"majority"
写关注与 (P-S-A) 或其他要求所有数据承载投票成员都可用来确认写入的拓扑一起使用。希望使用"majority"
写关注实现持久性保证的客户应改为部署不要求所有数据承载投票成员都可用的拓扑(例如P-S-S)。
警告
请勿在副本集中部署多个仲裁节点。请参阅有关多个仲裁节点的问题。
要将仲裁节点添加到现有副本集:
通常,如果副本集中承载数据的成员少于或等于两个,则可能需要先为副本集设置集群范围的写关注(write concern)。
请参阅集群范围的写关注(write concern),详细了解为什么可能需要设置集群范围的写关注。
在使用具有一个仲裁节点的新副本集之前,您不需要更改集群范围的写关注(write concern)。
写关注来源
从 4.4 版本开始,MongoDB 会跟踪写关注 provenance
,而后者表示特定写关注的来源。您可能会在 getLastError
指标中看到 provenance
、写关注错误对象和 MongoDB 日志。
下表显示了可能的写关注 provenance
值及其重要性:
来源 | 说明 |
---|---|
| 应用程序中指定了写关注。 |
| 写入关注源自自定义的默认值。请参阅 |
| 写关注源自副本集的 |
| 在没有所有其他写入关注规范的情况下,写入关注源自服务器。 |
写关注与提交法定人数对比
索引构建使用提交法定人数。
写入操作使用写关注。
集群中的每个承载数据的节点均为一个有投票权成员。
提交法定人数指定了必须准备多少个承载数据的有投票权节点,或是哪些有投票权节点(包括主节点)来提交同步索引构建。主节点才会执行提交。
写关注是指确认写入操作已传播到指定数量的实例的级别。
在版本 8.0 中进行了更改:提交法定人数指定了在主节点提交索引构建之前必须有多少个节点准备好完成索引构建。相反,当主节点已提交索引构建时,写关注则指定了在此命令返回成功之前有多少个节点必须复制索引构建操作日志条目。
在以前的版本中,当主节点提交索引构建时,写关注会指定在此命令返回成功之前有多少个节点必须完成索引构建。