一、数据同步的原理
当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:
1、检查自己local库的oplog.rs集合找出最近的时间戳
2、检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录
3、将找到的记录插入到自己的oplog.rs集合中,并执行这些操作
PRIMARY> rs.status()
{
"set" : "test",
"date" : ISODate("2015-07-02T02:38:15Z"),
"myState" : 1,
"members" : [
{
"_id" : 2,
"name" : "192.168.91.144:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 1678,
"lastHeartbeat" : ISODate("2015-07-02T02:38:14Z"),
"lastHeartbeatRecv" : ISODate("2015-07-02T02:38:14Z"),
"pingMs" : 1
},
{
"_id" : 1,
"name" : "192.168.91.135:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1678,
"optime" : Timestamp(1435803750, 1),
"optimeDate" : ISODate("2015-07-02T02:22:30Z"),
"lastHeartbeat" : ISODate("2015-07-02T02:38:14Z"),
"lastHeartbeatRecv" : ISODate("2015-07-02T02:38:13Z"),
"pingMs" : 1,
"syncingTo" : "192.168.91.148:27017"
},
{
"_id" : 0,
"name" : "192.168.91.148:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1698,
"optime" : Timestamp(1435803750, 1),
"optimeDate" : ISODate("2015-07-02T02:22:30Z"),
"electionTime" : Timestamp(1435803023, 1),
"electionDate" : ISODate("2015-07-02T02:10:23Z"),
"self" : true
}
],
"ok" : 1
}
myState:1表示primary
state:1表示primary;7表示arbiter
uptime:成员的在线时间
lastHeartbeat:当前实例到远端最近一次成功接收到心跳包的时间
pingMs:本实例到远端路由包的来回时间
optime:读取oplog.rs集合中本实例最近一次的更改时间
二、mongoDB数据同步的过程:
1:拉取同步节点的oplog。例如:Secondary节点拉去Primary节点的oplog。
2:将拉取的oplog写入到自己的oplog中。例如:Secondary节点从Primary拉去的oplog写入到自己的oplog。
3:请求下一个oplog同步到哪里。例如:Secondary会请求Primary节点同步到哪里了
Secondary节点同步到哪了?
1:Primary节点插入一条数据,同时会把该数据写入到Primary的oplog中,并且记录一个时间戳
2:db.runCommand({getlasterror:1,w:2}) 在Primary节点被调用时,Primary就完成了写入操作,等待其他非仲裁节点来同步数据
3:Secondary节点查询Primary的oplog并且拉取oplog
4:Secondary根据时间戳应用oplog
5:Secondary请求大于本身oplog时间戳的oplog
6:Primary更新时间戳
初始化同步:
1:新增加的节点或者oplog同步时候被覆写的时候都会进行初始化同步
2:从源节点取最新的oplog time,标记为start
3:从源节点克隆所有的数据到目标节点
4:在目标节点建立索引
5:取目标节点最新的oplog time,标记为minValid
6:在目标节点执行start到minValid的oplog(应该是复制过来还没有执行的oplog,没有完成最终一致性的那部分,就是一个oplog replay的过程)
7:成为正常成员
Initial Sync
Initial sync copies all the data from one member of the replica set to another member. A member uses initial sync when the member has no data, such as when the member is new, or when the member has data but is missing a history of the set’s replication.
When you perform an initial sync, MongoDB:
1:Clones all databases. To clone, the mongod queries every collection in each source database and inserts all data into its own copies of these collections. At this time, _id indexes are also built. The clone process only copies valid data, omitting invalid documents.
2:Applies all changes to the data set. Using the oplog from the source, the mongod updates its data set to reflect the current state of the replica set.
3:Builds all indexes on all collections (except _id indexes, which were already completed).
When the mongod finishes building all index builds, the member can transition to a normal state, i.e. secondary.
从哪个成员来同步数据(Who to sync from)?
MongoDB初始化同步数据的时候,可能从主节点同步,也可能是从从节点同步,根据最近的原则,选择最邻近节点去同步数据。(基于ping值)
同时也可以用任选以下一种方式指定从哪个节点来同步数据:
db.adminCommand( { replSetSyncFrom: "[hostname]:[port]" } )
rs.syncFrom("[hostname]:[port]")
新同步过来的数据并不能查看,Secondary默认不可读不可写。
如果需要查看要执行rs.slaveOk(),则当前shell连接上可以查看,后续的其他连接还是不可读不可写。
Primary写处理
master负责接收写请求,具体的流程为:
如果开启journal功能,则先将写请求记录到journal中,然后批量执行,同时将操作记录到oplog中
如果未开启journal功能,则对每个写请求进行单独操作,然后写入oplog
注:oplog是幂等的,当有累加操作inc时,会记录成set操作,从而无论重复执行多少次操作获得的结果都是一样的
从节点同步
如果是一个新的从节点,首先先从master的数据库文件进行复制,同时记录起始时间;当从节点从master的复制完成后,会根据复制的起始时间开始追oplog,进而与master进行同步。
初始化同步完成后的Secondaty定期从Primary的oplog中获取最新的操作,然后对自己的数据副本执行这些操作,从而保证Secondaty的数据与Primary最终一致性。
注意:当slave同步的速度赶不上master更新的速度时,oplog会因为追加了过多的操作而发生将旧记录覆盖掉,这样slave可能无法保证同步所有的数据,这时,slave会开始从头重新同步。
三、 mongoDB故障自动转移
image.png image.png image.pngmongoDB通过lastHeartbeat来实现自动转移。
mongod实例每隔2s就会向其他成员发送一个心跳包,并且通过rs.status()中返回的成员的health来判断成员的状态。
当主节点与集合中的其他成员的通信electionTimeoutMillis时间超过配置的时间段(默认为10秒)时,合格的secondary节点将要求选举,以提名自己为新的主节点。
如果primary节点不可用了,那么复制集中的所有secondary节点都会触发一次选举操作,选出新的primary节点。
群集尝试完成新主数据库的选择并恢复正常操作。
如果secondary节点有多个,则会选举拥有最新oplog时间戳记录的或者有较高权限的节点成为primary。
注意:如果secondary停止时间过长,导致primary节点的oplog内容被循环写覆盖掉了,则需要手动同步secondary节点。
节点类型
任何时间,集群中只有一个活跃节点,其他的都是备份节点。
有几种不同类型的节点可以存在与副本集中:
standard 标准节点
这是常规节点,它存储一份完整的数据副本,参与选举投票有可能成为活跃节点。
passive 被动结点
存储了完整的数据副本,参与投票,不能成为活跃节点,如延时节点。
arbiter 仲裁者
仲裁者只能参与投票,不接收复制的数据,也不能成为活跃节点。
节点优先级
每个参与节点(非仲裁)有优先权,优先权按照优先值从大到小,默认优先级为1,可以是0-1000(含)。
在节点配置中修改priority键,来配置标准节点或者被动节点:
> members.push({"_id":3,"host":"xx.xx.xx.xx:17017","priority":40})
"arbiterOnly"键可以指定仲裁节点:
members.push({"_id":4,"host":"xx.xx.xx.xx:27017","arbiterOnly":true})
备份节点会从活跃节点抽取oplog,并执行操作,就像活跃备份系统中的备份服务器一样。
活跃节点也会写操作到自己的本地oplog,oplog中的操作包含严格递增的序号,这个序号来判定数据的时效性,所以节点之家的时间同步非常重要!
选举策略
如果活跃节点出现故障,其余节点会选一个新的活跃节点。
选举过程可以由任何非活跃节点发起,新的活跃节点由副本集中的大多数选举产生。
其中仲裁节点也参与选举,避免出现僵局。
新的活跃节点将是优先级最高的节点,优先级相同则数据较新的节点获胜。
不论活跃节点何时变化,新的活跃节点的数据就被假定为系统的最新数据,对其他节点(原活跃节点)的操作都会回滚,即便是之前的活跃节点已经恢复工作了。
为了完成回滚,所有节点连接新的活跃节点后重新同步。这些节点会查看自己的oplog,找出活跃节点没有的操作,然后向活跃节点请求这些操作影响的文档最新副本。
正在执行重新同步的节点被视为恢复中,在完成这个过程之前不能成为活跃节点的候选者。
四、参考
mongoDB中文手册/复写
https://mongodb.net.cn/manual/replication/#replication-flow-control
数据库命令 > 复制命令 > replSetSyncFrom
https://mongodb.net.cn/manual/reference/command/replSetSyncFrom
Replica Set Data Synchronization
https://www.mongodb.com/docs/manual/core/replica-set-sync/#replica-set-initial-sync-source-selection
mongoDB 副本集添加新的节点
https://blog.csdn.net/csdnhsh/article/details/116333686
网友评论