首页 > 数据库 > Mongodb > Mongodb副本集理论详解
2015
03-06

Mongodb副本集理论详解

 

前言

副本集是一组服务器,其中有一个是主服务器,其余的都是备份服务器,备份服务器只能读不能写。服务器之间通过心跳信息监测彼此是否在线。还需强调一点 一个副本集最多有12个节点,但是同时最多只有其中的7个节点可以进行投票。

 


 

 

88

 

一、副本集成员介绍

主节点

在复制集中唯一的一个接受写请求的节点,并将写的操作记录到oplog中,供从节点使用

从节点

复制主节点的oplog文件并异步的将这些操作应用到自身上,以此保证和主节点的数据集一致。。

投票节点

投票节点没有数据,只是用来选举主服务器的,投票节点的存在使得复制集可以以偶数个节点存在,而无需为复制集再新增节点。

优先级为0的节点

 永远不能成为主节点,并且不能触发选举,但是具有投票权,并且拥有与主节点一致的数据集,能接受读请求

隐藏节点

复制主节点的oplog,并应用到本地保存一致的数据集,但是对于应用程序是隐藏的

是一个优先级为0的节点,永远不能成为主节点,选举时也可以投票

延时节点

从主节点同步数据,但是要比其他节点的数据要延后。(误操作时能用到)

 

一个复制集至少需要这几个成员:一个 主节点 ,一个 从节点 ,和一个 投票节点 。但是在大多数情况下,我们会保持3个拥有数据集的节点:一个 主节点 和两个 从节点 。

二、复制集的高可用

2.1、触发选举的条件

  1. 复制集初始化

  2. 主节点挂掉

  3. 主节点脱离副本集(可能是网络原因)

  4. 参与选举的节点数量必须大于副本集总节点数量的一半,如果已经小于一半了所有节点保持只读状态。

2.1、复制集主节点的选举

  1. 成员的优先级,优先级越高的从节点越有机会成为主节点

  2. 成员不是投票节点,优先级不能为0

  3. 成员的opTime不能落后于最新节点10s以上,越接近主节点的时间越有可能成为主节点

2.2、自动化故障切换

复制集成员每2秒向复制集中其他成员进行心跳检测。如果某个节点在10秒内没有返回,那么它将被标记为不可用,开始选举出新的主服务器

99

 

三、复制集成员个数

官方说复制集中最好是有奇数个成员,如果有偶数个节点,那就加一个投票节点吧,但是我曾经测试的时候发现偶数个节点也是可以。一直都搞不明白为什么必须是奇数,后来发现我们是不是应该站在更高的角度去看,Mongodb的副本集完全可以跨IDC的的分布式数据库,这里我们举个例子就明白了,假如我们有6个节点,有3个节点放在北京的IDC另3个放在天津的IDC,加入北京IDC到天津IDC这条线路出现问题了,我们在上面提到过触发选举的条件,此时主节点已经脱离了副本集,那么就应该开始选举了,我们现在的情况是每个IDC都有3个节点,不满足节点数量必须大于副本集总节点数量的一半的条件,主节点无法选举出来。 这样大家应该明白了吧,为什么官方说必须是奇数个节点,如果不是需要增加一个投票节点!

 

理论点就到此结束,下面开始副本集的配置


一、实验环境

Centos 6.5

IP:192.168.1.92  hostname :tshare365-master

IP:192.168.1.87  hostname :tshare365-slave1

IP:192.168.1.87  hostname :tshare365-slave2

二、Mongodb的安装

请参照我之前的博客 Mongodb的安装部署

三、创建数据目录并启动Mongodb服务(在3台服务器上都执行相同的操作)

mkdir -pv /data/{mongodb,log}
/usr/local/mongodb/bin/mongod --dbpath /data/mongodb/ --logpath /data/log/mongodb.log --logappend  --replSet tshare365  --fork

四、初始化副本集(在master服务器上)

[root@tshare365-master ~]# /usr/local/mongodb/bin/mongo
MongoDB shell version: 2.4.12
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see

