MongoDB之——管理维护 Replica Sets

转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80014056

一、读写分离

有一些第三方的工具,提供了一些可以让数据库进行读写分离的工具。我们现在是否有一个疑问,从库要是能进行查询就更好了,这样可以分担主库的大量的查询请求。

1、先向主库中插入一条测试数据
[root@localhost bin]# ./mongo --port 28010
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28010/test
rs1:PRIMARY> db.c1.insert({age:30})
db.c2rs1:PRIMARY> db.c1.find()
{ "_id" : ObjectId("4fc77f421137ea4fdb653b4a"), "age" : 30 }
2、在从库进行查询等操作
[root@localhost bin]# ./mongo --port 28011
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28011/test
rs1:SECONDARY> show collections
Thu May 31 22:27:17 uncaught exception: error: { "$err" : "not master and slaveok=false",
"code" : 13435 }
rs1:SECONDARY>
当查询时报错了,说明是个从库且不能执行查询的操作
3、让从库可以读,分担主库的压力
rs1:SECONDARY> db.getMongo().setSlaveOk()
not master and slaveok=false
rs1:SECONDARY> show collections
c1
system.indexes
rs1:SECONDARY> db.c1.find()
{ "_id" : ObjectId("4fc77f421137ea4fdb653b4a"), "age" : 30 }
rs1:SECONDARY>
看来我们要是执行 db.getMongo().setSlaveOk(), 我们就可查询从库了。

二、故障转移

复制集比传统的 Master-Slave 有改进的地方就是他可以进行故障的自动转移,如果我们停掉复制集中的一个成员,那么剩余成员会再自动选举出一个成员,做为主库,例如:我们将 28010 这个主库停掉,然后再看一下复制集的状态
1、杀掉 28010 端口的 MongoDB
[root@localhost bin]# ps aux|grep mongod
root 6706 1.6 6.9 463304 6168 Sl 21:49 0:26
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r0 --fork --port 28010
root 6733 0.4 6.7 430528 6044 ? Sl 21:50 0:06
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r1 --fork --port 28011
root 6747 0.4 4.7 431548 4260 ? Sl 21:50 0:06
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r2 --fork --port 28012
root 7019 0.0 0.7 5064 684 pts/2 S+ 22:16 0:00 grep mongod
[root@localhost bin]# kill -9 6706
2、查看复制集状态
[root@localhost bin]# ./mongo --port 28011
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28011/test
rs1:SECONDARY> rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T14:17:03Z"),
	"myState" : 2,
	"members" : [
		{
			"_id" : 0,
			"name" : "localhost:28010",
			"health" : 0,
			"state" : 1,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
			"optime" : {
				"t" : 1338472279000,
				"i" : 1
			},
			"optimeDate" : ISODate("2012-05-31T13:51:19Z"),
			"lastHeartbeat" : ISODate("2012-05-31T14:16:42Z"),
			"errmsg" : "socket exception"
		},
		{
			"_id" : 1,
			"name" : "localhost:28011",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"optime" :  {
				"t" : 1338472279000,
				"i" : 1
			},
			"optimeDate" : ISODate("2012-05-31T13:51:19Z"),
			"self" : true
		},
		{
			"_id" : 2,
			"name" : "localhost:28012",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1528,
			"optime" : {
				"t" : 1338472279000,
				"i" : 1
			},
			"optimeDate" : ISODate("2012-05-31T13:51:19Z"),
			"lastHeartbeat" : ISODate("2012-05-31T14:17:02Z")
		}
	],
	"ok" : 1
}
rs1:SECONDARY>
可以看到 28010 这个端口的 MongoDB 出现了异常,而系统自动选举了 28012 这个端口为主,所以这样的故障处理机制,能将系统的稳定性大大提高。

三、增减节点

