MongoDB readConcern 原理解析

    xiaoxiao2026-04-22  8

    MongoDB 可以通过 writeConcern 来定制写策略,3.2版本后又引入了 readConcern 来灵活的定制读策略。

    readConcern vs readPreference

    MongoDB 控制读策略,还有一个 readPreference 的设置,为了避免混淆,先简单说明下二者的区别。

    readPreference 主要控制客户端 Driver 从复制集的哪个节点读取数据,这个特性可方便的实现读写分离、就近读取等策略。

    primary 只从 primary 节点读数据,这个是默认设置 primaryPreferred 优先从 primary 读取,primary 不可服务,从 secondary 读 secondary 只从 scondary 节点读数据 secondaryPreferred 优先从 secondary 读取,没有 secondary 成员时,从 primary 读取 nearest 根据网络距离就近读取

    readConcern 决定到某个读取数据时,能读到什么样的数据。

    local 能读取任意数据,这个是默认设置 majority 只能读取到『成功写入到大多数节点的数据』

    readPreference 和 readConcern 可以配合使用。

    readConcern 解决什么问题?

    readConcern 的初衷在于解决『脏读』的问题,比如用户从 MongoDB 的 primary 上读取了某一条数据,但这条数据并没有同步到大多数节点,然后 primary 就故障了,重新恢复后 这个primary 节点会将未同步到大多数节点的数据回滚掉,导致用户读到了『脏数据』。

    当指定 readConcern 级别为 majority 时,能保证用户读到的数据『已经写入到大多数节点』,而这样的数据肯定不会发生回滚,避免了脏读的问题。

    需要注意的是,readConcern 能保证读到的数据『不会发生回滚』,但并不能保证读到的数据是最新的,这个官网上也有说明。

    Regardless of the read concern level, the most recent data on a node may not reflect the most recent version of the data in the system.

    有用户误以为,readConcern 指定为 majority 时,客户端会从大多数的节点读取数据,然后返回最新的数据。

    实际上并不是这样,无论何种级别的 readConcern,客户端都只会从『某一个确定的节点』(具体是哪个节点由 readPreference 决定)读取数据,该节点根据自己看到的同步状态视图,只会返回已经同步到大多数节点的数据。

    readConcern 实现原理

    MongoDB 要支持 majority 的 readConcern 级别,必须设置replication.enableMajorityReadConcern参数,加上这个参数后,MongoDB 会起一个单独的snapshot 线程,会周期性的对当前的数据集进行 snapshot,并记录 snapshot 时最新 oplog的时间戳,得到一个映射表。

    最新 oplog 时间戳snapshot状态t0snapshot0committedt1snapshot1uncommittedt2snapshot2uncommittedt3snapshot3uncommitted

    只有确保 oplog 已经同步到大多数节点时,对应的 snapshot 才会标记为 commmited,用户读取时,从最新的 commited 状态的 snapshot 读取数据,就能保证读到的数据一定已经同步到的大多数节点。

    关键的问题就是如何确定『oplog 已经同步到大多数节点』?

    primary 节点

    secondary 节点在 自身oplog发生变化时,会通过 replSetUpdatePosition 命令来将 oplog 进度立即通知给 primary,另外心跳的消息里也会包含最新 oplog 的信息;通过上述方式,primary 节点能很快知道 oplog 同步情况,知道『最新一条已经同步到大多数节点的 oplog』,并更新 snapshot 的状态。比如当t2已经写入到大多数据节点时,snapshot1、snapshot2都可以更新为 commited 状态。(不必要的 snapshot也会定期被清理掉)

    secondary 节点

    secondary 节点拉取 oplog 时,primary 节点会将『最新一条已经同步到大多数节点的 oplog』的信息返回给 secondary 节点,secondary 节点通过这个oplog时间戳来更新自身的 snapshot 状态。

    注意事项

    目前 readConcern 主要用于跟 mongos 与 config server 的交互上,参考MongoDB Sharded Cluster 路由策略 使用 readConcern 需要配置replication.enableMajorityReadConcern选项只有支持 readCommited 隔离级别的存储引擎才能支持 readConcern,比如 wiredtiger 引擎,而 mmapv1引擎则不能支持。 相关资源:MongoDB原理与实战-阿里云-张友东
    最新回复(0)