复制集使用及原理介绍

一、MongoDB 副本集概念及创建

(一)MongoDB 副本集的概念

官方概念:副本集是一组 MongoDB 的进程去维持同样的一份数据集,通过 MongoDB 的复制协议保证主备之间的数据一致性。

复制集使用及原理介绍如上图所示,MongoDB 有两种部署方式,一个是 Standalone 部署模式,另外一个 是副本级,有不同角色的节点,像 Primary 节点和 Secondary 节点。


生产环境不建议部署 Standalone 模式。

(二)使用 MongoDB 副本集的原因


关键词:可用性、拓展性、维护性


  • 可用性
    额外的副本结合高可用机制提升 MongoDB 实例可用性。


  • 扩展性
    通过 Secondary 节点配合 Driver 扩展 MongoDB 实例读能力。

  • 维护性
    通过滚动的方式 MongoDB 实例进行维护,尽量减少业务所受到的影响,比如版本升 级与可能会影响用户流量的 Compact 操作。

复制集使用及原理介绍

(三)MongoDB 副本集成员角色

副本集里面有多个节点,每个节点拥有不同的职责。


在看成员角色之前,先了解两个重要属性:

属性一Priority = 0
当 Priority 等于 0 时,它不可以被副本集选举为主,Priority 的值越高,则被选举为主 的概率更大。


属性二Vote = 0
不可以参与选举投票,此时该节点的 Priority 也必须为 0,即它也不能被选举为主。


复制集使用及原理介绍

成员角色

  • Primary:主节点,可以接受读写,整个副本集某个时刻只有一个。
  • Secondary:只读节点,分为以下三个不同类型:


    • Hidden = False:正常的只读节点,是否可选为主,是否可投票,取决于 Priority,Votes 的值;
    • Hidden = True:隐藏节点,对客户端不可见,可以参与选举,但是 Priority 必须为 0,即不能被提升为主;
    • Delayed Secondary:延迟只读节点,会延迟一定的时间(SlaveDelay 配置 决定)从上游复制增量,常用于快速回滚场景。


  • Arbiter:仲裁节点,只用于参与选举投票,本身不承载任何数据,只作为投票角色。


(四)如何获取 MongoDB 副本集


基于工具搭建测试实例


目的:业务要做线下测试,需要在本地环境搭建一个副本级或去探索新版本,比如 4.4 新增的功能。


使用工具 Mtools:


基于 mtools 部署副本集,一条命令:

mlaunch init --binarypath '/usr/local/Cellar/mongodb-community/ 4.4.0/bin' --replicaset -nodes 3 --name replset44 --dir ~/work/ mtools_data/data

执行 Mlaunch,Init 然后指定 Binarypath 还有一些副本集相关参数,Mtools 会一键 创建副本集,具体命令执行演示如下:

复制集使用及原理介绍

复制集使用及原理介绍

创建云上实例


  • MongoDB 的运维门槛较高,需要对相关原理有比较深刻的理解,才能运维好 MongoDB 副本集实例;
  • 推荐更便捷、可靠的方式:使用 MongoDB 云服务,一站式的解决方案。阿里云 MongoDB 具有社区版不具备的高级功能,如审计日志、按时间点恢复等,详情如下:

复制集使用及原理介绍


二、MongoDB 副本集使用介绍

(一)MongoDB 副本集连接方式

方式一:直接连接 Primary 节点,正常情况下可读写 MongoDB,但主节点故障切换 后,无法正常访问,如下图所示。

复制集使用及原理介绍

方式二(强烈推荐):通过高可用 Uri 的方式连接 MongoDB,当 Primary 故障切换 后,MongoDB Driver 可自动感知并把流量路由到新的 Primary 节点,如下图所示。

复制集使用及原理介绍

参考文档:https://help.aliyun.com/document_detail/44623.html


(二)MongoDB 副本集状态查看

查看副本集整体状态:rs.status()


可查看各成员当前状态,包括是否健康,是否在全量同步,心跳信息,增量同步信息, 选举信息,上一次的心跳时间等。


查看当前节点角色:DB.IsMaster()


除了当前节点角色信息,是一个更精简化的信息,也返回整个副本集的成员列表,真正 的 Primary 是谁,协议相关的配置信息等,Driver 在首次连接副本集时会发送该命令。

