MongoDB主从复制架构原理和缺陷

master-slave架构中master节点负责数据的读写,slave没有写入权限只负责读取数据。
image.png
在主从结构中,主节点的操作记录成为oplog(operation log)。oplog存储在系统数据库local的
oplog.$main集合中,这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器
中获取oplog记录,然后在本机上执行!对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随
着操作过多,新的操作会覆盖旧的操作!
主从结构没有自动故障转移功能,需要指定master和slave端,不推荐在生产中使用。
mongodb4.0后不再支持主从复制!
[main] Master/slave replication is no longer supported

复制集replica sets

什么是复制集

image.png
复制集是由一组拥有相同数据集的mongod实例做组成的集群。
复制集是一个集群,它是2台及2台以上的服务器组成,以及复制集成员包括Primary主节点,secondary从 节点和投票节点。
复制集提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,保证数据的安全性。

为什么要使用复制集

  1. 高可用

防止设备(服务器、网络)故障。
提供自动failover 功能。
技术来保证高可用

  1. 灾难恢复

当发生故障时,可以从其他节点恢复 用于备份。

  1. 功能隔离

我们可以在备节点上执行读操作,减少主节点的压力
比如:用于分析、报表,数据挖掘,系统任务等。

复制集集群架构原理

一个复制集中Primary节点上能够完成读写操作,Secondary节点仅能用于读操作。Primary节点需要记录所有改变数据库状态的操作,这些记录保存在 oplog 中,这个文件存储在 local 数据库,各个Secondary节点通过此 oplog 来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog 具有幂等性,即无论执行几次其结果一致,这个比 mysql 的二进制日志更好用。
oplog的组成结构

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

`复制集数据同步分为初始化同步和keep复制同步。初始化同步指全量从主节点同步数据,如果Primary节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,节点之间的实时同步一般是增量同步。
初始化同步有以下两种情况会触发:
(1) Secondary第一次加入。
(2) Secondary落后的数据量超过了oplog的大小,这样也会被全量复制。
MongoDB的Primary节点选举基于心跳触发。一个复制集N个节点中的任意两个节点维持心跳,每个节点维护其他N-1个节点的状态。
image.png
心跳检测:

整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点

每2秒就会发送一次pings包,如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会

维护一个状态映射表,表明当前每个节点是什么角色、日志时间戳等关键信息。如果主节点发现自己无法与

大部分节点通讯则把自己降级为secondary只读节点。

主节点选举触发的时机:

第一次初始化一个复制集

Secondary节点权重比Primary节点高时,发起替换选举

Secondary节点发现集群中没有Primary时,发起选举

Primary节点不能访问到大部分(Majority)成员时主动降级

当触发选举时,Secondary节点尝试将自身选举为Primary。主节点选举是一个二阶段过程+多数派协议。

第一阶段:

检测自身是否有被选举的资格 如果符合资格会向其它节点发起本节点是否有选举资格的FreshnessCheck,进行同僚仲裁

第二阶段:

发起者向集群中存活节点发送Elect(选举)请求,仲裁者收到请求的节点会执行一系列合法性检查,如果检 查通过,则仲裁者> (> 一个复制集中最多> 50> 个节点 其中只有> 7> 个具有投票权> )> 给发起者投一票。 pv0通过30秒选举锁防止一次选举中两次投票。

pv1使用了terms(一个单调递增的选举计数器)来防止在一次选举中投两次票的情况。

多数派协议:

发起者如果获得超过半数的投票,则选举通过,自身成为Primary节点。获得低于半数选票的原因,除了常

见的网络问题外,相同优先级的节点同时通过第一阶段的同僚仲裁并进入第二阶段也是一个原因。因此,当

选票不足时,会sleep[0,1]秒内的随机时间,之后再次尝试选举。

复制集搭建

环境配置

  1. 主节点

    主节点配置

dbpath=/data/mongo/data/server1

bind_ip=0.0.0.0

port=37017

fork=true

logpath=/data/mongo/logs/server1.log

replSet=lagouCluster

  1. 从节点1

    dbpath=/data/mongo/data/server2

bind_ip=0.0.0.0

port=37018

fork=true

logpath=/data/mongo/logs/server2.log

replSet=lagouCluster

  1. 从节点2

    dbpath=/data/mongo/data/server3

bind_ip=0.0.0.0

port=37019

fork=true

logpath=/data/mongo/logs/server3.log

replSet=lagouCluster

初始化节点配置

启动37017和37018,然后登录MongoDB,执行下面的语句

var cfg ={“_id”:”lagouCluster”,

“protocolVersion” : 1,

“members”:[

{“_id”:1,”host”:”192.168.209.140:37017”,”priority”:10},

{“_id”:2,”host”:”192.168.209.142:37018”}

]

}

rs.initiate(cfg)

rs.status()

image.png

节点的动态删减

增加节点

rs.add(“192.168.211.133:37019”)

删除slave 节点

rs.remove(“192.168.211.133:37019”)

集群测试

进入主节点 ——- 插入数据 ——— 进入从节点验证

注意:默认节点下从节点不能读取数据。调用 rs.slaveOk() 解决 为了保证高可用,在集群当中如果主节点挂掉后,会自动 在从节点中选举一个 重新做为主节点。

rs.status()

节点说明:

PRIMARY 节点: 可以查询和新增数据

SECONDARY 节点:只能查询 不能新增 基于priority 权重可以被选为主节点

ARBITER 节点: 不能查询数据 和新增数据 ,不能变成主节点

在主节点插入数据

use lg_resume db.log_resume.insert({name:”zbc”,salary:12345})

从节点

use lg_resume db.lg_resume.find() //会没有权限 rs.slaveOk()

复制集成员的配置参数

image.png
栗子

var cfg ={“_id”:”lagouCluster”,

“protocolVersion” : 1,

“members”:[

{“_id”:1,”host”:”192.168.211.133:37017”,”priority”:10},

{“_id”:2,”host”:”192.168.211.133:37018”,”priority”:0},

{“_id”:3,”host”:”192.168.211.133:37019”,”priority”:5},

{“_id”:4,”host”:”192.168.211.133:37020”,”arbiterOnly”:true}

]

};

// 重新装载配置,并重新生成集群节点。

rs.reconfig(cfg)

//重新查看集群状态

rs.status()

有仲裁节点复制集搭建

和上面的初始化节点配置步骤相同 只是增加了 一个特殊的仲裁节点
注入节点 执行 rs.addArb(“IP:端口”);
//可以删除一个节点,然后添加为仲裁节点
rs.addArb(“192.168.211.133:37020”)