由于当前环境拟使用副本集,所以下面写的都是有关使用副本集的时候需要注意的坑,与学习过程中的一些记录。
同步源不一定是primary节点,而是经过一套规则选择的一个节点,有可能是secondery节点。
failOver时的回滚机制:primary节点挂掉,oplog已经更新,但是其余secondery节点在没有同步。此时集群需要进行重新选出primary节点,此时新的主节点并没有最新的oplog,当后期重启老primary节点时,作为新加入集群的新节点,需要与主节点进行oplog的同步,此时会对节点进行强制一致性处理,形成回滚(rollback),当rollback发生时,MongoDB将把rollback的数据以BSON格式存放到dbpath路径下rollback文件夹中。
一次MongoDB的写入:
- 将文档数据写入对应的集合
- 更新集合的所有索引信息
- 写入一条oplog用于同步
- 返回response,并且secondery节点拉取最新的oplog(此处为回滚的坑)
- 提交事务并且journal落磁盘
解决方案:Write Concern的配置,http://www.mongoing.com/archives/2916。原理为调整写时的确认界别,使除了当前节点以外的节点也有最新的oplog后,才返回response,完成一个事务。这样当主节点宕掉,也可以有其他节点有最新的oplog,新oplog时间戳的拥有者更可能获得新选举的选票。
{w: “majority”, j:1 }级别,几乎可以满足所有要求。
参考:https://blog.csdn.net/jianlong727/article/details/73321905
新节点加入时的oplog丢失问题:新节点的加入会有一系列的同步操作,在每步同步操作过程中,虽然都会对oplog进行同步,但是如果某一时刻的同步时间大于oplog可存储的量,则会造成oplog的覆写,从而导致新节点的数据丢失。
intial sync流程,(翻译自MongoDB源码上的英文注释)
全量同步开始,设置minvalid集合的_initialSyncFlag。 获取同步源上最新oplog时间戳为t1。 全量同步集合数据 (耗时)。 获取同步源上最新oplog时间戳为t2。 重放[t1, t2]范围内的所有oplog。 获取同步源上最新oplog时间戳为t3。 重放[t2, t3]范围内所有的oplog。 建立集合所有索引 (耗时)。 获取同步源上最新oplog时间戳为t4。 重放[t3, t4]范围内所有的oplog。 全量同步结束,清除minvalid集合的_initialSyncFlag。
解决方案:一是:根据官方说法,需要删除掉节点上的全部数据,重新进行全量同步。参考:https://docs.mongodb.com/manual/tutorial/resync-replica-set-member/
二是:需要对oplog进行评估,扩大为较合理的oplog大小。
在生产环境中,当primary节点的写入压力过大,而secondery节点拉取oplog的速度相对缓慢,导致的oplog覆写,致使secondery节点状态变为recovering。
解决方案:可使用增加replWriter线程的方法进行解决。
参考:https://yq.aliyun.com/articles/47336?spm=5176.8091938.0.0.WPuhZ0
majority指的多数节点:在write Concern的参数设置级别的过程中引入了majority,N/2 +1指的就是多数。
这里引入为什么官方推荐布置奇数个节点的服务器,因为3 -(3/2 +1) = 4 - (4/2 +1)= 1,即无论是三个节点还是四个节点,都只可以容忍1个节点的失效。即三个节点的集群与四个节点的集群实现的效果相同(虽然四个节点的集群多一台物理机,相对来说更加安全。)
参考:https://yq.aliyun.com/articles/64?spm=5176.8091938.0.0.MFE7rL
journal与oplog机制的认识:journal是引擎级别,相当于redis中的wal日志操作,用于解决机房断电等非常规情况下,恢复数据。
oplog则是在MongoDB配置为复制集的情况下,用于对secondery节点进行同步数据的普通数据表。即为local.oplog.rs。secondery节点会使用tail cursor对主节点的oplog进行监控,如果有新数据则进行拉取。
参考:http://www.mongoing.com/archives/3988