查看同步进度/oplog 信息:rs.printSlaveReplicationInfo()/rs.printReplicationInf

o()


共两个命令,第一个命令返回一个汇总的各 Secondary 同步延迟信息,第二个命令返 回 Oplog 大小、保留时长、 起始时间等信息。


(三)副本集的基本读写

当用客户端,比如 Mongo Shell,通过 Mongodb Uri 连接副本集实例,来执行例如 Insert,Find,Delete 等命令,和 Standalone 模式⽆差异,重点看副本集读写和 Standalone 比较特异化的地方。


(四)扩展副本集的读能力 —— ReadPreference

复制集使用及原理介绍

如上图所示,左边为一个三节点的副本集,它部署在两个数据中心,Primary 和其中 一个 Secondary 部署在 Data Center 1,另一个 Secondary 部署在 Data Center 2, 当用默认的 ReadPreference 时,直接读写 Primary 节点。如果在 Data Center2 也有 业务进程存在时,也需要读取 MongoDB 时,则需要用 ReadPreference 模式自动识别 节点的远近,读取 Data Center 2 的 Secondary。


ReadPreference 共有以下五种模式:


模式一 Primary

默认模式,直接读取主节点,更好的一致性保证


模式二 PrimaryPreferred

主节点不可⽤时,选择从从节点读取。


模式三 Secondary 只从从节点读取。


模式四 SecondaryPreferred

尽⼒从从节点读取,如果找不到可⽤的从节点,从主节点读取。


模式五 Nearest

根据客户端对节点的 Ping 值判断节点的远近,选择从最近的节点读取。


ReadPreference(读偏好)决定了读请求会访问什角色的节点,合理的 ReadPreference 可以极大地扩展副本集的读性能,降低访问延迟。


(五)控制写操作的持久性级别 —— WriteConcern

复制集使用及原理介绍

上图为 WriteConcern 标准的配置格式,包括三个子参数:


  • W: 决定了写操作返回前需要等待多少个副本集节点的确认。
  • J: 决定写操作产生的日志是否已经落盘。
  • Wtimeout:决定了写操作等待的超时时间,避免客户端一直阻塞。


下面具体演示几个 WriteConcern 配置的值。

复制集使用及原理介绍

如上图,当 W:1 时,写操作在本地执行完成后,直接向客户端返回成功,无需等待 日志(Journal)刷盘。



复制集使用及原理介绍

如上图,当 W:1,J:true 时,区别于 W:1 的主要特点在于写操作在本地执行完成后, 需要等待日志(Journal)刷盘,会增加额外延迟。

复制集使用及原理介绍


如上图,当 W: "Majority",当下发了这个写操作之后,除了需要在 Primary 节点 Apply 完成,还需要复制到其中一个 Secondary 节点去 Apply 完成,才能向 Driver 反馈 写操作成功。


在三节点副本集情况下,"Majority"相当于两个节点,等同于 W:2。


(六)控制读操作的一致性级别 —— ReadConcern

ReadConcern 有五个级别如下:


  • "Local":读操作直接读取本地最新提交的数据,返回的数据可能被回滚。
  • "Available":含义和"Local"类似,但是用于 Sharding 场景可能会返回孤⼉⽂档。
  • "Majority":读操作返回已经在多数节点确认应用完成的数据,返回的数据不会被回滚, 但可能会读到历史数据。
  • "Linearizable":读取最新的数据,且能够保证数据不会被回滚,是所谓的线性一致性, 是最高的一致性级别。
  • "Snapshot":只用于多文档事务中,和"Majority"语义类似,但额外提供真正的一致 性快照语义。

复制集使用及原理介绍

上图为一个三节点副本集,每个 Secondary 节点的复制进度不同,用 Oplog 来表示, 比如 Primary 最新节点写到 5,第一个 Secondary 节点复制到 x=4,第二个 Secondary 节点复制到 x=3,在不同的 ReadConcern 值下,Client 从不同节点读的时 候,读到的是不同版本的数据。


对于 Local 来说,总是读取最新的数据,Available 也是读取最新数据,但在分片集群 场景下两者不太一样。


