MongoDB复制集原理详解

复制集简介

Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。

下图(图片源于Mongodb官方文档)是一个典型的Mongdb复制集,包含一个Primary节点和2个Secondary节点。

Primary选举

复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。

初始化复制集

config = {
  _id : "my_replica_set",
  members : [
     {_id : 0, host : "rs1.example.net:27017"},
     {_id : 1, host : "rs2.example.net:27017"},
     {_id : 2, host : "rs3.example.net:27017"},
  ]
}

rs.initiate(config)

『大多数』的定义

假设复制集内投票成员(后续介绍)数量为N,则大多数为 N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。

投票成员数 大多数 容忍失效数
1 1 0
2 2 0
3 2 1
4 3 1
5 3 2
6 4 2
7 4 3

通常建议将复制集成员数量设置为奇数,从上表可以看出3个节点和4个节点的复制集都只能容忍1个节点失效,从『服务可用性』的角度看,其效果是一样的。(但无疑4个节点能提供更可靠的数据存储)

特殊的Secondary

正常情况下,复制集的Seconary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。

Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb支持对复制集的Secondary节点进行灵活的配置,以适应多种场景的需求。

Arbiter

Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。

比如你部署了一个2个节点的复制集,1个Primary,1个Secondary,任意节点宕机,复制集将不能提供服务了(无法选出Primary),这时可以给复制集添加一个Arbiter节点,即使有节点宕机,仍能选出Primary。

Arbiter本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性。

Priority0

Priority0节点的选举优先级为0,不会被选举为Primary

比如你跨机房A、B部署了一个复制集,并且想指定Primary必须在A机房,这时可以将B机房的复制集成员Priority设置为0,这样Primary就一定会是A机房的成员。(注意:如果这样部署,最好将『大多数』节点部署在A机房,否则网络分区时可能无法选出Primary)

Vote0

Mongodb 3.0里,复制集成员最多50个,参与Primary选举投票的成员最多7个,其他成员(Vote0)的vote属性必须设置为0,即不参与投票。

Hidden

Hidden节点不能被选为主(Priority为0),并且对Driver不可见。

因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。

Delayed

Delayed节点必须是Hidden节点,并且其数据落后与Primary一段时间(可配置,比如1个小时)。

因Delayed节点的数据比Primary落后一段时间,当错误或者无效的数据写入Primary时,可通过Delayed节点的数据来恢复到之前的时间点。

数据同步

Primary与Secondary之间通过oplog来同步数据,Primary上的写操作完成后,会向特殊的local.oplog.rs特殊集合写入一条oplog,Secondary不断的从Primary取新的oplog并应用。

因oplog的数据会不断增加,local.oplog.rs被设置成为一个capped集合,当容量达到配置上限时,会将最旧的数据删除掉。另外考虑到oplog在Secondary上可能重复应用,oplog必须具有幂等性,即重复应用也会得到相同的结果。

如下oplog的格式,包含ts、h、op、ns、o等字段

