master作为cluster的灵魂必须要有,还必须要唯一,否则集群就出大问题了关于分布式系统的master选举算法有很多,最有名的当然要数paxos算法,在它的基础上出现了非常多的变体算法。但是paxos的功能远远超出了master选举,一致性向才是它的目标,任何需要实现一致性的问题都可以使用该算法。集群有一个问题就是brain split:一个集群因为网络问题导致多个master选举出来而分裂。这也是master选举必须要解决的问题。具体原理如下:
- 对所有可以成为master的节点根据nodeId排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第0位)节点,暂且认为它是master节点。
- 如果对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master。否则重新选举。
- 对于brain split问题,需要把候选master节点最小值设置为可以成为master节点数n/2+1
以上就是master选举的三条原则,其实第三条包含在第二条之中,为了说明brain split问题这里单独拿出来说一下。下面看一下ElectMasterService的相关代码,来补充说明一下一上的文字描述:
public DiscoveryNode electMaster(Iterable<DiscoveryNode> nodes) { List<DiscoveryNode> sortedNodes = sortedMasterNodes(nodes); if (sortedNodes == null || sortedNodes.isEmpty()) { return null; } return sortedNodes.get(0); }
上面就是选举master的方法,可以看到,它的做法就是对候选节点排序然后直接将第一个返回。当然这只是上面所说的第一条。如果每个节点都只是选举自己排序后的节点的第一个肯定会导致brain split和选举不一致。master比较的方法也比较简单如下所示:
private static class NodeComparator implements Comparator<DiscoveryNode> { @Override public int compare(DiscoveryNode o1, DiscoveryNode o2) { if (o1.masterNode() && !o2.masterNode()) { return -1; } if (!o1.masterNode() && o2.masterNode()) { return 1; } return o1.id().compareTo(o2.id()); } }
以上是节点排序比较器,可以看到它只是比较了nodeId,因此是按nodeId排序。为了解决brain split问题开发者加入了master候选数据量限制,代码如下:
public boolean hasEnoughMasterNodes(Iterable<DiscoveryNode> nodes) { if (minimumMasterNodes < 1) { return true; } int count = 0; for (DiscoveryNode node : nodes) { if (node.masterNode()) { count++; } } return count >= minimumMasterNodes; }
通过比较节点能“看到”的候选master数量和配置的最小值来确定是否可以进行选举,如果数量不够会导致选举不能进行,这样就可以保证集群不会被分裂。下面以一个图(图片来自于elasticsearch官网)来说明:
假设之前选举了A节点为master,两个switch之间突然断线了,这样就分词了两部分。CDE和AB,因为 minimumMasterNodes的数目为3(集群中5个节点都可以成为master,3=5/2+1),因此cde会可以进行选举假设C成为master。AB两个节点因为少于3所以无法选举,只能一直寻求加入集群,要么线路连通加入到CDE中要么就一直处于寻找集群状态,这样就保证了集群不分裂。
总结一下,本篇介绍了master选举的两种算法和elasticsearch的选举原理,并分析了它原理中的两条,第二条将在下一篇discovery中接下分析。
对比其它中间件选主机制: