1. 副本集的特性
1)一台主服务器(Primary),多台从服务器(Secondary)
2)Primary挂了之后,从服务器自动完成从它们之中选举一台服务器作为主服务器,继续工作,这就解决了单点故障,因此,在这种情况下,MongoDB集群能够继续工作
3)挂了的主服务器恢复到集群中只能以Secondary服务器的角色加入进来
2. 副本集环境搭建
2.1副本集闭环配置(以三台机器配置为例)
port=27017 bind_ip=127.0.0.1 dbpath=/home/tom/development/mongoDBdata/replicaA replSet=child/127.0.0.1:27018
port=27018 bind_ip=127.0.0.1 dbpath=/home/tom/development/mongoDBdata/replicaB replSet=child/127.0.0.1:27019
port=27019 bind_ip=127.0.0.1 dbpath=/home/tom/development/mongoDBdata/replicaC replSet=child/127.0.0.1:27017
2.2 查看副本集状态
rs.status()
2.3 启动三台服务器
在~/development/mongoDBConfig目录建立三个配置文件A.conf,B.conf和C.conf,内容分别是上面闭环设置的3台机器的配置,如A.conf的内容是
port=27017 bind_ip=127.0.0.1 dbpath=/home/tom/development/mongoDBdata/replicaA replSet=child/127.0.0.1:27018
在~/devlopment/mongDBConfig目录下,运行命令启动三台服务器
mongd --config A.conf mongd --config B.conf mongd --config C.conf
此时三台服务器都在输出如下类似的日志,不断尝试跟指定的conf文件中指定的child host进行通信(contact),例如27017的
Wed Aug 6 07:26:19.088 [rsStart] trying to contact 127.0.0.1:27018 Wed Aug 6 07:26:19.089 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:26:29.089 [rsStart] trying to contact 127.0.0.1:27018 Wed Aug 6 07:26:29.090 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:26:39.090 [rsStart] trying to contact 127.0.0.1:27018 Wed Aug 6 07:26:39.091 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:26:49.091 [rsStart] trying to contact 127.0.0.1:27018 Wed Aug 6 07:26:49.092 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:26:59.092 [rsStart] trying to contact 127.0.0.1:27018 Wed Aug 6 07:26:59.094 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
Wed Aug 6 07:27:38.614 [rsStart] trying to contact 127.0.0.1:27019 Wed Aug 6 07:27:38.615 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:27:48.615 [rsStart] trying to contact 127.0.0.1:27019 Wed Aug 6 07:27:48.616 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:27:58.616 [rsStart] trying to contact 127.0.0.1:27019 Wed Aug 6 07:27:58.617 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:28:08.617 [rsStart] trying to contact 127.0.0.1:27019 Wed Aug 6 07:28:08.618 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:28:18.618 [rsStart] trying to contact 127.0.0.1:27019 Wed Aug 6 07:28:18.619 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
Wed Aug 6 07:28:35.770 [rsStart] trying to contact 127.0.0.1:27017 Wed Aug 6 07:28:35.770 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:28:45.771 [rsStart] trying to contact 127.0.0.1:27017 Wed Aug 6 07:28:45.772 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:28:55.772 [rsStart] trying to contact 127.0.0.1:27017 Wed Aug 6 07:28:55.773 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Wed Aug 6 07:29:05.773 [rsStart] trying to contact 127.0.0.1:27017 Wed Aug 6 07:29:05.774 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
2.4 副本集环境初始化
上面的日志表明副本集还没有进行初始化,使用如下命令在任意一台服务器的Javascript Shell上运行,完成副本集初始化
use admin db.runCommand({"replSetInitiate": { "_id": "child", "members": [ { "_id": 1, "host": "127.0.0.1:27017" }, { "_id": 2, "host": "127.0.0.1:27018" }, { "_id": 3, "host": "127.0.0.1:27019" } ] } });
此时查看副本集的服务器日志输出,没台机器有如下的日志输出,表明闭环建立成功
Wed Aug 6 07:45:45.954 [initandlisten] connection accepted from 127.0.0.1:46181 #8 (3 connections now open)
rs.status()察看副本集状态,得到如下的输出,可见27017是Primary服务器,其它的是Secodary服务器
child:PRIMARY> rs.status(); { "set" : "child", "date" : ISODate("2014-08-05T23:56:21Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "127.0.0.1:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2338, "optime" : Timestamp(1407282254, 1), "optimeDate" : ISODate("2014-08-05T23:44:14Z"), "self" : true }, { "_id" : 2, "name" : "127.0.0.1:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 722, "optime" : Timestamp(1407282254, 1), "optimeDate" : ISODate("2014-08-05T23:44:14Z"), "lastHeartbeat" : ISODate("2014-08-05T23:56:19Z"), "lastHeartbeatRecv" : ISODate("2014-08-05T23:56:20Z"), "pingMs" : 0, "syncingTo" : "127.0.0.1:27017" }, { "_id" : 3, "name" : "127.0.0.1:27019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 720, "optime" : Timestamp(1407282254, 1), "optimeDate" : ISODate("2014-08-05T23:44:14Z"), "lastHeartbeat" : ISODate("2014-08-05T23:56:19Z"), "lastHeartbeatRecv" : ISODate("2014-08-05T23:56:20Z"), "pingMs" : 0, "syncingTo" : "127.0.0.1:27017" } ], "ok" : 1 }
2.5 验证
2.5.1.在主服务器27017上执行如下命令:
use foolbar db.persons.insert({"name":"tom"}); db.persons.find(); >>>{ "_id" : ObjectId("53e1709f07c1625ed566a67f"), "name" : "tom" }
上面创建了一个数据库foolbar,一个集合persons,插入一条文档,然后执行查询
2.5.2.在从服务器27018上执行查询
use foolbar db.persons.find() >>>error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
查询错误,提示27018是Secondary服务器,但是SlaveOk是false,不能做查询操作,所以需要设置从服务器,使之能够支持数据读取操作
2.5.3.关掉主服务器27017
那么MongoDB从27018和27019上自动选举一台作为主服务器,此时如果重启27017,那么27017将作为Secondary服务器加入到集群中。假如27019被选举为Primary,那么对27019做针对foolbar数据库persons集合的查询,会查询来1中创建的数据
2.5.4.设置读写分离
无论是主从复制还是副本集复制,一方面提供数据的备份,另外一点通过读写分离提高读写性能,在副本集复制方式下,默认情况下,从服务器只进行数据的同步,但是不提供数据读取功能,要想使从服务器提供数据读取功能,需要设置从服务器的slaveOkay为true,但是遗憾的是,如此重要的设置,MongoDB的Javascript Shell竟然没有提供修改的API,难道副本集的本意只做数据同步备份,不做读写分离?It doesn't make any sense!!!要修改slaveOkay,只能通过MongoDB的语言客户端如Java进行修改,这在以后再讲。