MongoDB实战指南(七):MongoDB复制集之复制集工作机制

http://www.cnblogs.com/longshiyVip/p/5097336.html 概述了复制集,整体上对复制集有了个概念,但是复制集最重要的功能之——自动故障转移是怎么实现的呢?数据同步又是如何实现的?带着这两个问题,下面展开分析。

一. 数据同步

先利用mongo客户端登录到复制集的primary节点上。

>mongo --port 40000

查看实例上所有数据库

rs0:PRIMARY> show dbs
local   0.09375GB

可以看到只有一个local数据库,因为此时还没有在复制集上创建任何其它数据库,local数据库为复制集所有成员节点上默认创建的一个数据库。在primary节点上查看local数据上的集合:

rs0:PRIMARY> show collections

oplog.rs

slaves

startup_log

system.indexes

system.replset

如果是在secondary节点则local数据库上的集合与上面有点不同,secondary节点上没有slaves集合,因为这个集合保存的是需要从primary节点同步数据的secondary节点;secondary节点上会有一个me集合,保存了实例本身所在的服务器名称;secondary节点上还有一个minvalid集合,用于保存对数据库的最新操作的时间截。其它集合primary节点和secondary节点都有,其中startup_log集合表示的是mongod实例每一次的启动信息;system.indexes集合保存的是当前数据库(local)上的所有索引信息;system.replset集合保存的是复制集的成员配置信息,复制集上的命令rs.conf()实际上是从这个集合取的数据返回的。最后要介绍的集合是oplog.rs,这个可是重中之中。

mongoDB就是通过oplog.rs来实现复制集间数据同步的,为了分析数据的变化,先在复制集上的primary节点上创建一个数据库students,然后插入一条记录。

rs0:PRIMARY> use students

switched to db students

rs0:PRIMARY> db.scores.insert({"stuid":1,"subject":"math","score":99});

接着查看一下primary节点上oplog.rs集合的内容:

rs0:PRIMARY> use local

switched to db local

rs0:PRIMARY> db.oplog.rs.find();

返回记录中会多出一条下面这样的记录(里面还有几条记录是复制集初始化时创建的):

