MongoDB副本集概述
以下图片摘自MongoDB官方文档:
http://docs.mongodb.org/manual/core/replication-introduction/
Primary节点接收客户端所有的写操作,整个副本集只会有一个primary节点。MongoDB副本集提供严格的一致性。主节点将所有的操作写入一个叫oplog的capped collection(这个collection的大小一般为磁盘剩余空间的5%,不同的系统可能不一样,详见
http://docs.mongodb.org/manual/core/replica-set-oplog/
)中,secondary节点通过复制oplog并执行oplog中的所有操作,因为对oplog的执行是幂等的,所以secondary节点上的数据可以保持和primary节点一样,当然这有一个“追赶”(catch up)的过程,会存在一定的落后(Lag)有时候因为网络延迟或宕机导致从节点永远赶不上主节点,这时候需要采取人为的干预了(后面会说到Resyncing Member of Replica Set)。
默认所有的读操作也是走的primary节点,当然客户端可以选择从secondary节点进行读取操作以减小主节点的压力(后面会对读写分离有详细说明)。
各个节点之间是通过心跳机制来维持联系的,当主节点无法和集群中其他节点通信超过10秒,集群会从剩下的节点中选择一个secondary作为primary,这个过程叫做选举(election),每个secondary节点都有一个优先级priority来参与投票(也可以有没有投票权的secondary节点),priority值越大就越优先成为主节点(所有的节点可以有相同的优先级,默认值都是1)。MongoDB通过heartbeat和election机制实现了自动的Failover:
副本集要求参与选举投票(vote)的节点数为奇数,这很容易理解。当我们实际环境中因为机器等原因限制只有两个(或偶数)的节点,这时为了实现Automatic Failover引入另一类节点:仲裁者(arbiter),仲裁者只参与投票不拥有实际的数据,因此它对物理资源要求不严格。
上面已经提到了primary,secondary和arbiter,整个MongoDB副本集群中除了这三种类型的节点还有其他几种:
Secondary-Only
:这种类型的节点和secondary节点一样拥有数据副本,但是它们在任何情形下都成为不了primary节点。
Hidden
:这种类型的节点对客户端程序来说是不可见的,同样也不能成为primary节点,但是Hidden成员能够参与选举投票。
Delayed
:这种类型的成员通过人为的设置,可以指定一个时间来延迟从primary节点同步数据。Delayed成员的作用在于帮助集群从一些误操作中恢复,比如管理员误删除了某个集合。不至于迅速扩散到整个集群中。因此Delayed节点必须不能成为primary节点(priority为0)并且是Hidden的。
Non-Voting
:这就是上面提到了没有选举权的secondary节点。这种类型的节点一般当集群节点数超过12才会需要。
简单副本集的搭建
官方建议的最小化的副本集为Three Member Sets,一个primary和两个secondary。我们先就搭建一个这样的测试环境。
首先建立三个数据目录和日志目录:
1. cd /usr/local/mongodb-2.4.1/data/
2. mkdir -p rs0-0 rs0-1 rs0-2
3. cd /usr/local/mongodb-2.4.1/log/
4. mkdir -p rs0-0 rs0-1 rs0-2
然后我们以守护进程的方式启动三个mongod进程,端口分别是37017,37018和37019:
1. ./bin/mongod --fork --dbpath data/rs0-0/ --logpath log/rs0-0/rs0-0.log --rest --replSet rs0 --port 37017
2. ./bin/mongod --fork --dbpath data/rs0-1/ --logpath log/rs0-1/rs0-1.log --rest --replSet rs0 --port 37018
3. ./bin/mongod --fork --dbpath data/rs0-2/ --logpath log/rs0-2/rs0-2.log --rest --replSet rs0 --port 37019
跟启普通的mongod进程基本相同,不同的跟了
--replSet
选项,
rs0
是该副本集的名称。
--rest
参数是打开web监控页面,比如我们这里监听37017端口,则打开
http://192.168.129.129:
38017
/
(mongod端口加上1000)就可以看到这个mongodb数据库进程的信息,如果是副本集就能查看整个副本集的相关信息。
然后我们用mongo shell连上端口为37017的mongod:
1. ./bin/mongo -port 37017
2. use admin
接着我们需要初始化一个Replica Set:首先创建一个副本集配置对象:
1. rscOnf={
2. "_id" : "rs0",
3. "members" : [
4. {
5. "_id" : 0,
6. "host" : "192.168.129.129:37017"
7. }
8. ]
9. }
然后用
rs.initiate()
进程初始化:
1. rs.initiate(rsconf)
2. {
3. "info" : "Config now saved locally. Should come online in about a minute.",
4. "ok" : 1
5. }
添加成员
:
通过rs.add()将另外两个mongod添加到副本集当中:
1. rs0:PRIMARY> rs.add("192.168.129.129:37018")
2. { "ok" : 1 }
3. rs0:PRIMARY> rs.add("192.168.129.129:37019")
4. { "ok" : 1 }
会发现37017这个mongod默认就是
PRIMARY
节点了。通过
rs.conf()
可以查看集群的配置情况:
1. rs0:PRIMARY> rs.conf()
2. {
3. "_id" : "rs0",
4. "version" : 3,
5. "members" : [
6. {
7. "_id" : 0,
8. "host" : "192.168.129.129:37017"
9. },
10. {
11. "_id" : 1,
12. "host" : "192.168.129.129:37018"
13. },
14. {
15. "_id" : 2,
16. "host" : "192.168.129.129:37019"
17. }
18. ]
19. }
移除成员
:
移除一个成员使用
rs.remove()
命令:
1. rs0:PRIMARY> rs.remove("192.168.129.129:37019")
2. Sun Aug 11 12:19:22.754 DBClientCursor::init call() failed
3. Sun Aug 11 12:19:22.874 Javascript execution failed: Error: error doing query: failed at src/mongo/shell/query.js:L78
4. Sun Aug 11 12:19:22.909 trying reconnect to 127.0.0.1:37017
5. Sun Aug 11 12:19:22.909 reconnect 127.0.0.1:37017 ok
需要
注意
的是:虽然有错误信息,但其实操作已经成功了。参看官方的文档:
每改变一次集群的配置,副本集的
version
都会加1。我们重新将37019加入rs0这次提示信息有点不一样:
1. rs0:PRIMARY> rs.add("192.168.129.129:37019")
2. { "down" : [ "192.168.129.129:37019" ], "ok" : 1 }
我们打开
http://192.168.129.129:38017/
可以看到整个副本集的相关信息:
至此一个简单的用于开发和测试Three Member Sets就搭建完成了。下节会在此基础上做一些简单的数据测试。