{
 "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操作包含该字段

Secondary初次同步数据时,会先进行init sync,从Primary(或其他数据更新的Secondary)同步全量数据,然后不断通过tailable cursor从Primary的local.oplog.rs集合里查询最新的oplog并应用到自身。

init sync过程包含如下步骤

T1时间,从Primary同步所有数据库的数据(local除外),通过listDatabases + listCollections + cloneCollection敏命令组合完成,假设T2时间完成所有操作。

从Primary应用[T1-T2]时间段内的所有oplog,可能部分操作已经包含在步骤1,但由于oplog的幂等性,可重复应用。

根据Primary各集合的index设置,在Secondary上为相应集合创建index。(每个集合_id的index已在步骤1中完成)。

oplog集合的大小应根据DB规模及应用写入需求合理配置,配置得太大,会造成存储空间的浪费;配置得太小,可能造成Secondary的init sync一直无法成功。比如在步骤1里由于DB数据太多、并且oplog配置太小,导致oplog不足以存储[T1, T2]时间内的所有oplog,这就Secondary无法从Primary上同步完整的数据集。

修改复制集配置

当需要修改复制集时,比如增加成员、删除成员、或者修改成员配置(如priorty、vote、hidden、delayed等属性),可通过replSetReconfig命令(rs.reconfig())对复制集进行重新配置。

比如将复制集的第2个成员Priority设置为2,可执行如下命令

cfg = rs.conf();
cfg.members[1].priority = 2;
rs.reconfig(cfg);

细说Primary选举

Primary选举除了在复制集初始化时发生,还有如下场景

  • 复制集被reconfig
  • Secondary节点检测到Primary宕机时,会触发新Primary的选举
  • 当有Primary节点主动stepDown(主动降级为Secondary)时,也会触发新的Primary选举

Primary的选举受节点间心跳、优先级、最新的oplog时间等多种因素影响。

节点间心跳

复制集成员间默认每2s会发送一次心跳信息,如果10s未收到某个节点的心跳,则认为该节点已宕机;如果宕机的节点为Primary,Secondary(前提是可被选为Primary)会发起新的Primary选举。

节点优先级

  • 每个节点都倾向于投票给优先级最高的节点
  • 优先级为0的节点不会主动发起Primary选举
  • 当Primary发现有优先级更高Secondary,并且该Secondary的数据落后在10s内,则Primary会主动降级,让优先级更高的Secondary有成为Primary的机会。

Optime

拥有最新optime(最近一条oplog的时间戳)的节点才能被选为主。

网络分区

只有更大多数投票节点间保持网络连通,才有机会被选Primary;如果Primary与大多数的节点断开连接,Primary会主动降级为Secondary。当发生网络分区时,可能在短时间内出现多个Primary,故Driver在写入时,最好设置『大多数成功』的策略,这样即使出现多个Primary,也只有一个Primary能成功写入大多数。

复制集的读写设置

Read Preference

默认情况下,复制集的所有读请求都发到Primary,Driver可通过设置Read Preference来将读请求路由到其他的节点。

  • primary: 默认规则,所有读请求发到Primary
  • primaryPreferred: Primary优先,如果Primary不可达,请求Secondary
  • secondary: 所有的读请求都发到secondary
  • secondaryPreferred:Secondary优先,当所有Secondary不可达时,请求Primary
  • nearest:读请求发送到最近的可达节点上(通过ping探测得出最近的节点)

Write Concern

默认情况下,Primary完成写操作即返回,Driver可通过设置[Write Concern(https://docs.mongodb.org/manual/core/write-concern/)来设置写成功的规则。

如下的write concern规则设置写必须在大多数节点上成功,超时时间为5s。

db.products.insert(
 { item: "envelopes", qty : 100, type: "Clasp" },
 { writeConcern: { w: majority, wtimeout: 5000 } }
)

上面的设置方式是针对单个请求的,也可以修改副本集默认的write concern,这样就不用每个请求单独设置。

cfg = rs.conf()
cfg.settings = {}
cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs.reconfig(cfg)

异常处理(rollback)

当Primary宕机时,如果有数据未同步到Secondary,当Primary重新加入时,如果新的Primary上已经发生了写操作,则旧Primary需要回滚部分操作,以保证数据集与新的Primary一致。

旧Primary将回滚的数据写到单独的rollback目录下,数据库管理员可根据需要使用mongorestore进行恢复。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • mongodb主从复制_动力节点Java学院整理

    从这一篇开始我们主要讨论mongodb的部署技术. 我们知道sql server能够做到读写分离,双机热备份和集群部署,当然mongodb也能做到,实际应用中我们不希望数据库采用单点部署,如果碰到数据库宕机或者被毁灭性破坏那是多么的糟糕. 一:主从复制 1: 首先看看模型图 2: 从上面的图形中我们可以分析出这种架构有如下的好处: <1> 数据备份. <2> 数据恢复. <3> 读写分离. 3:下面我们就一一实践 实际应用中我们肯定是多服务器部署,限于自己懒的装虚拟机,

  • MongoDB的Master-Slave主从模式配置及主从复制要点解析

    主从配置 mongodb的master-slave模式配置方式如下 1.keyFile 生成key_file openssl rand -base64 741 > mongo_key 将mongo_key 分别置于master 和 slave mongodb user可以access的地方. 设置权限 chmod 700 mongo_key 设置 onwer chown mongodb:nogroup mongo_key 2.master配置 编辑/etc/mongodb.conf, 设置如下

  • 详解mongoDB主从复制搭建详细过程

    详解mongoDB主从复制搭建详细过程 实验目的搭建mongoDB主从复制 主 192.168.0.4 从 192.168.0.7 mongodb的安装 1: 下载mongodb www.mongodb.org 下载最新的stable版 查看自己服务器 适合哪个种方式下载(wget 不可以的 可以用下面方式下载) wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.0.5.tgz curl -O -L https

  • MongoDB在不同主机间复制数据库和集合的教程

    1. db.cloneCollection() db.cloneCollection(from, collection, query) 在不同的mongodb实例间复制数据,db.cloneCollection是cloneCollection数据库命令的一个外在体现. function (from, collection, query) { assert( isString(from) && from.length ); assert( isString(collection) &

  • MongoDB 主从复制实例讲解

    主从复制可以用来做数据库的备份,故障恢复,读写分离. 本实验使用Mongodb 3.2版本,我们先查看一下mongod的帮助 [root@localhost mongodb]# mongod --help .....省略 Master/slave options (old; use replica sets instead): --master master mode --slave slave mode --source arg when slave: specify master as <s

  • MongoDB入门教程之主从复制配置详解

    从这一篇开始我们主要讨论mongodb的部署技术. 我们知道sql server能够做到读写分离,双机热备份和集群部署,当然mongodb也能做到,实际应用中我们不希望数据库采用单点部署, 如果碰到数据库宕机或者被毁灭性破坏那是多么的糟糕.  一:主从复制 1: 首先看看模型图   2: 从上面的图形中我们可以分析出这种架构有如下的好处: <1>  数据备份. <2>  数据恢复. <3>  读写分离.  3:下面我们就一一实践 实际应用中我们肯定是多服务器部署,限于自

  • MongoDB的主从复制及副本集的replSet配置教程

    复制 MongoDB的复制功能很重要,尤其是现在的存储引擎还不支持单击持久性.不仅可以用复制来应对故障切换,数据集成,还可以做读扩展,热备份或作为离线批处理的数据源. 1.主从复制 主从复制是MongoDB最常用的复制方式.可用于备份,故障恢复和读扩展等. 基本就是搭建一个主节点和一个或多个从节点,每个从节点需要知道主节点的地址.运行mongod --master启动主服务器.运行mongod --slave --source master_address启动从服务器. [root@test02

  • MongoDB复制集原理详解

    复制集简介 Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用. 下图(图片源于Mongodb官方文档)是一个典型的Mongdb复制集,包含一个Primary节点和2个Secondary节点. Primary选举 复制集通过replSetInitiate命令(或

  • Spark调度架构原理详解

    1.启动spark集群,就是执行sbin/start-all.sh,启动master和多个worker节点,master主要作为集群的管理和监控,worker节点主要担任运行各个application的任务.master节点需要让worker节点汇报自身状况,比如CPU,内存多大,这个过程都是通过心跳机制来完成的 2.master收到worker的汇报信息之后,会给予worker信息 3.driver提交任务给spark集群[driver和master之间的通信是通过AKKAactor来做的,也

  • apache commons工具集代码详解

    Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍. 组件 功能介绍 BeanUtils 提供了对于JavaBean进行各种操作,克隆对象,属性等等. Betwixt XML与Java对象之间相互转换. Codec 处理常用的编码方法的工具类包 例如DES.SHA1.MD5.Base64等. Collections java集合框架操作. Compress java提供文件打包 压缩类库. Con

  • Python深度强化学习之DQN算法原理详解

    目录 1 DQN算法简介 2 DQN算法原理 2.1 经验回放 2.2 目标网络 3 DQN算法伪代码 DQN算法是DeepMind团队提出的一种深度强化学习算法,在许多电动游戏中达到人类玩家甚至超越人类玩家的水准,本文就带领大家了解一下这个算法,论文的链接见下方. 论文:Human-level control through deep reinforcement learning | Nature 代码:后续会将代码上传到Github上... 1 DQN算法简介 Q-learning算法采用一

  • Apache Doris Join 优化原理详解

    目录 背景 & 目标 Doris 数据划分 Partition Bucket Join 方式 总览 Broadcast / Shuffle Join Bucket Shuffle Join Plan Rule Colocate Join Runtime Filter 优化 Join Reorder 优化 Join 调优建议 背景 & 目标 掌握 Apache Doris Join 优化手段及其实现原理 为代码阅读提供理论基础 Doris 数据划分 不同的 Join 方式非常依赖于对 Dor

  • 对ArrayList和LinkedList底层实现原理详解

    1.说一下 ArrayList 底层实现方式? ①ArrayList 通过数组实现,一旦我们实例化 ArrayList 无参数构造函数默认为数组初始化长度为 10 ②add 方法底层实现如果增加的元素个数超过了 10 个,那么 ArrayList 底层会新生成一个数组,长度为原数组的 1.5 倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中.当新数组无法容纳增加的元素时,重复该过程.是一旦数组超出长度,就开始扩容数组. 扩容数组调用的方法 Arrays.copyO

  • C# 通过反射初探ORM框架的实现原理(详解)

    背景: 以前学的Java进行开发,多用到Mybatis,Hiberante等ORM框架,最近需要上手一个C#的项目,由于不是特别难,也不想再去学习C#的ORM框架,所以就想着用反射简单的实现一下ORM框架的内容,简单的增删改查,没有用到多表之间的联系. 反射: Java和C#中的反射大体相同,主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.我的理解就是可以程序运行时动态的获取对象的属性和方法,并且可以进行与之相

  • java进行远程部署与调试及原理详解

    这篇文章主要介绍了java进行远程部署与调试及原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 远程调试,特别是当你在本地开发的时候,你需要调试服务器上的程序时,远程调试就显得非常有用. JAVA 支持调试功能,本身提供了一个简单的调试工具JDB,支持设置断点及线程级的调试同时,不同的JVM通过接口的协议联系,本地的Java文件在远程JVM建立联系和通信.此篇是Intellij IDEA远程调试的教程汇总和原理解释,知其然而又知其所以然.

  • mongodb driver使用代码详解

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 0 前言 全是干货的技术殿堂 文章收录在我的 GitHub 仓库,欢迎Star/fork: Java-Interview-Tutorial https://github.com/Wasabi1234/Java-Interview-Tutorial mongo

  • Python字典底层实现原理详解

    在Python中,字典是通过散列表或说哈希表实现的.字典也被称为关联数组,还称为哈希数组等.也就是说,字典也是一个数组,但数组的索引是键经过哈希函数处理后得到的散列值.哈希函数的目的是使键均匀地分布在数组中,并且可以在内存中以O(1)的时间复杂度进行寻址,从而实现快速查找和修改.哈希表中哈希函数的设计困难在于将数据均匀分布在哈希表中,从而尽量减少哈希碰撞和冲突.由于不同的键可能具有相同的哈希值,即可能出现冲突,高级的哈希函数能够使冲突数目最小化.Python中并不包含这样高级的哈希函数,几个重要

随机推荐