在 Majority 情况下,只有 x=4 是复制到多数派节点,也就是其中两个节点。 当用 Majority 读的时候,在 Primary 上只能读到 x=4,在第一个 Secondary 上能读到 x=4, 但在第二个 Secondary 只能读到 x=3。


Linearizable 也比较特殊,只能在 Primary 节点上使用,因此也能读取到 x=5,但大 家可能有疑惑,x=5 并没有复制到多数派节点,MongoDB 的解决方法是,当使用 Linearizable 时,在读到 x=5 之后,会等 x=5 复制到多数派节点,才会向客户端返回成功。


不同 ReadConcern Level 的 Tradeoff

复制集使用及原理介绍

LATEST:能读到多新的数据;

FAST:能多快地返回数据;

SAFE:读的数据是否会发生回滚;


Majority:能够保证 FAST,也就是数据不会被回滚。

Linearizable:能够保证数据不回滚,同时读取最新数据,但牺牲了延迟。 Local/available:能够最快返回数据,读取最新数据,但数据可能会回滚。


总结:ReadConcern Level 越高,一致性保证越好,但访问延迟也更高。


(七)基于副本集的维护性操作举例 —— Rollover Compact


背景:集合频繁的插入和删除会导致“碎片率”上升,浪费存储空间。


Tips:碎片率计算方式 Https://developer.aliyun.com/article/769536


MongoDB 提供 Compact 命令来回收碎片,但会阻塞读写,对业务有影响,在副本 集模式下,滚动的方式来进行 Compact 操作,避免影响业务。


复制集使用及原理介绍

举个例子,上图为一个三节点副本集,在最左边的副本集,用户可以在 Hidden 节点完 成 Compact Collection 操作。因为 Hidden 对客户端不可见,因而对业务没有影响。当 Hidden 节点操作后,可以把 Secondary 节点切换成 Hidden 节点,在新的节点上做 Compact Collection 操作(如上图中间所示),最后将 Primary 节点也切换成 Hidden 节点(如上图右边所示),最终完成 Compact Collection 操作。


切换节点会对业务产生些许影响,但 Driver 能够自动 Handle,避免直接在 Primary 节点完成 Compact Collection 操作,导致业务对 DB 不可访问。


三、MongoDB 副本集原理介绍

(一)什么是 MongoDB Oplog

  • MongoDB Oplog 是 Local 库下的一个集合,用来保存写操作所产生的增量日志(类 似于 MySQL 中的 Binlog);
  • 它是一个 Capped Collection,即超出配置的最大值后,会自动删除最老的历史数据, MongoDB 针对 Oplog 的删除有特殊优化,以提升删除效率;
  • 主节点产生新的 Oplog Entry,从节点通过复制 Oplog 并应用来保持和主节点的状态 一致;
  • Oplog 中包含的有:O —— 插入或更新的内容;Op —— 操作类型;Ns —— 操作 执行的 DB 和集合;Ts —— 操作发生的时间等。

复制集使用及原理介绍

(二)Oplog 保留策略 —— 根据大小及根据时间范围

  • 4.4 之前
    • 根据 Replication.OplogSizeMB 的配置值决定 Oplog 集合的大小上限,默认为 磁盘空间的 5%,如果用户是单机多实例的部署形态,需要调整默认值;
    • 当 Oplog 集合大小超过上限时,会自动删除最老的 Oplog Entry。

  • 4.4 删除策略增强:MongoDB 提供了按时间段来保留 Oplog,由参数 Storage. OplogMinRetentionHours 控制,方便用户更好地完成定期维护的操作。

  • 删除时,即使 Oplog 集合大小超过了配置的最⼤值,但最老的 Oplog 仍然在 Storage.OplogMinRetentionHours 范围内,那么 Oplog 不会删。


MongoDB 目前提供在线修改 OplogMinRetentionHours 配置值的方式,用户无需 重启实例,如下图所示。

复制集使用及原理介绍


(三)MongoDB 副本集同步原理

MongoDB 副本集同步原理分为两部分:全量同步与增量同步。


原理一:全量同步


  • 发生时机:
    • 新节点刚加入副本集时
    • 老的节点因为同步滞后而进入 Recovering 状态时

  • 全量同步包含两个阶段:
    • 数据克隆阶段:记录开始时间 T1,从源端拉取所有的集合数据,不保证数据和源 的一致性,记录结束时间 T2;
    • 增量应用阶段:应用从 T1 - T2 期间的 Oplog,达到一致性状态,全量同步结束。

