关于MongoDB的Write Concern

关于MongoDB的Write Concern

    • 什么是写入关注
    • 一些注意点
      • 在没有wtimeout的情况下在副本集上设置写入关注会导致写入无限期地阻塞
      • 即使使用w:majority,也可能会丢失数据
      • 设置j:true时将w设为0并不会提高写入性能
    • 参考资料

什么是写入关注

从MongoDB的文档中我们可以看到写入关注(Write Concern) 定义为“从MongoDB请求对standalone mongod或副本集或分片集群进行写入操作的确认级别”。

简单来说,写入关注表明了对MongoDB的写入操作传递的“持久性”。

写入关注的主要参数如下:

{ w: <value>, j: <boolean>, wtimeout: <number> }

其中

  • w 可以是整数(如,1,2,3等) 或者“majority” ,它表示必须承认写入的成员数量。 默认值为1。
  • j 请求写入在写入磁盘日志后而不仅仅是系统内存时进行确认。 默认情况下未指定。
  • wtimeout指定应用写入问题的超时。 默认情况下未指定。

使用的方法如下:

db.inventory.insert(
    { name: "abcdxyz", qty : 100, category: "Clothing" },
    { writeConcern: { w: 2, j: true, wtimeout: 5000 } }
)

上面例子中的写入关注表示:当’副本集的至少2个成员已经在5000毫秒内将其写入其journals或返回错误’时,确认此写入。
假如选项的写入关注值是***majority***时,表示“请求确认写入操作已传播到大多数投票节点,包括主要节点”。
而MongoDB的复制是通过Secondary不断拉取oplog并重放来实现的,并不是Primary主动将写入同步给Secondary,那么Primary是如何确认数据已成功写入到大多数节点的?具体步骤如下:

  • Client向Primary发起请求,指定writeConcern为{w: “majority”},Primary收到请求,本地写入并记录写请求到oplog,然后等待大多数节点都同步了这条/批oplog(Secondary应用完oplog会向主报告最新进度)。
  • Secondary拉取到Primary上新写入的oplog,本地重放并记录oplog。为了让Secondary能在第一时间内拉取到主上的oplog,find命令支持一个awaitData的选项,当find没有任何符合条件的文档时,并不立即返回,而是等待最多maxTimeMS(默认为2s)时间看是否有新的符合条件的数据,如果有就返回;所以当新写入oplog时,备立马能获取到新的oplog。
  • Secondary上有单独的线程,当oplog的最新时间戳发生更新时,就会向Primary发送replSetUpdatePosition命令更新自己的oplog时间戳。
  • 当Primary发现有足够多的节点oplog时间戳已经满足条件了,向客户端发送确认。

一些注意点

在没有wtimeout的情况下在副本集上设置写入关注会导致写入无限期地阻塞

如果写入关注值是***majority***时,大多数“投票节点”都要求确认。请注意,“如果未指定wtimeout选项且写入关注程度无法实现,则写入操作将被无限期地阻塞。 “

这可能会产生意想不到的后果,例如,考虑2 + 1副本集(即主要副本,辅助副本和仲裁者)。如果您的唯一只读副本出现故障,则所有写入关注w选项为“多数”的写操作将无限期阻塞。如果将w选项设置为2,则会发生相同的情况。另一个极端示例是3 + 2副本集(主要,2个辅助和2个仲裁,而不是推荐的配置)。即使单个数据节点不可用,所有“多数”写入也将阻止,因为在这种情况下,多数是3。

缓解此问题的最简单方法是始终指定wtimeout值,以便在无法强制执行写入关注时查询可以超时。但是,如果发生此类超时错误,MongoDB不会在超时发生之前撤消已成功写入某些成员的操作。

目前还没有设置来确保写入到达当前可访问的大多数节点,因此请注意根据拓扑关系,所需的持久性和可用性设置写入关注度w的值。

即使使用w:majority,也可能会丢失数据

看起来直观的是,一旦大多数投票成员确认了写入,其耐用性就得到了保证。但事实并非如此!请记住,当未指定j选项时,在写入内存后立即确认写入。

因此这样的写入还是有可能会丢失,比如一旦发生的断电,但这些数据还没被写入磁盘中。

为了确保写入的持久性,最好不要关闭数据库上的日记功能并将j选项设置为true。事实上,在启动MongoDB 3.6时,使用WiredTiger存储引擎的副本集成员不推荐使用–nojournal标志。

如果w值为“w:majority”且未在副本集上指定j选项,则确切的持久性行为取决于副本集配置writeConcernMajorityJournalDefault的值。设置为true时(以及启用日记功能时),它会在写入大多数投票成员的日记帐后确认写入。

另外:即使启用了日记功能,如果在commitIntervalMs持续时间内发生中断,你的写入仍可能在MMAPv1存储引擎上丢失。另一方面,WiredTiger存储引擎在收到j选项设置为true的写入时强制同步日志文件。而且,即使j设置为false,只有当大多数数据节点同时崩溃时,对最新的基于WiredTiger的部署的确认“多数”写入才会丢失。

设置j:true时将w设为0并不会提高写入性能

将w选项设置为0通常是为了以“一劳永逸”的方式写入数据库 - 当你对数据库基础结构有相当大的信心时,更关心延迟而不是每次写入的持久性。 但是,如果将j选项设置为true,则将有效地覆盖w选项,因为数据库将确保在返回之前将写入写入磁盘日志。

参考资料

MongoDB Write Concern: 3 Must-Know Caveats
MongoDB writeConcern原理解析

你可能感兴趣的:(MongoDB,MongoDB学习随笔)