副本集(Replica Set)的存在可以提高系统的稳定性,以防单台服务器上的数据丢失。在某些情形下,副本集的存在可以提升用户读取数据的性能,因为用户可以发送请求到不同的数据服务器上。而且在实际的生产部署过程中,都是要以副本集为基础的。这里记录一些mognodb副本集的注意事项。
副本集的组成
副本集由主节点(primary)、从节点(secondaries,或许应该翻译成复制节点,这不是重点)以及可选的仲裁节点(arbiter)组成,官方文档建议最少有3个存数据的节点(例如:1个主节点,2个从节点),这样冗余性较好。
另外,副本集最多可以有50个成员,但是最多只有7个可以进行投票。
主节点
主节点是副本集中唯一接受写操作的节点,主节点会将所有的写操作记录在opolog中,从节点会复制log信息并将操作作用于自身的数据集。
所有的成员都可以接受读操作,但是,默认会从主节点进行读取。
一个副本集只能有一个主节点,当主节点出现问题时,会选举出一个新的主节点。
从节点
从节点存储主节点数据的一份复制,可以接受读操作,可以通过选举机制成为新的主节点。
从节点可以配置优先级、隐藏节点、延时节点等,可以根据需要进行相应的配置。具体的参考官方文档。
仲裁节点
仲裁节点不存储数据,并且不能成为主节点,他的作用就是投票。按照官方文档的说法,仲裁节点的存在就是为了能让投票的总人数成为奇数,但是要注意,不要在主节点或者从节点的主机上运行仲裁节点(具体原因我也不清楚,个人理解可能是为了让仲裁节点以一个外部的视角看待副本集中的成员,也就是当有人挂掉了,不会影响到它,旁观者清~)
Arbiters participate in elections in order to break ties. If a replica set has an even number of members, add an arbiter.
IMPORTANT:
Do not run an arbiter on systems that also host the primary or the secondary members of the replica set.
oplog
oplog是副本集之间用于同步的一个log,它是一个capped collection。主节点上所有更改数据的动作都会记录在oplog中,从节点会异步地来复制这些操作。所有副本集中的成员都会保存一份oplog(在local.oplog.rs这个集合中),从节点在获取了源节点的oplog后,先执行操作,然后再把操作写到自己的oplog中。副本集成员之间还会发送心跳信号来促进复制的过程。
这里有两个小问题:
1. 仲裁节点中有oplog吗?
2. 心跳信号什么用?
----------------
3.20补充:
关于仲裁节点:查看仲裁节点的local数据库,并没有oplog.rs,所以应该是没有oplog。
关于心跳信号:各个成员会通过心跳信号将自己当前的状态告知其他成员,这样每个成员就可以知道哪个是主节点,哪个节点可以作为同步源,哪个节点挂掉了等等,通常心跳信号每两秒发送一次。
oplog有一个特性是幂等性,也就是说oplog里的操作执行多次和执行一次,效果是一样的。这也就保证了如果一个从节点在复制的过程中挂掉了,重启后接着执行的时候就不会出现错误了。
同步
同步可以分为两种,一种是初始化同步,一种是同步在主节点上的数据更新。
初始化同步在3.4貌似有比较大的改变,具体的执行步骤如下:
- 拷贝源节点的除了local之外的所有数据库,同时会建立所有索引,并会拷贝在数据复制过程中oplog中新出现的部分。
- 将所有的改变(应该指的就是步骤1里oplog中新出现的那部分吧)更新到数据库上。
当然初始化同步可以在一个完全空的节点上进行,也可以利用已有的其他节点的数据。
选举
当一个成员无法达到主节点时,它就会申请被选举为主节点。如果这个成员得到了“大多数”的赞成票,选举就成功了,它会成为主节点。
这里的大多数要注意了,对于奇数个成员来说,大多数指得是超过半数就可以,但是对于偶数个成员来说,大多数指半数+1。
这里的这个大多数还是要注意一下的。例如,一个有5个成员的复制集,如果有三个节点挂了,另外两个是达不到大多数的要求的,所以剩下的两个节点都没有办法成为主节点。这对于服务器的部署,特别是地理位置上分隔的几个数据中心的部署来说,还是要考虑一下。
回滚
如果一个主节点在执行了一个写请求之后挂掉了,而复制节点还没有来得及复制这次操作,那么新选举出来的主节点就会漏掉这次操作。当原来的主节点恢复,作为复制节点重新加入到复制集中的时候,会从现在的主节点开始同步自己的oplog中最后一个操作之后的操作,但会发现找不到这个操作,这样在这个节点上就会发生回滚操作。
发生回滚操作时,回滚的数据会被写到数据库路径下的一个bson文件中,可以根据需要选择是否需要将这些数据更改到数据库中。为了避免回滚,可以将getLastError的“w”参数的值设为“majority”,这样,会在大多数的复制集成员都复制了写入操作后,该操作才会返回,否则会报出异常,这样客户端可以考虑是否要重新执行上面的写操作。