MongoDB 集群模式-副本集

MongoDB的集群模式有三种:

  • 主从(Master-Slaver),MongoDB 3.6彻底废弃
  • 副本集(Replica Set)
  • 分片(Sharding)

本章主要讲述副本集(Replica Set)。

一、副本集介绍

1.1 什么是副本集

MongoDB 副本集是将数据同步在多个服务器的过程,复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性,同时还允许从硬件故障和服务中断中恢复数据。

1.2 什么是 Oplog

Oplog是MongoDB Primary(主节点)和Secondary(从节点)在副本集建立期间和建立完成之后的复制介质。Primary中所有的写入操作都会记录到Oplog中,然后从节点会来主节点拉取Oplog并应用到自己的节点上。这里的Oplog是MongoDB local数据库的一个集合,它是Capped collection,通俗意思就是它是固定大小,循环使用的。如下图:

MongoDB 集群模式-副本集_第1张图片
Oplog 复制介质

Oplog中的内容如下:

{
    "ts" : Timestamp(1446011584, 2),
    "h" : NumberLong("1687359108795812092"),
    "v" : 2,
    "op" : "i",
    "ns" : "test.nosql",
    "o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" }
}
  • ts: 操作时间,当前timestamp + 计数器,计数器每秒都被重置
  • h:操作的全局唯一标识
  • v:oplog版本信息
  • op:操作类型
    • i:插入操作
    • u:更新操作
    • d:删除操作
    • c:执行命令(如createDatabase,dropDatabase)
  • n:空操作,特殊用途
  • ns:操作针对的集合
  • o:操作内容,如果是更新操作
  • o2:操作查询条件,仅update操作包含该字段

1.2 副本集的结构与原理

MongoDB 集群模式-副本集_第2张图片
副本集结构

如上图所示,副本集由一组mongo实例组成,提供了数据冗余与高可用性。相对于主从模式,该模式可以在主节点挂掉的时候通过选举算法自动选举出新的主节点,保证服务的可用性。
该模式由三个角色组成:

  • primary: 主节点,是唯一能够接收写请求的节点。一旦主节点不可用,会选出新的主节点
  • secondaries: 从节点,提供数据备份和读功能,并且能在主节点挂掉的时候被选举为新的主节点。
  • arbiter: 投票节点或者叫仲裁节点。该角色是可选的,所以图上也没有画出来。投票节点其本身并不包含数据集,也无法被升级为主节点,但是,一旦当前的主节点不可用时,投票节点就会参与到新的主节点选举的投票中。投票节点仅在副本集成员为偶数个的时候需要,如果在拥有奇数个复制集成员的复制集中新增了一个投票节点,复制集可能会遇到选举僵局。

主节点上能够完成读写操作,从节点仅能用于读操作。主节点需要记录所有改变数据库状态的操作,这些记录保存在oplog中,各个从节点通过此oplog来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog具有幂等性,即无论执行几次其结果一致。

集群中的各节点还会通过传递心跳信息来检测各自的健康状况。当主节点故障时,多个从节点会触发一次新的选举操作,并选举其中的一个成为新的主节点(通常谁的优先级更高,谁就是新的主节点),心跳信息默认每 2 秒传递一次。


MongoDB 集群模式-副本集_第3张图片
心跳信息

客户端连接到副本集后,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份。一旦主节点挂掉,副本节点就会选举一个新的主服务器。这一切对于应用服务器不需要关心。


MongoDB 集群模式-副本集_第4张图片
主节点挂掉

副本集中的副本节点在主节点挂掉后通过心跳机制检测到后,就会在集群内发起主节点的选举机制,自动选举出一位新的主服务器。

MongoDB官方建议副本集至少需要三个节点。3.0之前最多12个节点,3.0开始节点数量能够达到50个。限制副本节点的数量,主要是因为一个集群中过多的副本节点,增加了复制的成本,反而拖累了集群的整体性能。太多的副本节点参与选举,也会增加选举的时间。而官方建议奇数的节点,是为了避免选举僵局的发生(平局)。

1.3 副本集数据同步

Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败,则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作
执行多次,与执行一次的效果是一样的。简单的说就是:

