马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
MongoDB副本集(Replica Set)作为MongoDB数据库的焦点功能之一,为开发人员提供了一种简单而有效的方式来实现数据的高可用性和冗余备份。在本文中,我们将探讨MongoDB副本集的概念、工作原理以及如何设置和管理一个妥当的副本集环境。
关于MongoDB分片介绍与摆设,可以参考:
MongoDB分片介绍与摆设
一、副本集介绍
1、副本集(replica set)
MongoDB的副本集(Replica Set)是一组MongoDB进程实例的聚集,其中的数据相互复制,并自动进行故障转移。
通过MongoDB的数据库复制,系统增长了冗余性,确保了高可用性,简化了管理任务,如备份,而且提升了读取性能。大多数生产摆设都会采用复制功能。在MongoDB中,主节点(Primary)负责处置惩罚写操作,而其他复制成员则是次要节点(Secondaries)。
2、成员脚色
成员可以是以下某种脚色:
3、故障切换恢复
副本集可以或许自动进行故障切换和恢复。如果主节点(Primary)掉线或无相应,而且多数副本集成员可以或许相互连接,系统将选出一个新的主节点。
通常环境下,当主节点发生故障、不可用或不适合作为主节点时,在几秒内没有管理员干预,副本集会会议自动进行故障切换。
如果MongoDB摆设未按预期进行故障切换,则可能出现以下问题:
- 副本集剩余成员数量少于总数的一半
- 没有适合成为主节点的成员
4、回滚(Rollback)
在大多数环境下,回滚操作可以或许优雅地处置惩罚无法进行故障切换恢复的环境。回滚操作发生在主节点(Primary)处置惩罚写操作时,但在其他成员尚未乐成复制该操作之前主节点掉线。当之前的主节点重新到场副本集并开始进行复制时,会出现回滚操作。如果操作已经乐成复制到其他成员,而且这些成员可用且可以或许连接到大多数副本集成员,则不会发生回滚。回滚操作会删除那些尚未复制到其他成员的操作,以确保数据集的一致性。
5、推选(Elections)
在任何以障切换发生时,都会触发一次推选,以确定哪个成员将成为主节点。推选提供了一种机制,使得副本集中的成员无需管理员干预,就能自动选出一个新的主节点。推选可以或许让副本集快速而可靠地从故障中恢复。当主节点变得不可达时,次要成员会发起推选,第一个收到大多数选票的成员将成为新的主节点。
6、成员优先级
在副本集中,每个成员都有优先级,它可以帮助决定推选出primary。默认环境下,全部的成员的优先级都为1。
7、一致性
在MongoDB中,全部针对主节点(Primary)的读操作都包管与最后一次写操作效果一致。如果客户端设置了答应从次要节点(Secondary)读取的读选项,读操作可能会从没有实时复制更新或操作的次要节点返回效果。在这种环境下,查询操作可能会返回之前的状态。
这种行为偶然被称为最终一致性,由于次要节点的状态最终会与主节点的状态一致。MongoDB不能包管从次要节点读取的读操作具有强一致性。
除非在设置写操作乐成后,确保全部节点上的写操作都乐成执行,否则无法包管从次要节点读取的一致性。
副本集分片集群的架构:
二、副本集设置
三成员副本集为大多数网络分区和系统故障提供了充足的冗余。另外,这些聚集有充足的分布式读操作能力。大多数摆设不需要额外的成员或设置。
有三个服务器:
- Server1 : 218.30.117.193
- Server2 : 218.30.117.195
- Server3 : 218.30.117.196
复制代码 需求:
大多数副本集由三个或更多个mongod实例组成。这里形貌了一个三成员副本集。在生产环境中,应至少有三个独立的系统,每个系统上运行一个单独的mongod实例。在开发系统中,你可以在一个本地系统或虚拟系统中运行三个mongod实例。在生产环境中,应尽可能将副本集成员分隔开来。
摆设一个开发测试副本集
1、这个例子中创建了一个名为rs0的副本集。
(1) 在创建副本集之前,确认每个成员都能乐成的连接到其它成员上。网络设置必须答应恣意成员之间的连接。
(2) 运行作为rs0副本集的成员的三个mongod实例。
2. 创建必要的数据目录
命令如下:
- mkdir –p /srv/mongodb/rs0-0 /srv/mongodb/rs0-1 /srv/mongodb/rs0-2
复制代码 3. 打开多个窗口,在差别的窗口下执行下面的命令:
- mongod --port 27017 --dbpath /srv/mongodb/rs0-0 --replSet rs0 --smallfiles --oplogSize 128
- mongod --port 27018 --dbpath /srv/mongodb/rs0-1 --replSet rs0 --smallfiles --oplogSize 128
- mongod --port 27019 --dbpath /srv/mongodb/rs0-2 --replSet rs0 --smallfiles --oplogSize 128
复制代码 这运行了每个rs0副本集成员的实例,运行在差别的端口。如果你已经利用了这些端口,则可以利用其他的端口。
每个mongod测试利用的--smallfiles和--oplogSize选项低沉了磁盘空间。
4、打开一个mongo shell并连接第一个mongod实例,命令如下:
5、在mongo shell环境中创建一个副本集设置对象,用于初始化副本集,命令如下:
- rsconf = {
- _id: "rs0",
- members: [
- {
- _id: 0,
- host: "<hostname>:27017"
- }
- ]
- }
复制代码 6、利用rs.initiate()命令初始化由当前成员组成的副本集,并利用默认设置:
7、显示当前副本集的设置
8、通过rs.add()命令向副本集中添加第二和第三个mongod实例。用你的主机名更换下例中的<hostname>:
- rs.add("<hostname>:27018")
- rs.add("<hostname>:27019")
复制代码 在这些命令后,将返回一个功能完备的副本集,新的副本集会会议在几秒内推选出主成员。
9、通过rs.status()命令随时检查你的副本集的状态
摆设一个生产副本集
摆设一个生产副本集与开发测试副本集很相似,但有以下差别:
- 每个副本集成员都运行在单独的机器上,而且MongoDB进程都绑定端口27017。
- 每个副本集成员都必须通过DNS解析可达或者主机名如下(设置得当的DNS名或设置系统的/etc/hosts文件以反映设置):
- mongodb0.example.net
- mongodb1.example.net
- mongodb2.example.net
复制代码 - 你在每个系统指定一个运行时的设置以一个设置文件的形式,存放在/etc/mongodb.conf或者一个相关的位置。你不能通过命令行选项指定一个运行时设置。
对于每个mongoDB实例,利用下面的设置。针对于你的系统设置得当的设置参数:
- port = 27017
- bind_ip = 10.8.0.10
- dbpath = /srv/mongodb/
- fork = true
- replSet = rs0
复制代码 不愿定需要指定bind_ip接口。然而,如果你不知道一个接口,则MongoDB会监听全部的可用IPv4的接口上的连接。修改bind_ip反映出系统上的安全接口,它可以或许访问其他的聚集成员,而且其他副本集成员也能访问当前成员。DNS或主机名必须指定并解析成IP所在。
1、在创建你的副本集之前,确认每个成员都能乐成的连接到其它成员上。网络设置必须答应恣意成员之间的连接。
2、每个运行mongod进程的系统上执行下面的命令:
- mongod --config /etc/mongodb.conf
复制代码 3、启动一个mongo shell连接这个主机
4、利用rs.initiate()命令初始化由当前成员组成的副本集,并利用默认设置
5、显示当前副本集设置
6、向副本集中增长两个成员,命令如下:
- rs.add("mongodb1.example.net")
- rs.add("mongodb2.example.net")
复制代码 在这些命令后,将返回一个功能完备的副本集,新的副本集会会议在几秒内推选出主成员。
7、通过rs.status()命令随时检查你的副本集的状态。
三、副本集摆设
1、启动mongod
在每台运行mongod服务的机器上增长设置文件/etc/mongodb-rs.conf,内容为:
- port = 27017
- dbpath = /usr/tmp/mongodb
- logpath = /usr/tmp/mongodb/log.log
- fork = true
- replSet = rs0
复制代码 创建/usr/tmp/mongodb目录
- mkdir -p /usr/tmp/mongodb
复制代码 通过下面命令启动mongod:
- /usr/local/mongodb/bin/mongod -f /etc/mongodb-rc.conf
复制代码 2、修改每个机器的/etc/hosts
在每台机器的/etc/hosts文件中增长:
- 218.30.117.193 mongodb1.example.net
- 218.30.117.195 mongodb2.example.net
- 218.30.117.196 mongodb3.example.net
复制代码 3、利用mongo shell连接mongod,进行设置,可以看到当前副本集的状态。
- /usr/local/mongodb/bin/mongo 218.30.117.193
- MongoDB shell version: 2.4.2
- connecting to: 218.30.117.193/test
- > config = {_id:'rs0', members: [
- ... {_id:0, host:'mongodb1.example.net'},
- ... {_id:1, host:'mongodb2.example.net'},
- ... {_id:2, host:'mongodb3.example.net'}]}
- > rs.initiate(config)
- > rs.status()
复制代码 4、故障切换
假设193为Primary,其它为Secondary,则可以利用mongo shell连接195,看到下面效果
- /usr/local/mongodb/bin/mongo 218.30.117.195
- MongoDB shell version: 2.4.2
- connecting to: 218.30.117.195/test
- rs0:SECONDARY> rs.isMaster()
- {
- "setName" : "rs0",
- "ismaster" : false,
- "secondary" : true,
- "hosts" : [
- "mongodb2.example.net:27017",
- "mongodb3.example.net:27017",
- "mongodb1.example.net:27017"
- ],
- "primary" : "mongodb1.example.net:27017",
- "me" : "mongodb2.example.net:27017",
- "maxBsonObjectSize" : 16777216,
- "maxMessageSizeBytes" : 48000000,
- "localTime" : ISODate("2013-05-15T06:14:01.153Z"),
- "ok" : 1
- }
复制代码 同样可以登录196查看其状态。
我们停止193的mongod,然后发现已经mongo shell连接不上,而通过另外两个成员可以看到副本集的状态:
- /usr/local/mongodb/bin/mongo 218.30.117.195
- MongoDB shell version: 2.4.2
- connecting to: 218.30.117.195/test
- rs0:PRIMARY> rs.status()
- {
- "set" : "rs0",
- "date" : ISODate("2013-05-15T06:16:03Z"),
- "myState" : 1,
- "members" : [
- {
- "_id" : 0,
- "name" : "mongodb1.example.net:27017",
- "health" : 0,
- "state" : 8,
- "stateStr" : "(not reachable/healthy)",
- "uptime" : 0,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "lastHeartbeat" : ISODate("2013-05-15T06:16:02Z"),
- "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
- "pingMs" : 0,
- "syncingTo" : "mongodb3.example.net:27017"
- },
- {
- "_id" : 1,
- "name" : "mongodb2.example.net:27017",
- "health" : 1,
- "state" : 1,
- "stateStr" : "PRIMARY",
- "uptime" : 644,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "self" : true
- },
- {
- "_id" : 2,
- "name" : "mongodb3.example.net:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 299,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "lastHeartbeat" : ISODate("2013-05-15T06:16:02Z"),
- "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
- "pingMs" : 3,
- "lastHeartbeatMessage" : "syncing to: mongodb2.example.net:27017",
- "syncingTo" : "mongodb2.example.net:27017"
- }
- ],
- "ok" : 1
- }
复制代码 可以看出,195自动成为Primary,196继续为Secondary,而193的health已经变为0,stateStr变为(not reachable/healthy)。
我们可以重新启动193上的mongod,并将其priority设为2,高于另外两个成员的优先级:
- rs0: PRIMARY> conf = rs.config()
- rs0: PRIMARY> conf.members[0].priority=2
- rs0: PRIMARY> rs.reconfig(conf)
复制代码 查看当前副本集成员设置信息:
- rs0: PRIMARY > rs.config()
- {
- "_id" : "rs0",
- "version" : 2,
- "members" : [
- {
- "_id" : 0,
- "host" : "mongodb1.example.net:27017",
- "priority" : 2
- },
- {
- "_id" : 1,
- "host" : "mongodb2.example.net:27017"
- },
- {
- "_id" : 2,
- "host" : "mongodb3.example.net:27017"
- }
- ]
- }
复制代码 在之前的primary上,几秒钟后命令标识已经变为SECONDARY了,查看副本集状态:
- rs0:SECONDARY> rs.status()
- {
- "set" : "rs0",
- "date" : ISODate("2013-05-15T06:18:42Z"),
- "myState" : 2,
- "syncingTo" : "mongodb1.example.net:27017",
- "members" : [
- {
- "_id" : 0,
- "name" : "mongodb1.example.net:27017",
- "health" : 1,
- "state" : 1,
- "stateStr" : "PRIMARY",
- "uptime" : 41,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "lastHeartbeat" : ISODate("2013-05-15T06:18:41Z"),
- "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
- "pingMs" : 1,
- "syncingTo" : "mongodb2.example.net:27017"
- },
- {
- "_id" : 1,
- "name" : "mongodb2.example.net:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 803,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "errmsg" : "syncing to: mongodb1.example.net:27017",
- "self" : true
- },
- {
- "_id" : 2,
- "name" : "mongodb3.example.net:27017",
- "health" : 1,
- "state" : 2,
- "stateStr" : "SECONDARY",
- "uptime" : 458,
- "optime" : {
- "t" : 1368626414,
- "i" : 1
- },
- "optimeDate" : ISODate("2013-05-15T14:00:14Z"),
- "lastHeartbeat" : ISODate("2013-05-15T06:18:41Z"),
- "lastHeartbeatRecv" : ISODate("2013-05-15T06:18:42Z"),
- "pingMs" : 0,
- "lastHeartbeatMessage" : "syncing to: mongodb1.example.net:27017",
- "syncingTo" : "mongodb1.example.net:27017"
- }
- ],
- "ok" : 1
- }
复制代码 发现193已经升级为Primary,由于其优先级高于其他两个。
实验在SECONDARY上插入数据:
- rs0:SECONDARY> db.kz.insert({"user1":111})
- not master
复制代码 返回not master。以是必须利用驱动连接到PRIMARY上进行操作,必须在应用上对这种故障切换做进一步控制,包管是对PRIMARY进行操作。
可以通过rs.slaveOk()命令使该SECONDARY可以进行读操作:
- rs0:SECONDARY> db.kz.find()
- error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
- rs0:SECONDARY> rs.slaveOk()
- rs0:SECONDARY> db.kz.find()
- { "_id" : ObjectId("51932c0df2aa04a85bc95d33"), "user" : 1111 }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |