复制是基于操作日志oplog,相当于MySQL中的二进制日志,只记录发生改变的记录,复制是将主节点的oplog日志同步并应用到其他从节点的过程。

首先要理解两个概念:
1、复制:提供冗余和高可用性;
2、拆分分片:提供水平扩容;

复制提供冗余并增加数据可用性。通过在不同数据库服务器上提供多个数据副本,复制可以提供对单个数据库服务器丢失的级别容错。

主要概念:

  • 副本集
  • OPLOG(operations log)
  • 多副本策略(超过3个)
  • 副本集选举
  • 写关注
  • 读偏好

副本集

副本集的成员是:

  • 主节点:主要接收所有写操作。
  • 辅助节点:辅助节点从主节点复制以维护相同的数据集。

副本集包含:

  • 多个数据承载节点(主节点、辅助节点);
  • 可选的一个仲裁节点;

在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要节点。
如下图:

可以将一个额外的mongod实例添加到副本集中作为仲裁者。确保副本集具有奇数个投票成员。如果您拥有偶数个投票成员,请部署仲裁者以使该集合具有奇数个投票成员。
仲裁者不维护数据集。仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的大多数投票。
如下图:


自动故障转移
当主节点与集合中的其他成员通信的时间超过配置的electionTimeoutMillis期间(默认为 10 秒)时,符合条件的辅助节点用于选举以指定自己作为新主节点。
如下图:


在选举成功完成之前,副本集不能处理写操作
默认情况下,clients 从主节点读取;但是,clients 也可以指定阅读偏好来向辅助节点读取。
异步复制到辅助节点意味着从辅助节点读取可能会返回不反映主节点上数据的(最后一次更新状态的)真实值的数据。

OPLOG

OPLOG(operations log)是一个特殊的上限集合,它保存了修改存储在数据库中的数据的所有操作的历史记录。 复制是将主节点的oplog日志同步并应用到其他从节点的过程。
MongoDB 在主节点上应用数据库操作(添加、删除等),然后在 oplog 上记录操作,然后辅助节点异步操作中复制并应用这些操作。为了便于复制,所有副本集成员都会向所有其他成员发送心跳(ping)。任何辅助节点都可以导入来自任何其他成员的 oplog 条目。oplog 中的每个操作都是幂等。也就是说,无论是对目标数据集应用一次还是多次,oplog 操作都会产生相同的结果。

oplog 大小取决于存储引擎:

多副本策略(超过3个)

以具有 5 个成员的副本集为例,一些可能的成员分布包括:

  • 两个数据中心:数据中心 1 的三个成员和数据中心 2 的两个成员。
  • 如果数据中心 1 关闭,则副本集将变为 read-only。
  • 如果数据中心 2 关闭,则副本集仍然可写,因为数据中心 1 中的成员可以创建多数。
  • 三个数据中心:数据中心 1 的两个成员,数据中心 2 的两个成员和数据中心 3 的一个成员。
  • 如果任何数据中心发生故障,副本集仍然可写,因为其余成员可以举行选举。

如图
例如,以下 5 个成员副本集将其成员分布在三个数据中心

副本集选举

触发副本集选举的事件如下:

  • 将新节点添加到副本集;
  • 启动副本集;
  • 使用rs.stepDown()或rs.reconfig()等方法执行副本集维护;
  • 次节点失去与主节点的连接超过配置的超时(默认为 10 秒)。

在选举成功完成之前,副本集不能处理写操作。如果此类查询配置为run on secondaryaries,则副本集可以继续提供读取查询。

心跳
副本集成员每两秒发送一次心跳(ping)。如果心跳在 10 秒内没有回复,则其他成员会将其标记为无法访问。

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

  • 心跳: 复制集中的所有members之间都互相建立心跳连接,且每隔两秒发送一次心跳,如果未在10秒内收到回复,则此member将会被标记为“不可用”,Secondary(前提是可被选为Primary)会发起新的Primary选举,而其他能正常收到心跳反馈的Secondary能否决新的Primary选举。
  • 优先级: 优先级即Priority值,每个member都有权重值,默认为都为1,members倾向于选举权重最高者。上述提到,priority为0的member不能被选举为primary且不能发起选举;只要当前primary的权重最高或者持有最新oplog数据的secondaries没有比它更高的权重时,集群不会触发选举。当Primary发现有优先级更高Secondary,并且该Secondary的数据落后在10s内,则Primary会主动降级,让优先级更高的Secondary有成为Primary的机会。
  • Optime: 当前member已经从primary的oplog中应用的最后一个operation的时间戳(此时间戳由primary生成,在oplog中每个操作记录都有);一个member能成为primary的首要条件就是在所有有效的members中它持有最新的optime。
  • 多数派连接: 一个member要成为primary,它必须与“多数派”的其他members建立连接,如果未能与足够多的member建立连接,事实上它本身也无法被选举为primary;多数派参考的是“总票数”,而不是member的个数,因为我们可以给每个member设定不同的“票数”。假设复制集内投票成员数量为N,则大多数为 N/2 + 1。

写关注

用来描述数据库写操作返回信息的保证级别。写关注的强度决定了保证的级别。当插入,更新,删除是弱写关注的时候,操作返回的速度则快。如果写关注是弱的,在一些写失败的时候,写操作可能不会持久。写关注级别越强,客户端则需要越长的时间来等待MongoDB确认写操作。

例如对于副本集,w:1的默认写入关注要求在返回写入关注确认之前,只有主副本集成员确认写入,才予以返回。
如图:


为任何给定的写操作选择理想的写入关注取决于您的应用的性能目标和数据持久性要求。关键数据,可以牺牲性能的,就设置大一些,非关键数据,w:1的默认写入关注就可以了。

以下操作包括insert()方法的writeConcern选项。该操作使用wtimeout写入关注参数指定“多数”写入关注和 5 秒超时,以便操作不会无限期地阻塞。

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

例如,在 3-member 副本集中,操作将需要来自 3 个成员中的 2 个的确认。如果稍后缩放副本集以包括两个额外的投票节点,则相同的操作将需要来自 5 个副本集成员中的 3 个的确认。如果主要没有在wtimeout限制内 return 写入关注确认,则写入操作将失败并出现写入问题错误。

读偏好

在某些情况下,将读请求发送给副本集的备份节点是合理的,例如,单个服务器无法处理应用的读压力,就可以把查询请求路由到可复制集中的多台服务器上。
5种读偏好模式:

  • primary — 这是默认的设置,表明只从可复制集的主节点读取数据,因此具有强一致性。如果可复制集有问题,并且没有可选举的从节点,就表示出现错误。
  • premaryPreferred — 设置了此参数的驱动会从主节点读取数据,除非某些原因使主节点不可用或者没有主节点,此时它会从从节点读取数据。此种设置下,读请求无法保证一致性。
  • secondary — 这个设置告诉驱动应该一直从从节点读取数据。这种设置对于我们想确保读请求不会影响主节点的写入请求时非常有用。如果没有可用的从节点,读请求会抛出异常。
  • secondarypreferred — 读请求会发出到从节点,除非没有从节点可用,此时才会从主节点读取。
  • nearest – 驱动会尝试从最近的可复制集成员节点读取读取数据,通过网络延迟判断。可以是主节点也可以是从节点。因此读请求只会发送给驱动认为最快通信的节点。

primary是唯一一个可以确保读一致的模式。因为写请求首先在主节点完成,从服务器的更新会有些延迟,所以可能在从节点无法找到刚刚在主节点写入的文档数据。

考虑一下不需要读一致的场景,可以考虑使用其他模式:

  • 1、为地理位置分散的应用程序提供数据读取(不要求一致性)。

    •   如果您在多个数据中心中有服务器,则可以考虑使用地理分布的副本集并使用secondary或nearest首选项。
  • 2、在故障转移期间维护可用性
    •   如果希望应用在正常情况下从主数据库读取,则使用primaryPreferred,但是当主数据库不可用时允许从辅助数据库读取过时数据。

实操

通过发出类似于以下内容的命令为每个成员创建必要的数据目录:

mkdir -p /srv/mongodb/rs0-0 /srv/mongodb/rs0-1 /srv/mongodb/rs0-2

这将创建名为“rs0-0”,“rs0-1”和“rs0-2”的目录,它们将包含实例的数据库 files。

第一位成员:

mongod --replSet rs0 --port 27017 --bind_ip localhost,<ip address of mongod host> --dbpath /srv/mongodb/rs0-0 --smallfiles --oplogSize 128

第二位成员:

mongod --replSet rs0 --port 27018 --bind_ip localhost,<ip address of mongod host> --dbpath /srv/mongodb/rs0-1 --smallfiles --oplogSize 128

第三名成员:

mongod --replSet rs0 --port 27019 --bind_ip localhost,<ip address of mongod host> --dbpath /srv/mongodb/rs0-2 --smallfiles --oplogSize 128

这会将每个实例作为名为rs0的副本集的成员启动,每个副本在不同的 port 上运行,并使用--dbpath设置指定数据目录的路径。如果您已在使用建议的端口,请选择不同的端口。

实例绑定到 host 的 localhost 和 ip 地址。

--smallfiles和--oplogSize设置减少了每个mongod实例使用的磁盘空间。这是测试和开发部署的理想选择,因为它可以防止机器过载。

mongo --port 27017

在mongo shell 中,使用rs.initiate()启动副本集。您可以在mongo shell 环境中创建副本集 configuration object,如下面的示例所示:

rsconf = {
_id: "rs0",
members: [
{
_id: 0,
host: "<hostname>:27017"
},
{
_id: 1,
host: "<hostname>:27018"
},
{
_id: 2,
host: "<hostname>:27019"
}
]
}

用系统的主机名替换<hostname>,然后将rsconf文件传递给rs.initiate(),如下所示:

