Replicat Set比起传统的Master - Slave结构而言,应用场景更加多,也有了自动failover的能力。
在mongo3.2的文档中明确写道:
-
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.
本文将简单介绍mongodb副本集搭建。
〇 副本集结构图
我在此处大致理解为“MySQL中1主2从+mha_manager”的结构。
Replication通过Oplog实现语句复现。
〇 副本集成员的属性:
分别为Primary、Secondary(Secondaries)
Primary负责处理所有的write请求,并记录到oplog(operation log)中。
Secondary负责复制oplog并应用这些write请求到他们自己的数据集中。(有一些类似于MySQL Replication)
所有的副本集都可以处理读操作,但是需要设置。
最小化的副本集配置建议有三个成员:
1个Primary + 2个Secondary
或者
1个Primary + 1个Secondary + 1个Arbiter(仲裁者)
〇 Arbiter和选举机制:
Arbiter可以作为副本集的一部分,但它不是一个数据副本,故它不会成为Primary。
Arbiter在Primary不可用的时候,作为一个选举的角色存在。
如果Arbiter不存在,Primary挂掉的情况下,剩下的两个Secondary则也会进行选举。
在1个Primary + 2个Secondary的情况下,failover如下:
〇 搭建
实验结构:
185(Arbiter)(后文用到)
186\187\188(1个Primary、2个Secondary)
在三台机器上分别创建对应目录然后启动mongodb:
-
mkdir -p /data/mongo_replset
-
mongod --dbpath=/data/mongo_replset --logpath=/data/mongo_replset/mongo.log --fork --replSet=first_replset
登录任意一台副本集的mongo shell
此处用的是192.168.1.187
输入:
-
> cnf = {_id:"first_replset", members:[
-
{_id:1, host:"192.168.1.186:27017"},
-
{_id:2, host:"192.168.1.187:27017"},
-
{_id:3, host:"192.168.1.188:27017"},
-
]
-
}
-
-
输出结果:
-
> {
-
"_id" : "first_replset",
-
"members" : [
-
{
-
"_id" : 1,
-
"host" : "192.168.1.186:27017"
-
},
-
{
-
"_id" : 2,
-
"host" : "192.168.1.187:27017"
-
},
-
{
-
"_id" : 3,
-
"host" : "192.168.1.188:27017"
-
}
-
]
-
}
初始化配置:
-
> rs.initiate(cnf);
-
{ "ok" : 1 }
-
first_replset:OTHER>
-
first_replset:PRIMARY>
-
first_replset:PRIMARY>
此时可以发现该mongodb实例已经成为PRIMARY了。
可以看一下这个副本集的各个成员的状态:
-
first_replset:PRIMARY> rs.status();
-
{
-
"set" : "first_replset",
-
"date" : ISODate("2016-11-15T08:22:10.316Z"),
-
"myState" : 2,
-
"term" : NumberLong(0),
-
"heartbeatIntervalMillis" : NumberLong(2000),
-
"members" : [
-
{
-
"_id" : 1,
-
"name" : "192.168.1.186:27017",
-
"health" : 1,
-
"state" : 2,
-
"stateStr" : "SECONDARY",
-
……………………
-
},
-
{
-
"_id" : 2,
-
"name" : "192.168.1.187:27017",
-
"health" : 1,
-
"state" : 2,
-
"stateStr" : "PRIMARY",
-
……………………
-
},
-
{
-
"_id" : 3,
-
"name" : "192.168.1.188:27017",
-
"health" : 1,
-
"state" : 2,
-
"stateStr" : "SECONDARY",
-
……………………
-
}
-
],
-
"ok" : 1
-
}
〇 副本集复制状态测试
在PRIMARY上insert:
-
[root@192.168.1.187]# mongo 127.0.0.1/test
-
MongoDB shell version: 3.2.10
-
connecting to: 127.0.0.1/test
-
first_replset:PRIMARY> db.test_table.insert({"id": 1})
-
WriteResult({ "nInserted" : 1 })
-
first_replset:PRIMARY> db.test_table.find()
-
{ "_id" : ObjectId("582abba066fdf9fae28a1ba7"), "id" : 1 }
在186、188任意SECONDARY上查询:
同master - slave结构一样,默认SECONDARY是不可读的,需要执行rs.slaveOk()。
-
first_replset:SECONDARY> rs.slaveOk()
-
first_replset:SECONDARY> db.test_table.find()
-
{ "_id" : ObjectId("582abba066fdf9fae28a1ba7"), "id" : 1 }
〇 failover测试
此时情况:
187:PRIAMRY
186、188:SECONDARY
停掉PRIAMRY:
-
first_replset:PRIMARY> use admin
-
switched to db admin
-
first_replset:PRIMARY> db.shutdownServer()
-
server should be down...
-
2016-11-15T16:31:25.921+0800 I NETWORK [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
-
2016-11-15T16:31:27.299+0800 I NETWORK [thread1] Socket recv() errno:104 Connection reset by peer 127.0.0.1:27017
-
2016-11-15T16:31:27.299+0800 I NETWORK [thread1] SocketException: remote: (NONE):0 error: 9001 socket exception [RECV_ERROR] server [127.0.0.1:27017]
-
2016-11-15T16:31:27.299+0800 I NETWORK [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) failed failed
-
2016-11-15T16:31:27.302+0800 I NETWORK [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
-
2016-11-15T16:31:27.302+0800 W NETWORK [thread1] Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused
-
2016-11-15T16:31:27.302+0800 I NETWORK [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) failed failed
-
>
(原SECONDARY)188上查到,此时188已经为PRIMARY了。
-
first_replset:PRIMARY> rs.status()
-
{
-
"set" : "first_replset",
-
"date" : ISODate("2016-11-15T16:31:45.773Z"),
-
"myState" : 1,
-
"term" : NumberLong(2),
-
"heartbeatIntervalMillis" : NumberLong(2000),
-
"members" : [
-
{
-
"_id" : 1,
-
"name" : "192.168.1.186:27017",
-
"health" : 1,
-
"state" : 2,
-
"stateStr" : "SECONDARY",
-
……………………
-
},
-
{
-
"_id" : 2,
-
"name" : "192.168.1.187:27017",
-
"health" : 0,
-
"state" : 8,
-
"stateStr" : "(not reachable/healthy)",
-
……………………
-
},
-
{
-
"_id" : 3,
-
"name" : "192.168.1.188:27017",
-
"health" : 1,
-
"state" : 1,
-
"stateStr" : "PRIMARY",
-
……………………
-
}
-
],
-
"ok" : 1
-
}
〇 在副本集中添加一个属性为Arbiter的成员
当然此处只做添加实践,实际上并不建议在Secondary-Primary-Secondary的结构上再多一个Arbiter成员形成偶数个节点。
文档写到:
-
Only add an arbiter to sets with even numbers of voting members.
-
If you add an arbiter to a set with an odd number of voting members, the set may suffer from tied elections.
在192.168.1.185(另一台)上启动一个mongod实例:
-
mkdir -p /data/arb
-
mongod --dbpath=/data/arb/ --logpath=/data/arb/mongo.log --fork --replSet=first_replset
在failover后的PRIMARY节点添加Arbiter
-
first_replset:PRIMARY> rs.addArb("192.168.1.185:27017")
-
{ "ok" : 1 }
-
first_replset:PRIMARY> rs.status()
-
……………………
-
{
-
"_id" : 4,
-
"name" : "192.168.1.185:27017",
-
"health" : 1,
-
"state" : 7,
-
"stateStr" : "ARBITER",
-
……………………
-
}
-
……………………
此时回到arbiter的mongo shell,发现正如文档所说,arbiter是不会存有副本集中数据的。
-
first_replset:ARBITER> rs.slaveOk()
-
first_replset:ARBITER> use test;
-
switched to db test
-
first_replset:ARBITER> show tables;
-
first_replset:ARBITER> db.test_table.find();
-
Error: error: { "ok" : 0, "errmsg" : "node is recovering", "code" : 13436 }
〇 参考文档:
Replication > Replica Set Tutorials > Replica Set Deployment Tutorials
Reference > mongo Shell Methods > Replication Methods
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29773961/viewspace-2128530/
,如需转载,请注明出处,否则将追究法律责任。