具体全量同步流程图如下:

复制集使用及原理介绍

4.4 增强 —— 全量同步断点续传 

复制集使用及原理介绍

  • 4.4 之前:全量同步期间,如果发生网络异常,导致同步中断,需要重头开始,网络 环境比较差时,大数据量很难完成全量同步,可用节点数变少,实例可用性存在隐患;
  • 4.4 : 基于「Resume Token」机制,记录全量拉取的位点,网络异常导致同步中断 后,重连时带上 Resume Token;
  • Replication.initialSyncTransientErrorRetryPeriodSeconds 参数决定了同步中断 后重试的超时时间,默认 24h。


原理二:增量同步

复制集使用及原理介绍

  • 发生时机:全量同步结束后,持续同步,保持和主节点数据一致,可以从不同工作职责 的角度分析增量同步的具体流程;
  • Oplog Fetcher 线程负责拉取 Oplog Find 命令创建 Tailable Cursor,GetMore 命令批量从同步源拉取 Oplog,单个 Batch 最大 16MB;
  • 拉取的 Oplog Batch 放到内存中的 Blocking Queue 中;
  • ReplBatcher 线程负责从 Blocking Queue 中取出 Batch 生成新的可 Apply 的 Batch 放到 Deque 中,这里主要是因为需要控制并发,有些操作需要放到一个单独的 Batch;
  • OplogApplier 线程负责从 Deque 中取出 Batch 写 Oplog, 然后把 Batch 拆分, 分发到 Worker 线程进行并发 Apply;
  • 为了保持一致性,中间需要保存多个不同的 Oplog 应用位点信息。


(四)MongoDB 副本集高可用原理

复制集使用及原理介绍

  • 主备切换时机:
    • 主节点不可用;
    • 新增节点(更高的 Priority);
    • 主动运维,rs.stepDown() or rs.reconfig()

  • MongoDB 基于 Raft 协议实现了自己的高可用机制;
  • 副本集之间保持心跳(默认 2 秒探测一次);
  • 如果超出 ElectionTimeoutMillis(默认 10 秒)没有探测到主节点,Secondary 节点 会发起选举,发起前检查自身条件:
    • Priority 是否大于 0
    • 当前状态是否够新


  • 在真正选举前,会先进行一轮空投(Dry-Run),避免当前 Primary 无意义的降级( StepDown),因为 Primary 收到其他节点且 Term 更高的话则会降级;
  • Dry-Run 成功后,会增加自身的 Term 发起真正的选举,如果收到多数派的选票则选 举成功,把新的拓扑信息通过心跳广播到整个副本。


四、总结

  • 副本集是可用性、扩展性、维护性的有效保证,中等业务规模,生产环境建议优先选择 部署该形态,如果是大型业务规模,建议使用 Sharing 形态;
  • 副本集使用务必使用高可用连接串的方式,避免业务访问单点;
  • 默认情况下的 Read/Write Concern 可以满足绝大部分业务需求,特殊情况需要在一 致性和性能之间做出取舍;
  • Oplog 是 MongoDB 的重要基础设施,除了用于同步(全量 + 增量),还可用于构 建数据生态(ChangeStream);
  • MongoDB 以 Raft 协议为指导实现了自己的高可用机制,大部分情况下,主节点故障 15 秒内可选出新主。


快速掌握MongoDB核心技术目录

电子书下载:《玩转MongoDB从入门到实战》 https://developer.aliyun.com/article/780915
走进 MongoDB  https://developer.aliyun.com/article/781079
MongoDB聚合框架 https://developer.aliyun.com/article/781095
复制集使用及原理介绍  https://developer.aliyun.com/article/781137
分片集群使用及原理介绍  https://developer.aliyun.com/article/781104
ChangeStreams 使用及原理 https://developer.aliyun.com/article/781107
事务功能使用及原理介绍 https://developer.aliyun.com/article/781111
MongoDB最佳实践一 https://developer.aliyun.com/article/781139
MongoDB最佳实践二  https://developer.aliyun.com/article/781141
上一篇:阿里云POLARDB发布:6倍性能差,100TB容量


下一篇:nodejs链接mongodb数据库