http://docs.mongodb.org/

Questions? Try the support group

http://groups.google.com/group/mongodb-user

> use admin
switched to db admin
>

#定义副本集配置变量,这里的 _id:”tshare365” 和上面命令参数“ –replSet tshare365” 要保持一样。

> config = { _id:"tshare365", members:[
... ... {_id:0,host:"192.168.1.92:27017"},
... ... {_id:1,host:"192.168.1.87:27017"},
... ... {_id:2,host:"192.168.1.54:27017"}]
... ... }
{
	"_id" : "tshare365",
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.1.92:27017"
		},
		{
			"_id" : 1,
			"host" : "192.168.1.87:27017"
		},
		{
			"_id" : 2,
			"host" : "192.168.1.54:27017"
		}
	]
}
> 
#初始化副本集
> rs.initiate(config);

{
	"info" : "Config now saved locally.  Should come online in about a minute.",
	"ok" : 1
}
>

五、查看集群节点状态

rs.status()
{
	"set" : "tshare365",
	"date" : ISODate("2015-03-05T02:46:22Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.1.92:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 584,
			"optime" : Timestamp(1425523494, 1),
			"optimeDate" : ISODate("2015-03-05T02:44:54Z"),
			"self" : true
		},
		{
			"_id" : 1,
			"name" : "192.168.1.87:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 88,
			"optime" : Timestamp(1425523494, 1),
			"optimeDate" : ISODate("2015-03-05T02:44:54Z"),
			"lastHeartbeat" : ISODate("2015-03-05T02:46:22Z"),
			"lastHeartbeatRecv" : ISODate("2015-03-05T02:46:22Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.92:27017"
		},
		{
			"_id" : 2,
			"name" : "192.168.1.54:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 88,
			"optime" : Timestamp(1425523494, 1),
			"optimeDate" : ISODate("2015-03-05T02:44:54Z"),
			"lastHeartbeat" : ISODate("2015-03-05T02:46:22Z"),
			"lastHeartbeatRecv" : ISODate("2015-03-05T02:46:22Z"),
			"pingMs" : 2,
			"syncingTo" : "192.168.1.92:27017"
		}
	],
	"ok" : 1
}
tshare365:PRIMARY>

我们看到92是主 87,54都是从,如果输出这样的信息就说明Mongodb主从环境就搭建成功了。下面我们测试一下

六、测试副本数据集复制功能

6.1、在主节点上写入数据

tshare365:PRIMARY> db.tshare365_info.insert({"name":"tshare365","site":"www.tshare365.com"}
... )
tshare365:PRIMARY> db.tshare365_info.find()
{ "_id" : ObjectId("54f7c50d1430d1197a2dd157"), "name" : "tshare365", "site" : "www.tshare365.com" }
tshare365:PRIMARY>

6.2、在从节点上查看数据

[root@tshare365-slave1 /]# /usr/local/mongodb/bin/mongo
MongoDB shell version: 2.4.12
connecting to: test
tshare365:SECONDARY> show dbs
local	1.078125GB
tshare365	0.203125GB
tshare365:SECONDARY> use tshare365
switched to db tshare365
tshare365:SECONDARY> show collections
Wed Feb 25 21:58:03.242 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:128
tshare365:SECONDARY> db.tshare365_info.find()
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
tshare365:SECONDARY>

What,我们查看数据的时候报错了,这是什么情况? 在Mongodb副本集中默认都是从主节点上读写数据的,所以这里会出现这样的错误信息,在数据库的读写分离的场景中,我们需要将从库设置成可读的模式

6.3、Mongodb默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读(在两台从服务器都是需要设置哦)

tshare365:SECONDARY> db.getMongo().setSlaveOk();
tshare365:SECONDARY> db.tshare365_info.find()
{ "_id" : ObjectId("54f7c50d1430d1197a2dd157"), "name" : "tshare365", "site" : "www.tshare365.com" }
tshare365:SECONDARY>

到此我们看到副本集数据复制是正常的,下面我们就测试一下副本集最牛X的功能,故障自动化转移!

