MongoDB庖丁解牛(Replication Sets)

  • A+
所属分类:MongoDB 数据库

问什么使用副本集?

传统的主从架构是非常落后的,存在Master单点故障,不能自动切换,没有很好的扩展性和容错性,官方原文已经不建议使用主从复制了,生产环境使用副本集才是最佳方案。

IMPORTANT

Replica sets replace master-slave replication for most use cases. If
possible, use replica sets rather than master-slave replication for all new
production deployments. This documentation remains to support legacy deployments
and for archival purposes only.

由图可以看到客户端连接到整个副本集,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份,一但主节点挂掉,副本节点就会选举一个新的主服务器,这一切对于应用服务器不需要关心。我们看一下主服务器挂掉后的架构:

mongodb故障转移

环境描述

1、首选确保时间同步

2、三台服务器安装mongodb,确定互相能访问

3、修改replsSetName名

vim /etc/mongo.conf
replication:
replSetName: testrs0

4、初始化

> rs.status()
{
"info" : "run rs.initiate(...) if not yet done for the set",
"ok" : 0,
"errmsg" : "no replset config has been received",
"code" : 94
}
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the 
set",
"me" : "192.168.16.130:27017",
"ok" : 1

5、查看状态

testrs0:OTHER> rs.status()
{
"set" : "testrs0",
"date" : ISODate("2016-01-19T04:53:41.297Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "192.168.16.130:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 163,
"optime" : {
"ts" : Timestamp(1453179212, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2016-01-19T04:53:32Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1453179211, 2),
"electionDate" : ISODate("2016-01-19T04:53:31Z"),
"configVersion" : 1,
"self" : true
}
],
"ok" : 1
}

查看谁是Master

t

estrs0:PRIMARY> db.isMaster()
{
"hosts" : [
"192.168.16.130:27017"
],
"setName" : "testrs0",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "192.168.16.130:27017",
"me" : "192.168.16.130:27017",
"electionId" : ObjectId("569dc14b0000000000000001"),
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2016-01-19T04:55:10.062Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,
"ok" : 1
}

6、添加从节点

testrs0:PRIMARY> rs.add("192.168.16.129:27017")
testrs0:PRIMARY> rs.add("192.168.16.131:27017")
testrs0:PRIMARY> rs.status()

从节点查看谁是Master

testrs0:SECONDARY> db.isMaster()
{
"hosts" : [
"192.168.16.130:27017",
"192.168.16.129:27017",
"192.168.16.131:27017"
],
"setName" : "testrs0",
"setVersion" : 3,
"ismaster" : false,
"secondary" : true,
"primary" : "192.168.16.130:27017",
"me" : "192.168.16.129:27017",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2016-01-19T04:57:11.451Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,

7、在主节点创建数据

首先在从节点查看是否有数据

testrs0:SECONDARY> show dbs
2016-01-18T20:58:13.398-0800 E QUERY [thread1] Error: listDatabases failed:{ 
"ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435 } :
_getErrorWithCode@src/mongo/shell/utils.js:23:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:53:1
shellHelper.show@src/mongo/shell/utils.js:700:19
shellHelper@src/mongo/shell/utils.js:594:15

报错:把自己提成一个可以查询的从节点

testrs0:SECONDARY> rs.slaveOk()
testrs0:SECONDARY> show dbs
local 0.000GB

(1)在master创建

testrs0:PRIMARY> db.testcoll.insert({Name: "Mike"})
WriteResult({ "nInserted" : 1 })
testrs0:PRIMARY> show collections
testcoll
testrs0:PRIMARY> db.testcoll.find()
{ "_id" : ObjectId("569dc348eb8c1cb10b8cdfc8"), "Name" : "Mike" }
testrs0:PRIMARY>

8、在从节点查询数据,看是否增加过来

testrs0:SECONDARY> use liudb
switched to db liudb
testrs0:SECONDARY> db.testcoll.find()
{ "_id" : ObjectId("569dc348eb8c1cb10b8cdfc8"), "Name" : "Mike" }

9、让主节点挂掉,在从节点查看选举过程

/etc/init.d/mongod stop
vim /etc/mongod.conf

10、此时查看会发现自动选举了一个主,原来的主状态变为不健康

testrs0:SECONDARY> rs.status();
{
"set" : "testrs0",
"date" : ISODate("2016-01-19T05:07:04.697Z"),
"myState" : 2,
"term" : NumberLong(2),
"syncingTo" : "192.168.16.129:27017",
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "192.168.16.130:27017",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2016-01-19T05:07:03.641Z"),
"lastHeartbeatRecv" : ISODate("2016-01-19T05:06:13.709Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "192.168.16.129:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 595,
"optime" : {
"ts" : Timestamp(1453179984, 2),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2016-01-19T05:06:24Z"),
"lastHeartbeat" : ISODate("2016-01-19T05:07:04.601Z"),
"lastHeartbeatRecv" : ISODate("2016-01-19T05:07:04.138Z"),
"pingMs" : NumberLong(1),
"electionTime" : Timestamp(0, 0),
"electionDate" : ISODate("1970-01-01T00:00:00Z"),
"configVersion" : 3
},
{
"_id" : 2,
"name" : "192.168.16.131:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1282,
"optime" : {
"ts" : Timestamp(1453179984, 2),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2016-01-19T05:06:24Z"),
"syncingTo" : "192.168.16.129:27017",
"configVersion" : 3,
"self" : true
}
],
"ok" : 1
}

11、在新的主上添加数据,把故障的主上线,查看会发现自己变成从

testrs0:PRIMARY> db.testcoll.insert({Name: "liuyalei"})
WriteResult({ "nInserted" : 1 })
testrs0:PRIMARY> db.testcoll.find().limit(2)
{ "_id" : ObjectId("569dc348eb8c1cb10b8cdfc8"), "Name" : "Mike" }
{ "_id" : ObjectId("569dc4f509e777f735de6aa0"), "Name" : "liuyalei" }
[root@130 mongo]# /etc/init.d/mongod start
testrs0:SECONDARY> rs.status()
{
"set" : "testrs0",
"date" : ISODate("2016-01-19T05:12:02.449Z"),
"myState" : 2,
"term" : NumberLong(2),
"syncingTo" : "192.168.16.129:27017",
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "192.168.16.130:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 22,
"optime" : {
"ts" : Timestamp(1453180149, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2016-01-19T05:09:09Z"),
"syncingTo" : "192.168.16.129:27017",
"configVersion" : 3,
"self" : true

12、故障期间的数据回同步过来

testrs0:SECONDARY> rs.slaveOk()
testrs0:SECONDARY> use liudb
testrs0:SECONDARY> db.testcoll.find().limit(2)
{ "_id" : ObjectId("569dc348eb8c1cb10b8cdfc8"), "Name" : "Mike" }
{ "_id" : ObjectId("569dc4f509e777f735de6aa0"), "Name" : "liuyalei" }

https://docs.mongodb.org/manual/tutorial/adjust-replica-set-member-priority/

在主节点,调整副本优先级

1、定义cfg别名

cfg = rs.conf()

2、调整id 0 1 2的优先级(数字越大优先级越高,会被选举为PRIMARY)

cfg.members[0].priority = 1
cfg.members[1].priority = 2
cfg.members[2].priority = 3

3、应用

rs.reconfig(cfg)

4、查看优先级高的会被选举成PRIMARY

rs.status()

YaLei

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: