何以高可用?
我们以前用Mysql的时候,经常是一台服务器走天下,如果只是用于学习,是没有问题的,但是在生产环境中,这样的风险是很大的,如果服务器因为网络原因或者崩溃了,就会导致数据库一段时间了不可用,这样的体验很不好。
那么应该怎么办呢?既然一台机器不行,我就多上几台机器总可以了吧,比如我上个两台,让他们互为主备,相互同步数据。想到这里我就只想说一个字,稳。
其实redis,mongodb,kafka等分布式应用基本上都是这样的思想
MongoDB也差不多是这样的思想。它通过复制集来解决这个问题,MongoDB复制集由一组Mongod进程组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。
要想成为primary节点,你必须保证大多数节点都同意才行,大多数的节点就是副本中一半以上的成员。
成员总数 | 大多数 | 容忍失败数 |
---|---|---|
1 | 1 | 0 |
2 | 2 | 0 |
3 | 2 | 1 |
4 | 3 | 1 |
5 | 3 | 2 |
6 | 4 | 2 |
7 | 4 | 3 |
为什么要要求大多数呢?其实是为了避免出现两个primary节点。比如一个五个节点的复制集,其中3个成员不可用,剩下的2个仍然正常工作。这两个工作的节点由于不能满足复制集大多数的要求(这个例子中要求要有3个节点才是大多数),所以他们无法选择主节点,即使其中有一个节点是primary节点,当它注意到它无法获取大多数节点的支持时,它就会退位,成为备份节点。
如果让这两个节点可以选出primary节点,问题是另外3个节点可能不是真正挂了,而只是网络不可达而已。另外3个节点就一定可以选择出primary节点,这样就存在了两个primary节点了。
所以要求大多数就可以避免产生两个primary节点的问题。
如果MongoDB副本集可以拥有多个primary节点,那么就会面临写入冲突的问题,在支持多线程写入的系统中解决冲突的方式有手动解决和让操作系统任选一个这两种方式,但是这两种方式都不易实现,无法保证写入的数据不被其他节点修改,因此mongodb只支持单一的primary节点,这样使得开发更容易。
当一个备份节点无法与主节点连通时,它会联系并请求其他副本集成员将自己选举为主节点,其他成员会做几项理性的检查:自身是否能够与主节点连通?希望被选举为主节点的备份节点的数据是否最新?有没有其他更高优先级的成员可以被选举为主节点?
如果竞选节点成员能够得到大多数投票,就会成为主节点。但是一旦大多数成员中只有一个否决了本次选举,选举就会取消。
在日志中可以看到得票数为比较大的负数的情况,因为一张否决票相当于10000张赞成票。如果有2张赞成票,2张否决票,那么选举结果就是-19998,依此类推。
配置选项
我们一般在部署的时候,副本集节点个数至少是3个(因为它允许1个失败),这也就意味着数据要被复制三份。