【mongoDB】mongoDB 数据同步和自动故障转移原理

一、数据同步的原理

当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.png

mongoDB通过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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容