先说一下副本集的概念:有自动故障恢复功能的主从结构!前面讲到的主从结构和副本集最大的区别就是:副本集没有固定的“主节点”,整个集群结构会动态选举出一个“主节点”,当其不能工作了,则会动态变更到其他节点。副本集对其节点又特殊的称呼:活跃节点(“主节点”)和 备份节点(“从节点”)。
副本集最美妙的地方是其自动化,在当前活跃节点因故障停止时,备份节点会自动升级为活跃节点!以维持系统的正常运行。
搭建副本集的过程为:我们首先需要为副本集起一个名称(试验名称为“yy”),然后使用选项--replSet来启动副本集的第一个服务:
C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver1 --port 10000 --lo gpath e:\mdblog1\log.log --replSet yy/localhost:10001 all output going to: e:\mdblog1\log.log上述我们通过--replSet yy/localhost:10001(这里有一点尤为注意:副本集名称yy后的分隔符必须为“/”,否则后面注册后失败!),这是指定了该副本集yy中的另外一个MongoDB服务,其监听的端口为本机的10001,但此时我们还并未启动该服务!
我们看一下第一个节点日志此时的输出包含如下语句:
Sun Sep 02 10:48:51 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG) Sun Sep 02 10:48:51 [rsStart] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done
我们开始启动副本集的第二个服务:
C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver2 --port 10001 --lo gpath e:\mdblog2\log.log --replSet yy/localhost:10000 all output going to: e:\mdblog2\log.log我们还可以启动副本集的第三台服务,下面两种方式均可:
C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver3 --port 10002 --lo gpath e:\mdblog3\log.log --replSet yy/localhost:10000 all output going to: e:\mdblog3\log.log
C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver3 --port 10002 --lo gpath e:\mdblog3\log.log --replSet yy/localhost:10000,localhost:10001 all output going to: e:\mdblog3\log.log即在启动第三台服务时,可以只指定副本集中的一个服务,或同时指定。副本集的一个特性为:自动检测,你仅指定单台服务器后,MongoDB会自动搜索并连接到同一副本集的其余的节点。
C:\Documents and Settings\liuxjd>mongo localhost:10001 MongoDB shell version: 2.0.7 connecting to: localhost:10001/test > use admin switched to db admin > db.runCommand({"replSetInitiate" : { ... "_id" : "yy", ... "members" : [ ... { ... "_id" :1, ... "host": "localhost:10000" ... }, ... { ... "_id" : 2, ... "host" : "localhost:10001" ... }, ... { ... "_id" : 3, ... "host" : "localhost:10002" ... } ... ]}}); { "info" : "Config now saved locally. Should come online in about a minut e.", "ok" : 1 } >运行这个命令的文档稍显复杂,我们解释一下各个键的含义:
1》 “_id” : “yy”, 这个键指明了副本集的名称
2》 “members” :[...], 这个键指明服务器列表,我们以后还可以往副本集中加入服务器
3》 “_id” : N, 内嵌文档的键,用于唯一标示副本集中的某一台服务器
4》 “host”:host address, 指明服务器的主机和端口号
通过命令初始化完毕后,我们查看日志:
Sun Sep 02 10:52:11 [rsHealthPoll] replSet member localhost:10001 is now in state PRIMARY Sun Sep 02 10:52:25 [rsHealthPoll] replSet member localhost:10000 is now in state SECONDARY Sun Sep 02 10:52:17 [rsHealthPoll] replSet member localhost:10002 is now in state SECONDARY
第二个服务器成为了活跃节点,其余两个服务器均是备份节点。备份节点会抽取活跃节点的oplog,来维持和活跃节点的数据同步!备份节点无法直接通过客户端进行些操作,查询操作也要指明“slaveok”(在shell进行查询,主从结构的从节点可以通过shell客户端查询数据,而副本集控制严一些,其备份节点通过shell客户端也无法直接查询,提示需要设置slaveok选项,但shell查询好像没有提供这种支持!)
初始化会将副本集的信息保存在副本集各个节点的数据库local的集合system.replset中,我们到第一台服务器上查看一下该集合:
SECONDARY> use local; switched to db local SECONDARY> db.system.replset.find(); { "_id" : "yy", "version" : 1, "members" : [ { "_id" : 1, "host" : "localhost:10000" }, { "_id" : 2, "host" : "localhost:10001" }, { "_id" : 3, "host" : "localhost:10002" } ] } SECONDARY>执行初始化命令时,键“members”的内嵌文档中,还有如下两个键可以使用:
1》 priority :N,优先级,指明一个服务器的优先级,默认为1,可以是[0,1000],通过这个我们可以指明副本集某台服务器节点初始为活跃节点
2》 arbiterOnly :true,仲裁节点,特定指明某个服务器节点为仲裁节点,仲裁节点不会复制数据,不会成为活跃节点,其存在的目的只有一个:当前活跃节点失效后,副本集内重新投票选活跃节点时,防止出现僵局!
【故障切换】
当当前活跃节点失效,包括两种情况:
1》 当前活跃节点宕机或本身异常
2》 当前活跃节点会通过心跳跟踪集群中多收节点对其可见,如果数量小于集群服务器数量的一半,会自动降级为备份节点
此时,集群会投票选举出一个新的活跃节点(新比较优先级,优先级相同的,各个节点判断哪个数据最新,就会投哪个),任何时候,活跃节点的数据会被认为是最新的。当重新确定了活跃节点后,所有其他节点都要重新进行完整同步!