MongoDB Replica Sets 不仅提供高可用性的解决方案,它也同时提供负载均衡的解决方案,增减 Replica Sets 节点在实际应用中非常普遍,例如当应用的读压力暴增时, 3 台节点的环境已不能满足需求,那么就需要增加一些节点将压力平均分配一下;当应用的压力小时,可以减少一些节点来减少硬件资源的成本;总之这是一个长期且持续的工作。
1、增加节点
官方给我们提了 2 个方案用于增加节点,一种是通过 oplog 来增加节点,一种是通过数据库快照(--fastsync)和 oplog 来增加节点,下面将分别介绍。
1) 通过 oplog 增加节点
①、 配置并启动新节点,启用 28013 这个端口给新的节点
[root@localhost ~]# mkdir -p /data/data/r3
[root@localhost ~]# echo "this is rs1 super secret key" > /data/key/r3
[root@localhost ~]# chmod 600 /data/key/r3
[root@localhost ~]# /Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r3 --fork --port
28013 --dbpath /data/data/r3 --logpath=/data/log/r3.log --logappend all output going to: /data/log/r3.log
forked process: 10553
[root@localhost ~]#
②、 添加此新节点到现有的 Replica Sets
rs1:PRIMARY> rs.add("localhost:28013")
{ "ok" : 1 }
③、 查看 Replica Sets 我们可以清晰的看到内部是如何添加 28013 这个新节点的.
步骤一: 进行初始化
rs1: PRIMARY > rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T12:17:44Z"),
	"myState" : 1,
	"members" : [
		……
		{
			"_id" : 3,
			"name" : "localhost:28013",
			"health" : 0,
			"state" : 6,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
			"optime" : {
			"t" : 0,
			"i" : 0
		},
		"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
		"lastHeartbeat" : ISODate("2012-05-31T12:17:43Z"),
		"errmsg" : "still initializing"
		}
	],
	"ok" : 1
}
步骤二: 进行数据同步
rs1:PRIMARY> rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T12:18:07Z"),
	"myState" : 1,
	"members" : [
	……
	{
		"_id" : 3,
		"name" : "localhost:28013",
		"health" : 1,
		"state" : 3,
		"stateStr" : "RECOVERING",
		"uptime" : 16,
		"optime" : {
			"t" : 0,
			"i" : 0
		},
		"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
		"lastHeartbeat" : ISODate("2012-05-31T12:18:05Z"),
		"errmsg" : "initial sync need a member to be primary or secondary
		to do our initial sync"
		}
	],
	"ok" : 1
}
步骤三: 初始化同步完成
rs1:PRIMARY> rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T12:18:08Z"),
	"myState" : 1,
	"members" : [
		……
		{
		"_id" : 3,
		"name" : "localhost:28013",
		"health" : 1,
		"state" : 3,
		"stateStr" : "RECOVERING",
		"uptime" : 17,
		"optime" : {
			"t" : 1338466661000,
			"i" : 1
		},
		"optimeDate" : ISODate("2012-05-31T12:17:41Z"),
		"lastHeartbeat" : ISODate("2012-05-31T12:18:07Z"),
		"errmsg" : "initial sync done"
		}
	],
	"ok" : 1
}
步骤四: 节点添加完成,状态正常
rs1:PRIMARY> rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T12:18:10Z"),
	"myState" : 1,
	"members" : [
	……
		{
		"_id" : 3,
		"name" : "localhost:28013",
		"health" : 1,
		"state" : 2,
		"stateStr" : "SECONDARY",
		"uptime" : 19,
		"optime" : {
			"t" : 1338466661000,
			"i" : 1
		},
		"optimeDate" : ISODate("2012-05-31T12:17:41Z"),
		"lastHeartbeat" : ISODate("2012-05-31T12:18:09Z")
		}
	],
	"ok" : 1
}
④、 验证数据已经同步过来了
[root@localhost data]# /Apps/mongo/bin/mongo -port 28013
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28013/test
rs1:SECONDARY> rs.slaveOk()
rs1:SECONDARY> db.c1.find()
{ "_id" : ObjectId("4fc760d2383ede1dce14ef86"), "age" : 10 }
rs1:SECONDARY>
2) 通过数据库快照(--fastsync)和oplog 增加节点
通过 oplog 直接进行增加节点操作简单且无需人工干预过多,但 oplog 是 capped collection,采用循环的方式进行日志处理,所以采用 oplog 的方式进行增加节点,有可能导致数据的不一致,因为日志中存储的信息有可能已经刷新过了。不过没关系,我们可以通过数据库快照(--fastsync)和 oplog 结合的方式来增加节点,这种方式的操作流程是,先取某一个复制集成员的物理文件来做为初始化数据,然后剩余的部分用 oplog 日志来追,最终达到数据一致性
①、 取某一个复制集成员的物理文件来做为初始化数据
[root@localhost ~]# scp -r /data/data/r3 /data/data/r4
[root@localhost ~]# echo "this is rs1 super secret key" > /data/key/r4
[root@localhost ~]# chmod 600 /data/key/r4
②、 在取完物理文件后,在 c1 集中插入一条新文档,用于最后验证此更新也同步了
rs1:PRIMARY> db.c1.find()
{ "_id" : ObjectId("4fc760d2383ede1dce14ef86"), "age" : 10 }
rs1:PRIMARY> db.c1.insert({age:20})
rs1:PRIMARY> db.c1.find()
{ "_id" : ObjectId("4fc760d2383ede1dce14ef86"), "age" : 10 }
{ "_id" : ObjectId("4fc7748f479e007bde6644ef"), "age" : 20 }
rs1:PRIMARY>
③、 启用 28014 这个端口给新的节点
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r4 --fork --port 28014 --dbpath /data/data/r4 --logpath=/data/log/r4.log --logappend --fastsync
④、 添加 28014 节点
rs1:PRIMARY> rs.add("localhost:28014")
{ "ok" : 1 }
⑤、 验证数据已经同步过来了
[root@localhost data]# /Apps/mongo/bin/mongo -port 28014
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28014/test
rs1:SECONDARY> rs.slaveOk()
rs1:SECONDARY> db.c1.find()
{ "_id" : ObjectId("4fc760d2383ede1dce14ef86"), "age" : 10 }
{ "_id" : ObjectId("4fc7748f479e007bde6644ef"), "age" : 20 }
rs1:SECONDARY>
2、减少节点
下面将刚刚添加的两个新节点 28013 和 28014 从复制集中去除掉,只需执行 rs.remove 指令就可以了,具体如下:
rs1:PRIMARY> rs.remove("localhost:28014")
{ "ok" : 1 }
rs1:PRIMARY> rs.remove("localhost:28013")
{ "ok" : 1 }
查看复制集状态,可以看到现在只有 28010、 28011、 28012 这三个成员,原来的 28013 和28014 都成功去除了
rs1:PRIMARY> rs.status()
{
	"set" : "rs1",
	"date" : ISODate("2012-05-31T14:08:29Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "localhost:28010",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"optime" : {
			"t" : 1338473273000,
			"i" : 1
		},
		"optimeDate" : ISODate("2012-05-31T14:07:53Z"),
		"self" : true
		},
		{
			"_id" : 1,
			"name" : "localhost:28011",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 34,
			"optime" : {
			"t" : 1338473273000,
			"i" : 1
		},
		"optimeDate" : ISODate("2012-05-31T14:07:53Z"),
		"lastHeartbeat" : ISODate("2012-05-31T14:08:29Z")
		},
		{
			"_id" : 2,
			"name" : "localhost:28012",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 34,
			"optime" : {
				"t" : 1338473273000,
				"i" : 1
			},
			"optimeDate" : ISODate("2012-05-31T14:07:53Z"),
			"lastHeartbeat" : ISODate("2012-05-31T14:08:29Z")
		}
	],
	"ok" : 1
}
rs1:PRIMARY>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰 河

可以吃鸡腿么?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值