当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:

  1. 检查自己local库的oplog.rs集合找出最近的时间戳。
  2. 检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
  3. 将找到的记录插入到自己的oplog.rs集合中,并执行这些操作。

副本集的同步和主从同步一样,都是异步同步的过程,不同的是副本集有个自动故障转移的功能。其原理是:Secondary端从primary端获取日志,然后在自己身上完全顺序的执行日志所记录的各种操作(该日志是不记录查询操作的),这个日志就是local数据 库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参数中设定:--oplogSize 1000,单位是M。

1.4 何时触发选举

MongoDB 在下面几个条件触发之下进行选举:

  • 初始化副本集时;
  • 备份节点无法和主节点通讯时(可能主节点宕或网络原因);
  • Primary 手动降级,rs.stepDown(sec),默认 60s。

选举的步骤如下:

  1. 得到每个服务器节点的最后操作时间戳。每个 mongodb 都有 oplog 机制会记录本机的操作,方便和主服务器进行对比数据是否同步还可以用于错误恢复;
  2. 如果集群中大部分服务器宕机了,保留活着的节点都为 secondary 状态并停止选举;
  3. 如果集群中选举出来的主节点或者所有从节点最后一次同步时间看起来很旧了,停止选举等待人工操作;
  4. 如果上面都没有问题就选择最后操作时间戳最新(保证数据最新)的服务器节点作为主节点。

二、示例

副本集的启动,和从节点加入到副本集的操作,只能在主节点上完成,但是主节点随时可以转移到其他从节点。
启动一个副本集系统的基本步骤如下:

  • 在主节点启动 mongod 服务时,可以使用 --replSet 启动副本集,同时指定副本集名称;
  • 连接主节点,初始化新的副本集;
  • 启动各个从节点 mongod 服务,同时这些从节点也必须初始化副本集,使用同一个副本集 id;
  • 在主节点将这些从节点加入主节点副本集;

下面演示 3 个 mongodb 创建一个副本集系统:
1)主节点启动 mongod 服务

$ mongod --port 27017 --dbpath "/usr/local/mongodb/data" --replSet simon

simon 为 副本集ID
2) 2 个从节点分别启动 mongod 服务

$ mongod --port 27017 --dbpath "/usr/local/mongodb/data" --replSet simon

3)连接到主节点 mongodb,进行副本集的初始化和配置

$ mongo
> rs.initiate()      # 初始化的副本集
> rs.add("192.168.10.58:27107")   # 加入从节点,该节点为 192.168.10.58 主机 27107 端口上的 mongod 服务
> rs.add("192.168.10.138:27107")    # 加入从节点,该节点为 192.168.10.138 主机 27107 端口上的 mongod 服务

也可以这样设置

$ mongo
>rs.initiate({"_id":"simon","members":[
     {
       "_id":1,
       "host":"192.168.10.58:27017",
       "priority":1
     },
     {
       "_id":2,
       "host":"192.168.10.138:27017",
       "priority":1
     }
   ]
  }
)
  • _id: 副本集的名称
  • members: 副本集的服务器列表
  • _id: 服务器的唯一ID
  • host: 服务器主机
  • priority: 是优先级,默认为1,优先级0为被动节点,不能成为活跃节点。优先级不位0则按照有大到小选出活跃节点
  • arbiterOnly: 仲裁节点,只参与投票,不接收数据,也不能成为活跃节点。

此时一个副本系统已经完成,所有操作直接面向主节点,实际操作由整个副本集集群提供,默认是从主节点读取

查看副本集信息

> rs.conf()      # 查看副本集的配置
> rs.status()    # 查看副本集状态
> rs.isMaster()  # 查看该主机节点是否为副本集主节点

设置从节点读写策略

> rs.getMongo().setReadPref(STRATEGY)

具体策略如下:

  • Primary 从主节点读取;
  • secondary 从从节点读取;
  • nearest 从网络延迟最小的节点读取;
  • primaryPreferred 基本上从主节点读取,主节点不可用时,从从节点的读取;
  • secondaryPreferred 基本上从从节点读取,从节点不可用时,从主节点读取;

你可能感兴趣的:(MongoDB 集群模式-副本集)