{ "ts" : { "t" : 1376838296, "i" : 1 }, "h" : NumberLong("6357586994520331181"),

 "v" : 2, "op" : "i", "ns" : "students.scores", "o" : { "_id" : ObjectId("5210e2

98d7b419b44afa58cc"), "stuid" : 1, "subject" : "math", "score" : 99 } }

里面有几个重要字段,其中"ts"表示是这条记录的时间截,"t"是秒数,"i"每秒操作的次数;字段"op"表示的是操作码,值为"i"表示的是insert操作;"ns"表示插入操作发生的命名空间,这里值为: "students.scores",由数据库和集合名构成;"o"表示的是此插入操作包含的文档对象;

当primary节点完成插入操作后,secondary节点为了保证数据的同步也会完成一些动作:

所有secondary节点检查自己的local数据上oplog.rs集合,找出最近的一条记录的时间截;接着它会查询primary节点上的oplog.rs集合,找出所有大于此时间截的记录;最后它将这些找到的记录插入到自己的oplog.rs集合中并执行这些记录所代表的操作;通过这三步策略,就能保证secondary节点上的数据与primary节点上的数据同步了。整个流程如下图所示:

          复制集数据同步流程

查看一下secondary节点上的数据,证明上面的分析是正确的。

rs0:SECONDARY> show dbs

local   0.09375GB

students        0.0625GB

在secondary节点上新插入了一个数据库students。但是有一点要注意:现在还不能在secondary节点上直接查询students集合上的内容,默认情况下mongoDB的所有读写操作都是在primary节点上完成的,后面也会介绍通过设置从secondary节点上来读,这将引入一个新的主题,后面再分析。

关于oplog.rs集合还有一个很重要的方面,那就是它的大小是固定的,mongoDB这样设置也是有道理的,假如大小没限制,那么随着时间的推移,在数据库上的操作会逐渐累积,oplog.rs集合中保存的记录也会逐渐增多,这样会消耗大量的存储空间,同时对于某个时间点以前的操作记录,早已同步到secondary节点上,也没有必要一直保存这些记录,因此mongoDB将oplog.rs集合设置成一个capped类型的集合,实际上就是一个循环使用的缓冲区。

固定大小的oplog.rs会带来新的问题,考虑下面这种场景:假如一个secondary节点因为宕机,长时间不能恢复,而此时大量的写操作发生在primary节点上,当secondary节点恢复时,利用自己oplog.rs集合上最新的时间截去查找primary节点上的oplog.rs集合,会出现找不到任何记录。因为长时间不在线,primary节点上的oplog.rs集合中的记录早已全部刷新了一遍,这样就不得不手动重新同步数据了。因此oplog.rs的大小是很重要,在32位的系统上默认大小是50MB,在64位的机器上默认是5%的空闲磁盘空间大小,也可以在mongod启动命令中通过项—oplogSize设置其大小。

二. 故障转移

上面的介绍的数据同步相当于传统数据库中的备份策略,mongoDB在此基础还有自动故障转移的功能。在复制集概述那一节提到过心跳"lastHeartbeat"字段,mongoDB就是靠它来实现自动故障转移的。 mongod实例每隔2秒就向其它成员发送一个心跳包以及通过rs.staus()中返回的成员的”health”值来判断成员的状态。如果出现复制集中primary节点不可用了,那么复制集中所有secondary的节点就会触发一次选举操作,选出一个新的primary节点。如上所配置的复制集中如果primary节点宕机了,那么就会选举secondary节点成为primary节点,arbiter节点只是参与选举其它成员成为primary节点,自己永远不会成为primary节点。如果secondary节点有多个则会选择拥有最新时间截的oplog记录或较高权限的节点成为primary节点。oplog记录在前面复制集概述中已经描述过,关于复制集中节点权限配置的问题可在复制集启动的时候进行设置,也可以在启动后重新配置,这里先略过这一点,集中精力讨论故障转移。

如果是某个secondary节点失败了,只要复制集中还有其它secondary节点或arbiter节点存在,就不会发生重新选举primary节点的过程。

下面模拟两种失败场景:一是secondary节点的失败,然后过一段时间后重启(时间不能无限期,否则会导致oplog.rs集合严重滞后的问题,需要手动才能同步);二是primary节点失败,故障转移发生。

先分析第一种情况的测试,当前复制集的配置情况如下:

(1)

rs0:PRIMARY> rs.conf()

{

"_id" : "rs0",

"version" : 3,

"members" : [

{

"_id" : 0,

"host" : "Guo:40000" //primary节点

},

{

"_id" : 1,

"host" : "Guo:40001" //secondary节点

},

{

"_id" : 2,

"host" : "Guo:40002", //arbiter节点

"arbiterOnly" : true

}

]

}

(2)通过Kill掉secondary节点所在的mongod实例,模拟第一种故障情况,如下图所示:

    模拟secondary节点故障

通过rs.status()命令查看复制集状态,secondary节点状态信息如下:

"_id" : 1,

"name" : "Guo:40001",

"health" : 0,

"state" : 8, //表示成员已经down机

"stateStr" : "(not reachable/healthy)",

"uptime" : 0,

"optime" : {

"t" : 1376838296,

"i" : 1

},

"optimeDate" : ISODate("2013-08-18T15:04:56Z")

(3)接着通过primary节点插入一条记录:

rs0:PRIMARY> db.scores.insert({stuid:2,subject:"english",score:100})

(4)再次查看复制集状态信息rs.status(),可以看到primary成员节点上oplpog信息如下:

"optime" : {

"t" : 1376922730,

"i" : 1

},

"optimeDate" : ISODate("2013-08-19T14:32:10Z"),

与上面down机的成员节点比较,optime已经不一样,primary节点上要新于down机的节点。

(5)重新启动Kill掉的节点

>mongod --config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_1.conf

查询复制集状态信息rs.status(),观看节点"Guo:40001"的状态信息如下:

"_id" : 1,

"name" : "GUO:40001",

"health" : 1,

"state" : 2,

"stateStr" : "SECONDARY",

"uptime" : 136,

"optime" : {

"t" : 1376922730, //与上面primary节点一致了

"i" : 1

},

"optimeDate" : ISODate("2013-08-19T14:32:10Z"),

说明secondary节点已经恢复,并且从primary节点同步到了最新的操作数据。进一步通过查询secondary节点上local数据库上的oplog.rs集合来进行验证,发现多了一条下面这样的记录:

{ "ts" : { "t" : 1376922730, "i" : 1 }, "h" : NumberLong("-451684574732211704"),

"v" : 2, "op" : "i", "ns" : "students.scores", "o" : { "_id" : ObjectId("52122c

6a99c5a3ae472a6900"), "stuid" : 2, "subject" : "english", "score" : 100 } }

这正是在primary节点上插入的记录,再次证明数据确实同步过来了。

接下来测试第二种情况,假如primary节点故障,流程变化如下图所示:

      模拟primary节点失败并恢复后

(1)将primary节点Kill掉。

查询复制集的状态信息rs.status()

"name" : "Guo:40000",

"health" : 0,

"state" : 8,

"stateStr" : "(not reachable/healthy)"

字段"health"的值为0,说明原来的primary节点已经down机了。

"name" : "Guo:40001",

"health" : 1,

"state" : 1,

"stateStr" : "PRIMARY"

字段"stateStr"值为"PRIMARY",说明原来secondary节点变成了primary节点。

(2)在新的primary节点上插入一条记录

rs0:PRIMARY> db.scores.insert({stuid:3,subject:"computer",score:99})

(3)重新恢复"Guo:40000"节点(原来的primary节点)

>mongod --config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_0.conf

再次查看复制集状态rs.status()

"name" : "Guo:40000",

"health" : 1,

"state" : 2,

"stateStr" : "SECONDARY",

"uptime" : 33,

"optime" : {

"t" : 1376924110,

"i" : 1

},

当"Guo:40000"实例被重新激活后,变成了secondary节点,oplog也被同步成最新的了。说明当primary节点故障时,复制集能自动转移故障,将其中一个secondary节点变为primary节点,读写操作继续在新的primary节点上进行。原来primary节点恢复后,在复制集中变成了secondary节点。

上面两中情况都得到了验证,但是有一点要注意,mongDB默认情况下只能在primary节点上进行读写操作,如下图所示:

    默认的读写流程图

  对于客户端应用程序来说,对复制集的读写操作是透明的,默认情况它总是在primary节点上进行。 mongoDB提供了很多种常见编程语言的驱动程序,驱动程序位于应用程序与mongod实例之间,应用程发起与复制集的连接,驱动程序自动选择primary节点。当primary节点失效,复制集发生故障转移时,复制集将先关闭与所有客户端的socket连接,驱动程序将返回一个异常,应用程序收到这个异常,这个时候需要应用程序开发人员去处理这些异常,同时驱动程序会尝试重新与primary节点建立连接(这个动作对应用程序来说是透明的)。假如这个时候正在发生一个读操作,在异常处理中你可以重新发起读数据命令,因为读操作不会改变数据库的数据;假如这个时候发生的是写操作,情况就变得微妙起来,如果是非安全模式下的写,就会产生不确定因素,写是否成功不确定,如果是安全模式,驱动程序会通过getlasterror命令知道哪些写操作成功了,哪些失败,驱动程序会返回失败的信息给应用程序,针对这个异常信息,应用程序可以决定怎样处置这个写操作,可以重新执行写操作,也可以直接给用户暴出这个错误。

时间: 2024-10-21 19:38:00

MongoDB实战指南(七):MongoDB复制集之复制集工作机制的相关文章

MongoDB实战指南(四):MongoDB的Journaling日志功能

mongoDB的Journaling日志功能与常见的log日志是不一样的,mongoDB也有log日志,它只是简单记录了数据库在服务器上的启动信息.慢查询记录.数据库异常信息.客户端与数据库服务器连接.断开等信息.Journaling日志功能则是mongoDB里面非常重要的一个功能,它保证了数据库服务器在意外断电.自然灾害等情况发生下数据的完整性.尽管mongoDB还提供了其它的复制集等备份措施(后面会分析),但Journaling的功能在生产环境中是不可缺少的,它依靠了较小的CPU和内存消耗,

mongodb权威指南之mongodb基础知识学习记录

mongo show dbs查看所有的数据库 使用use可以切换数据库,如果没有数据库则创建一个新的 use local切换倒local数据库 增加数据 db.test.insert({name:"jack"})向test表中插入一条数据,如果没有test表则创建一个,如果传入一个文档数组则会批量插入. 批量插入 db.test.batchInsert([{"_id":0, "_id":1}])接受一个文档数组作为参数,如果插入过程中有个文档插入

57-1、2、3 NoSQL基础及MongoDB、MongoDB基本应用、mongodb索引及复制集

02MongoDB基本应用 配置环境: node1:192.168.1.121CentOS release 6.7 [[email protected] ~]# cd mongodb-2.6.4/ [[email protected] mongodb-2.6.4]# ls mongodb-org-2.6.4-1.x86_64.rpm         mongodb-org-shell-2.6.4-1.x86_64.rpm mongodb-org-mongos-2.6.4-1.x86_64.rpm

MongoDB集群复制部署

简介: 本文总结了MongoDB 3.2版本的集群复制集部署步骤. 要求: •该集群中包含2个分片(shard) •每个分片都是1个副本集 •分片副本集.配置服务器都需要考虑到单机故障的情况,保证可用性 •为了减小实验数据占据磁盘空间.加快实验速度,将每个分片的mongodb服务oplogSize设置在100以下 •部署前,做好部署准备工作,记录部署架构 部署前准备工作: 根据要求,绘制出集群部署架构图,如下图所示: 两台Linux服务器,服务器版本为CentOS-6.6,为实现高可用配置两个复

【MongoDB】windows平台搭建Mongo数据库复制集(类似集群)(转)

原文链接:[MongoDB]windows平台搭建Mongo数据库复制集(类似集群)(一) Replica  Sets(复制集)是在mongodDB1.6版本开始新增的功能,它可以实现故障自动切换和自动修复功能成员节点的功能,各个DB之间的数据完全一致,大大降低了单点故障的风险. [] 以上图示是三个节点的Replica Set架构.该图来源于红丸编写的<Mongodb管理与开发精要>这本书.从上图可以看出,结构类似与一个集群,其实完全可以当做一个集群.因为它确实和集群实现的作用是相同的. 一

MongoDB 部署复制集(副本集)

环境 操作系统:Ubuntu 18.04 MongoDB: 4.0.3 服务器 首先部署3台服务器,1台主节点 + 2台从节点 3台服务器的内容ip分别是: 10.140.0.5 (主节点) 10.140.0.6 (从节点01) 10.140.0.7 (从节点02) 安装MongoDB 接下来,需要在每一台服务器上安装MongoDB. 完整安装过程可参考官方文档. 为了方便,本文提供MongoDB的一键安装脚本. 切换成root用户 sudo su - 运行安装脚本 wget https://g

MongoDB基础入门之一:基础入门和复制集

mongoDB基础入门 介绍 mongoDB是一个存储文档的非关系型数据库 mongoDB的结构: 数据库: 包含集合 集合: 存储文档 文档: json格式 一条命令在docker容器中运行mongoDB docker run --name mymongo -v /mongo/data:/data/db -d mongo:4 docker ps #查看容器状态 docker logs mymongo #查看日志 mongoExpress 的使用 基于网络的mongoDB数据库管理页面 dock

mongodb 权威指南 pdf

需要学习的同学可以通过网盘下载pdf: http://tadown.com/ls/yibenshu/ccecc15b/内容简介  · · · · · · mongodb如何帮你管理通过web应用收集的海量数据呢?通过本书的权威解读,你会了解面向文档数据库的诸多优点,会发现mongodb如此稳定.性能优越甚至能够无限水平扩展背后的原因. <mongodb权威指南>的两位作者来自开发并支持开源数据库mongodb的公司10gen.数据库开发人员可将此书作为参考指南,系统管理员可以从本书中找到高级配

【MongoDB】02、MongoDB索引及复制

一.索引 索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录.这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的. 索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构 1.索引的类型 B+ Tree.hash.空间索引.全文索引 MongoDB支持的索引: 单字索引.组合索引(多字段索引).