rs.initiate( rsconf )
通过发出以下命令显示当前副本 configuration:
rs.conf()
{
"_id" : "rs0",
"version" : 1,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "<hostname>:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "<hostname>:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "<hostname>:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"getLastErrorModes" : { },
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("598f630adc9053c6ee6d5f38")
}
}

使用rs.status()操作检查副本集的状态。

MongoDB开发深入之三:复制的更多相关文章

  1. MongoDB开发最佳实践

    MongoDB开发最佳实践 连接到MongoDB · 关于驱动程序:总是选择与所用之MongoDB相兼容的驱动程序.这可以很容易地从驱动兼容对照表中查到: · 如果使用第三方框架(如Spring Da ...

  2. [转载]MongoDB开发学习(2)索引的基本操作

    索引能够极大的提高查询的效率.在数据库中简历索引必不可少. 在MongoDB中可以很轻松的创建索引. 默认索引_id_ 开启MongoDB服务器,创建数据库cnblogs,创建集合Users .(关于 ...

  3. 利用Sails.js+MongoDB开发博客系统

    http://yoyoyohamapi.me/categories/利用Sails-js-MongoDB开发博客系统/ 利用Sails.js+MongoDB开发博客系统 Apr 14, 2016 利用 ...

  4. [原创].NET 分布式架构开发实战之三 数据访问深入一点的思考

    原文:[原创].NET 分布式架构开发实战之三 数据访问深入一点的思考 .NET 分布式架构开发实战之三 数据访问深入一点的思考 前言:首先,感谢园子里的朋友对文章的支持,感谢大家,希望本系列的文章能 ...

  5. AngularJS + Node.js + MongoDB开发

    AngularJS + Node.js + MongoDB开发的基于位置的通讯录(by vczero) 一.闲扯 有一天班长说了,同学们希望我开发一个可以共享位置的通讯录,于是自己简单设计了下功能.包 ...

  6. 基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统

    很久没更新博客,最近也有点忙,然后业余时间搞了一个比较完整基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统的流程系统,希望对 ...

  7. 结合MongoDB开发LBS应用(转)

    原文链接:结合MongoDB开发LBS应用 简介 随着近几年各类移动终端的迅速普及,基于地理位置的服务(LBS)和相关应用也越来越多,而支撑这些应用的最基础技术之一,就是基于地理位置信息的处理.我所在 ...

  8. MongoDB之Replica Set(复制集复制)

    MongoDB支持两种复制模式: 主从复制(Master/Slave) 复制集复制(Replica Set) 下面主要记录我在centos虚拟机上安装replica set,主要参考:http://d ...

  9. Studio 3T for MongoDB连接51.212复制集

    Studio 3T for MongoDB连接51.212复制集 [ #DirectConection Authentication Mode - Basic(MONGODB-CR or SCEAM- ...

随机推荐

  1. Django 的 cbv

    Django 的 cbv 正如我们了解到的,Django 写视图函数有两种写法:cbv 和 fbv.cbv 提倡使用类来写,fbv 使用函数来 写.当然为了代码的重复行,官方更推荐使用 cbv. 写 ...

  2. Nuxt 知识点

    脚手架工具 create-nuxt-app 创建项目: $ npx create-nuxt-app <项目名> 启动项目: To get started: cd nuxt_demo npm ...

  3. http 和 https(通俗原理了解)

    超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂 ...

  4. Educational Codeforces F. Remainder Problem

    [传送门] 题意就是单点加以及查询下标为等差数列位置上的值之和.刚开始看到这道题.我以为一个数的倍数是log级别的.就直接写了发暴力.就T了.还在想为啥,优化了几发才发现不太对劲.然后才想到是$\df ...

  5. Wooden Signs Gym - 101128E (DP)

    Problem E: Wooden Signs \[ Time Limit: 1 s \quad Memory Limit: 256 MiB \] 题意 给出一个\(n\),接下来\(n+1\)个数, ...

  6. node.js封装数据库增删改查

    数据库增删改查的封装 小编不容易 const sql = { insert: function (Collection, insertData) { return new Promise((resol ...

  7. Markdown&Latex学习笔记,qwq

    目录 推荐的文章 居中 字体 加颜色 指数 分数 根号 神奇的符号(不要多想qwq) 箭头 小于号 大括号 累加符号 累乘符号 下标 \(\phi\)&\(\varphi\) \(\equiv ...

  8. 洛谷 P2634 [国家集训队]聪聪可可-树分治(点分治,容斥版) +读入挂+手动O2优化吸点氧才过。。。-树上路径为3的倍数的路径数量

    P2634 [国家集训队]聪聪可可 题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一 ...

  9. shell 只读变量

    test.sh: #!/bin/bash myUrl="http://www.google.com" readonly myUrl myUrl="http://www.r ...

  10. mybatis之批量查询

    关于MyBatis批量更新和添加,参考我的如下文章即可:MyBatis的批量更新实例 MyBatis的批量添加实例 另外不管是批量的新增.删除.修改.查询也好,还是单个新增.删除.修改查询也罢.都会用 ...