Elasticsearch 分布式原理Node篇
ES集群构成
配置文件 conf/elasticsearch.yml
node.master: true
node.data: false
当node.master为true时,其表示这个node是一个master的候选节点,可以参与选举,在ES的文档中常被称作 master-eligible node,类似于Leader和Candidate的关系。当node.data为true时,这个节点作为一个数据节点,会存储分配在该node上的shard的数据并负责这些shard的写入、查询等。此外,任何一个集群内的node都可以执行任何请求,其会负责将请求转发给对应的node进行处理
节点发现
ES ZenDiscovery在选举时没有term的概念,不能保证每轮每个节点只投一票
Node启动后,首先要通过节点发现功能加入集群。ZenDiscovery是ES自己实现的一套用于节点发现和选主等功能的模块
# 推荐这里设置为所有的master-eligible node
discovery.zen.ping.unicast.hosts: [x.x.x.1, x.x.x.2, x.x.x.3]
Master选举
保证选举出的master被多数派(quorum)的master-eligible node认可,以此来保证只有一个master
# 设置 quorum
discovery.zen.minimum_master_nodes: 2
master选举发起的时机
当一个节点发现包括自己在内的多数派的master-eligible节点认为集群没有master时,就可以发起master选举
- 该master-eligible节点的状态为
当前没有master
- 该master-eligible节点通过ZenDiscovery模块的ping操作询问其已知的集群其他节点的信息,获取到的状态都为
当前没有master
- 包括本节点在内,当前已有超过minimum_master_nodes个节点认为集群没有master
master选举的投票对象
当clusterStateVersion越大,优先级越高。这是为了保证新Master拥有最新的clusterState(即集群的meta),避免已经commit的meta变更丢失
class Some {
// 计算出选举的投票对象
public MasterCandidate electMaster(Collection<MasterCandidate> candidates) {
assert hasEnoughCandidates(candidates);
List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates);
sortedCandidates.sort(MasterCandidate::compare);
return sortedCandidates.get(0);
}
// 先根据节点的clusterStateVersion比较,相同时,则按照节点的Id比较(Id为节点第一次启动时随机生成)
public static int compare(MasterCandidate c1, MasterCandidate c2) {
int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
if (ret == 0) {
ret = compareNodes(c1.getNode(), c2.getNode());
}
return ret;
}
}
达成选举
假设Node_A选Node_B当Master
Node_A会向Node_B发送join请求,那么此时:
(1) 如果Node_B已经成为Master,那么Node_B就会把Node_A加入到集群中,然后发布最新的cluster_state, 最新的cluster_state就会包含Node_A的信息。相当于一次正常情况的新节点加入。对于Node_A,等新的cluster_state发布到Node_A的时候,Node_A也就完成join了
(2) 如果Node_B在竞选Master,那么Node_B会把这次join当作一张选票。对于这种情况,Node_A会等待一段时间,看Node_B是否能成为真正的Master,直到超时或者有别的Master选成功。、
(3) 如果Node_B认为自己不是Master(现在不是,将来也选不上),那么Node_B会拒绝这次join。对于这种情况,Node_A会开启下一轮选举
假设Node_A选自己当Master
此时NodeA会等别的node来join,即等待别的node的选票,当收集到超过半数的选票时,认为自己成为master,然后变更cluster_state中的master node为自己,并向集群发布这一消息
脑裂保证
一个节点可能在相邻的两轮选主中选择不同的主,恰好导致这两个被选的节点都成为了主。但是这种脑裂很快会自动恢复,因为不一致发生后某个master再次发布cluster_state时就会发现无法达到多数派条件,或者是发现它的follower并不构成多数派而自动降级为candidate等
错误检测
MasterFaultDetection
Master定期检测集群内其他的Node
如果Master检测到某个Node连不上了,会执行removeNode的操作,将节点从cluster_state中移除,并发布新的cluster_state。当各个模块apply新的cluster_state时,就会执行一些恢复操作,比如选择新的primaryShard或者replica,执行数据复制等
NodesFaultDetection
集群内其他的Node定期检测当前集群的Master
如果某个Node发现Master连不上了,会清空pending在内存中还未commit的new cluster_state,然后发起rejoin,重新加入集群(如果达到选举条件则触发新master选举)。
rejoin
Master发现自己已经不满足多数派条件(>=minimumMasterNodes)了,需要主动退出master状态(退出master状态并执行rejoin)以避免脑裂的发生
electMasterService.hasEnoughMasterNodes
当有节点连不上时,会执行removeNode。在执行removeNode时判断剩余的Node是否满足多数派条件,如果不满足,则执行rejoinpublishClusterState.publish
在publish新的cluster_state时,分为send阶段和commit阶段,send阶段要求多数派必须成功,然后再进行commit。如果在send阶段没有实现多数派返回成功,那么可能是有了新的master或者是无法连接到多数派个节点等,则master需要执行rejoinotherClusterStateVersion > localClusterState.version()
在对其他节点进行定期的ping时,发现有其他节点也是master,此时会比较本节点与另一个master节点的cluster_state的version,谁的version大谁成为master,version小的执行rejoin
集群扩缩容
扩容DataNode
rebalance
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-reroute.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/shards-allocation.html
缩容DataNode
https://www.elastic.co/guide/en/elasticsearch/reference/current/allocation-filtering.html
PUT /_cluster/settings
{
"transient" : {
"cluster.routing.allocation.exclude._ip" : "10.0.0.1"
}
}
扩容MasterNode
先增大quorum,然后扩容节点
PUT /_cluster/settings
{
"persistent" : {
"discovery.zen.minimum_master_nodes" : 3
}
}'
缩容MasterNode
缩容MasterNode与扩容跟扩容是相反的流程,我们需要先把节点缩下来,再把quorum数调下来