简单来说,副本集(Replica Set)就是有自动故障恢复功能的主从集群。主从集群和副本集最为明显的区别是副本集没有固定的“主节点”:整个集群会选举出一个“主节点”,当其不能工作时则变更到其他节点。然而,二者看上去非常相似:副本集总会有一个活跃节点(primary)和一个或多个备份节点(secondary)。
副本集最美妙的地方就是所有东西都是自动化的。首先他为你做了很多管理工作,自动提升备份节点为活跃节点,其次,对开发者而言也非常易用:仅需要为副本集指定一下服务器,驱动程序就会自动找到服务器,在当前活跃节点死机时自动处理故障恢复这类事情。
当活跃节点挂了,备份节点自动成为活跃节点。
当活跃节点又恢复了,由于已经有活跃节点了,自动变为备份节点。
1. Standard: 常规节点,存储了完整数据副本,参与投票,可能成为活跃节点,优先权非0.
2. Passive: 存储了完整数据副本,参与投票,不能成为活跃节点。优先权为0.
3. Arbiter:仲裁者,只参与投票,不接受复制的数据,也不能成为活跃节点。
如果活跃节点坏了,其他节点会选出一个新的活跃节点来。选举过程可以由任何非活跃节点发起。新的活跃节点由副本集中的大多数选举产生。仲裁节点也会参与投票,避免出现僵局。新的活跃节点将是优先级最高的节点,优先级相同则数据较新的获胜。
活跃节点使用心跳来跟踪集群中有多少节点对其可见。如果不够半数,活跃节点会自动降级为备份节点。这样就能防止活跃节点一直不放权。
不论活跃节点何时变化,新活跃节点的数据就被假定为系统的最新数据。其他节点的操作会回滚,即便之前的活跃节点恢复了工作。
在以下几种情景发生的时候,副本集通过“选举”来决定副本集中的primary节点:
· 当第一次初始化一个副本集的时候;
· primary几点steps down的时候,出现这种情况可能是因为执行了replSetStepDown命令,或者是集群中出现了更适合当primary的节点,比如当primary节点和集群中其他大部分节点无法通信的时候,当primarysteps down的时候,它会关闭所有客户端的连接。
· 当集群中一个secondary节点无法和primary节点建立连接的时候也会导致一次election发生。
· 一次failover。
· 执行rs.conf()命令。
在一次选举中包括hidden节点、仲裁者甚至正处于recovering状态的节点都具有“投票权”。默认配置中所有参与选举的节点具有相等的权利,当然在一些特定情况下,应明确的指定某些secondary会优先成为primary,比如一个远在千里之外异地机房的节点就不应该成为primary节点,选举的权重通过设置priority来调节,默认该值都是1,在前面简单副本集的搭建中已经介绍过了如何修改该值。
集群中任何一个节点都可以否决选举,即使它是non-voting member:
· 如果发起选举的节点不具有选举权(priority为0的成员);
· 发起选举的节点数据落后太多;
· 发起选举的节点的priority值比集群中其他某一个节点的小;
· 如果当前的primary节点比发起选举的节点拥有更新或同等新的数据(也就“optime”值相等或更大)。
· 当前的primary节点会否决,如果它拥有比发起选举的节点更新或相同新的数据。
首先获取最多选票的成员(实际上要超过半数)才会成为primary节点,这也说明了为什么当有两个节点的集群中primary节点宕机后,剩下的只能成为secondary,当primary宕掉,此时副本集只剩下一个secondary,它只有1票,不超过总节点数的半数,它不会选举自己为primary。
ReadReferences:
应用程序驱动通过read reference来设定如何对副本集进行读取操作,默认的,客户端驱动所有的读操作都是直接访问primary节点的,从而保证了数据的严格一致性。
但有时为了缓解主节点的压力,我们可能需要直接从secondary节点读取,只需要保证最终一致性就可以了。
MongoDB 2.0之后支持五种的readpreference模式:
primary:默认,只从主节点上进行读取操作;
primaryPreferred:在绝大部分的情形都是从主节点上读取数据的,只有当主节点不可用的时候,比如在进行failover的10秒或更长的时间内会从secondary节点读取数据。
警告:2.2版本之前的MongoDB对ReadPreference支持的还不完全,如果客户端驱动采用primaryPreferred实际上读取操作都会被路由到secondary节点。
secondary:只从secondary节点上进行读取操作,存在的问题是secondary节点的数据会比primary节点数据“旧”。
secondaryPreferred:优先从secondary节点进行读取操作;
nearest:既有可能从primary,也有可能从secondary节点读取,这个决策是通过一个叫memberselection过程处理的。
MongoDB允许在不同的粒度上指定这些模式:连接、数据库、集合甚至单次的操作。不同语言的驱动基本都支持这些粒度。
从节点第一次启动时,会对主节点数据进行完整的同步.从节点复制主节点上的每个文档,很耗资源.同步完成后,
从节点开始查询主节点的oplog并执行这些操作,以保证数据是最新的.
如果从节点的操作和主节点的相差很远,从节点就跟不上同步了.跟不上同步的从节点无法一直追赶主节点.因为
主节点oplog的所有操作太新了.从节点发生了宕机或着疲于应付读取时会出现这个情况,也会在执行完完整同步以后
反生类似的事,因为只要同步的时间太长,同步完成时,oplog可能已经操作了很多.
从节点跟不上同步时,复制就会停下来,从节点需要重新做完整的同步.可以用{"resync":1}命令手动执行从新同步,
也可以在启动从节点时使用--autoresync选项让其自动重新同步,重新同步的代价很高,应尽量避免,方法是配置
足够大的oplog,配置足够大的oplog能存放相当长的时间操作记录.大的oplog会占用更多的磁盘空间,则需要权衡一下.
默认的oplog大小是剩余磁盘空间的5%.
准备:
两台服务器:
192.168.229.80:80服务器作为节点1,目录如下
/export/servers/dbs/node1/
192.168.192.75:75服务器作为节点2,目录如下
启动node1节点:80:
-bash-3.2# ./bin/mongod --dbpath ./data/node1 --logpath ./data/node1/node1.log --port 10001 --replSet test/192.168.192.75:10002 |
启动node2节点:75:
[root@localhost mongodb-linux-x86_64-2.0.4]# ./bin/mongod --dbpath ./data/node2/ --port 10002 --replSet test/ |
通过192.168.192.68链接到一台服务器:
./bin/mongo 192.168.229.80:10001/admin |
初始化副本集:
db.runCommand({ "replSetInitiate":{ "_id":"test", "members":[ { "_id":1, "host":"192.168.229.80:10001" , "priority":3 }, { "_id":2, "host":"192.168.192.75:10002", "priority":2 } ] } });
|
结果如图:提示ok:1即成功,间有几次报错是磁盘满了,清除后ok
查看副本集状态:
查看是否为主节点:看到ismaster:true
切换到75上查看:ismaster:false
往主库插入数据:
去从库查看:
发现查不到数据,这是正常的,因为SECONDARY是不允许读写的,在写多读少的应用中,使用Replica Sets来实现读写分离。通过在连接时指定或者在主库指定slaveOk,由Secondary来分担读的压力,Primary只承担写操作。
对于replica set 中的secondary 节点默认是不可读的,分别从从库和主库设置setSlaveOk即可。
参考:
http://www.cnblogs.com/refactor/archive/2012/08/13/2600140.html