1.什么是mongodb副本集
mongodb副本集是一种在多台机器同步数据的进程,副本提供了数据冗余,扩展了数据可用性。在多台服务器保存数据以避免一台服务器出现问题导致数据的丢失。
在某些场景下,也可以通过使用副本集来扩展读取性能,因为客户端可以将读操作发送到不同的服务器上。在不同的数据中心维护数据副本可以提高分布式应用程序的数据本地化和可用性。您还可以维护额外的副本以实现特殊用途,比如灾难恢复、报告或备份。
2.mongodb副本集的结构和原理
mongodb副本集和之前的主从模式并不相同,副本集是一组mongod维护相同数据集的实例,一个副本集中可以包含多个数据承载节点和一个仲裁节点(可选)。在数据承载节点中,只有一个成员会被视为主节点,而其他节点则被认为是从节点或者是仲裁节点。
在副本集中只有主节点可以进行读写操作,而从节点只有读操作,仲裁节点只有选举作用。主节点的操作记录会保存在oplog中,其他从节点会通过此oplog来复制数据来保证和主节点的数据一致性。oplog是具有幂等性的,也就是说无论执行几次其结果都是一致的。
当集群中主节点出现异常,副本集节点就会选举出一个新的主服务器,以保证整个集群的正常运行。原来的主节点会自动降级为从节点,以保证写入数据的一致性。
有一点需要注意,就是在副本集出现异常的时候,存活的节点数一定要大于副本集节点总数的一半,否则就无法选举出主节点,甚至有可能会出现主节点自动降级为从节点,导致整个副本集变为只读。因此,考虑增加不容易出现故障的仲裁节点,可以增加有效的选票,降低整个副本集不可用的风险,因为仲裁节点只参与投票,不接收复制的数据,也不会成为活跃节点。当然如果最后真的出现了副本集只读的情况,当主节点仍可以正常工作的时候,也是可以快速恢复副本集的读写状态的,这里我会在下面进行详解。
这里官方推荐的mongodb副本集节点最少是3台,并且建议副本集成员的数量为奇数,最多12个副本集节点,最多7个节点参与选举。限制副本集节点的数量主要是因为副本集节点参与选举,也会增加选举的时间增加复制的成本,最后可能会拖累整个集群。
3.实际生产中的选择
网络上有不少副本集的部署流程,这里就不在详细进行说明了。主要说一下在实际的生产环境下是怎么使用的。
实际环境中,由于之前我们使用的是mongodb3.X版本的,还可以使用主从模式来保证数据的安全,但是为了与时俱进,有个项目使用了mongodb4.X版本的,这个版本官方是不推荐使用主从模式了,为了能保证数据的安全性,我们需要另外一种模式来替代之前的主从模式。这里有查阅官方的文档,目前是比较推荐使用副本集模式或者是分片模式的。简单看了下副本集模式和分片模式的区别之后,我们觉得使用副本集模式会比较切合当前线上的一个环境,但是我们是不需要当主节点故障时,出现节点转移的,因此我首先对其进行了简单的尝试。
最开始考虑是使用3个节点进行测试,一个主节点,一个从节点外加一个仲裁节点来保证集群的稳定性。
config = { _id:"test", members:[{_id:0,host:"xxxxxx:27017",priority:2}, {_id:1,host:"xxxxxx:27017",priority:2}, {_id:2,host:"xxxxxx:27018",arbiterOnly:true}]}
rs.initiate(config)
rs.status()
测试发现同步没有什么问题,目前就只有一个问题就是如何保证当主节点故障的时候不让从节点升级为主节点。
有详细看了下官方的文档,发现priority这个参数比较有意思,priority越大,被选举的可能性就越大,如果priority为0,则永不会被选举为主节点。
唉~这里不就是我想要的嘛。如果我把从节点的priority设置为0,会变成什么样?是不是只会从主节点进行复制,而不会在主节点挂掉只会被选择为新的主节点呢?
经给测试发现确实是的
主节点挂掉之后,从节点并没有发生改变。这不就可以代替之前的主从模式来使用了嘛。最后选择了这种模式和节点数。
4.故障测试
当发现这个可行之后,剩下就是要进行各种故障测试来检验这种模式,也是对未来可能会出现的问题提前整理好处理方案,以便到时出现后措手不及。
第一个是主节点故障无法启动情况,这个时候,拉取从节点的数据库到主节点机器上直接启动,发现可以正常启动,而且副本集也正常。
第二个是数据同步的一致性测试,也是正常的。
第三个就是当从节点和仲裁节点都挂掉的情况,这种情况可能性比较小,但是也进行了测试,这时就会出现上面所说的情况,整个副本集变成了只读状态,这种情况对于正在线上跑的游戏来说那可是不好的情况,会数据无法写入到数据库。
那如果真的出现了,要怎么处理呢?
这种时候因为没有主节点,因此你没法再添加仲裁节点取平衡整个副本集,因为从节点只有读的权限。那怎么办呢?
不能增加,是不是可以考虑删除?我把除了主节点之外的节点全部删除掉会发生什么?
但是要怎么进行删除呢,从节点没法重新做初始化的。这里官方并没有细说,但是有一个地方进行了说明--强制成为主要成员,是不是可以利用这个来进行操作呢?
这里官方给到的是force : true
,强制取执行,这个也是可以在从节点进行执行的。
操作方式是:
cfg = rs.conf()
cfg.members = [cfg.members[0]]
rs.reconfig(cfg, {force : true})
之后你会发现除了主节点其他的节点都被删掉了,而过了一会,从节点又恢复为主节点了,终于可以继续进行写操作了。
这个操作如果写到脚本里面,去做主节点进行检测,当主节点正常但是状态变化的时候直接操作,基本上可以在1-2分钟左右可以重新恢复,这样对线上的游戏影响也会比较小。