七、测试副本集故障转移

7.1、模拟故障环境

#手动关闭主节点
[root@tshare365-master ~]# killall mongod

7.2、在次查看集群状态

[root@tshare365-slave1 ~]# /usr/local/mongodb/bin/mongo
MongoDB shell version: 2.4.12
connecting to: test
tshare365:SECONDARY> rs.status()
{
	"set" : "tshare365",
	"date" : ISODate("2015-02-25T14:17:01Z"),
	"myState" : 2,
	"syncingTo" : "192.168.1.54:27017",
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.1.92:27017",
			"health" : 0,
			"state" : 8,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"lastHeartbeat" : ISODate("2015-02-25T14:17:01Z"),
			"lastHeartbeatRecv" : ISODate("2015-02-25T14:09:44Z"),
			"pingMs" : 0
		},
		{
			"_id" : 1,
			"name" : "192.168.1.87:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 2233,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"self" : true
		},
		{
			"_id" : 2,
			"name" : "192.168.1.54:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1812,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"lastHeartbeat" : ISODate("2015-02-25T14:17:00Z"),
			"lastHeartbeatRecv" : ISODate("2015-02-25T14:17:00Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.92:27017"
		}
	],
	"ok" : 1
}
tshare365:SECONDARY>

我们发现1.92的health 状态变成0,说明心跳信息已经检测不到了 集群通过投票选举出了新的主节点1.54,我们发现故障转移是成功的,是不是感觉很强大呢。

7.3、我们启动1.92原来的主节点,查看集群的状态

我们查看从节点的日志发现1.92重新回归集群,并且成为了从节点,看到状态是STARTUP2

Wed Feb 25 22:21:53.625 [rsHealthPoll] replSet member 192.168.1.92:27017 is up
Wed Feb 25 22:21:53.625 [rsHealthPoll] replSet member 192.168.1.92:27017 is now in state STARTUP2
Wed Feb 25 22:21:55.627 [rsHealthPoll] replSet member 192.168.1.92:27017 is now in state SECONDARY
Wed Feb 25 22:22:07.606 [conn125] end connection 192.168.1.92:7962 (2 connections now open)

查看集群状态

tshare365:PRIMARY> rs.status()
{
	"set" : "tshare365",
	"date" : ISODate("2015-03-05T11:22:41Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.1.92:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 157,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"lastHeartbeat" : ISODate("2015-03-05T11:22:40Z"),
			"lastHeartbeatRecv" : ISODate("2015-03-05T11:22:40Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.54:27017"
		},
		{
			"_id" : 1,
			"name" : "192.168.1.87:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 2267,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"lastHeartbeat" : ISODate("2015-03-05T11:22:41Z"),
			"lastHeartbeatRecv" : ISODate("2015-03-05T11:22:41Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.54:27017"
		},
		{
			"_id" : 2,
			"name" : "192.168.1.54:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 2627,
			"optime" : Timestamp(1425523981, 1),
			"optimeDate" : ISODate("2015-03-05T02:53:01Z"),
			"self" : true
		}
	],
	"ok" : 1
}
tshare365:PRIMARY>

到此故障转移就测试完了,感觉副本集的配置很easy呀!

 

我们在查看日志的时候看到一个1.92的状态是STARTUP2,下面我详解介绍一下服务器的状态

八、服务器状态

STARTUP:刚加入到复制集中,配置还未加载

STARTUP2:配置已加载完,初始化状态

RECOVERING:正在恢复,不适用读

ARBITER: 仲裁者

DOWN:节点不可到达

UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂

REMOVED:移除复制集

ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态

FATAL:出错。查看日志grep “replSet FATAL”找出错原因,重新做同步

PRIMARY:主节点

SECONDARY:备份节点

 

本博客到此结束,感觉副本集的配置还是很简单的,注意是副本集的理论知识,尤其是选举主节点的过程,希望大家好好理解,如果有什么问题,请留言!




最后编辑:
作者:tshare365
这个作者貌似有点懒,什么都没有留下。
捐 赠您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击

留下一个回复