【Elasticsearch】留意Elasticsearch 7.x 可能无法选主的问题

556 篇文章 544 订阅 ¥79.90 ¥99.00

在这里插入图片描述

1.概述

转载:留意Elasticsearch 7.x 可能无法选主的问题

Elasticsearch 7.x 选举算法改为基于 Raft 的实现,与标准 Raft 相比,最大的区别是允许选民可以投多票,当产生多个主节点的时候,让最后一个当选,这样,可以更快地选出主节点。但是这种机制同样也有缺点,就是会使竞选过程比较激烈。特别是当集群节点数量比较多的时候,候选人反复竞争可能会持续很长时间。

当遇到这种情况时,节点会有如下的日志:

master not discovered or elected yet, an election requires at least XX nodes with ids from [] which is a quorum; discovery will continue using [] from hosts providers and [] from last-known cluster state; node term 14, last-accepted version 71 in term 5

以及:

failed to join{…}
CoordinationStateRejectedException: incoming term 4996 does not match current term

在这里插入图片描述
但是这些报错和问题根因没有啥关系,探测到的节点已经能够达到 quorum,然后继续discovery,让人很费解。这时得把日志调到 DEBUG:

{
    "persistent": {
        "logger.org.elasticsearch.cluster.service.MasterService": "DEBUG",
        "logger.org.elasticsearch.cluster.coordination": "DEBUG"
    }
}
 

跟随报错日志”which is a quorum; discovery will“,从代码一路跟过去,发现只有becomeCandidate的时候才会触发,搜索 debug 日志”coordinator becoming CANDIDATE“,找到以下信息:

在这里插入图片描述
注意他上一个状态是FOLLOWER,在 Elasticsearch 的选举状态图里,只有加入集群才会切换到FOLLOWER状态。这说明有主节点被选出来了,继续搜 ”coordinator becoming FOLLOWER “,可以找到他切换到FOLLOWER时Leader的源地址:

在这里插入图片描述
然后看一下 Leader 节点的日志,发现有:

elected-as-master (.. nodes joined) 以及
failing [elected-as-master

在这里插入图片描述

可以看到节点起初被成功选为 Master,但是后来因为收到其他节点拉选票的RequestVote 请求(joinLeaderInTerm函数是对竞选请求的处理)取消集群状态的发布,切换到候选人状态。如果他成功发布了集群状态,新主就可以顺利当选了。

我们再观察候选人每次发起 RequestVote 的周期以及成功情况:

grep -E "starting election with|elected-as-master" logs/my-debug.log |less

发现他有时候甚至来不及被选为master,都没有走到发布集群状态的流程:
在这里插入图片描述
而来不及被选为 master 的原因是被其他候选人拉选票的请求打断:

在这里插入图片描述
在 Elasticsearch 的选举算法中,允许选民投多票,并让最后一个leader当选,这需要

  • 候选人在拉选票的过程中,如果收到其他候选人的 RequestVote,则清空自己已经收到的选票
  • 如果一个 leader 收到 RequestVote,则切换到候选人

决定竞选激烈程度的是几个超时时间控制的选举周期:

  • gracePeriod:固定的竞选时长限制,由cluster.election.duration配置,默认 500ms
  • maxTimeout:选举前的最大等待时间,由cluster.election.max_timeout配置,默认 10s
  • backoffTime:竞选失败进行重试时,用重试次数乘以 backoffTime,由cluster.election.back_off_time
    配置,默认 100ms

候选人的竞选过程周期性执行,执行周期就是在cluster.election.duration的基础上加上不超过最大等待时间的随机值。

//重试次数,每次加 1
final long thisAttempt = attempt.getAndIncrement();
//最大延迟时间不超过cluster.election.max_timeout配置,每次递增cluster.election.back_off_time
final long maxDelayMillis = Math.min(maxTimeout.millis(), initialTimeout.millis() + thisAttempt * backoffTime.millis());
//执行延迟在cluster.election.duration基础上递增随机值
final long delayMillis = toPositiveLongAtMost(random.nextLong(), maxDelayMillis) + gracePeriod.millis();
threadPool.scheduleUnlessShuttingDown(TimeValue.timeValueMillis(delayMillis), Names.GENERIC, runnable);

这个延迟时间是一个比较小的时间,我们截取两个时间点可以大致看一下增长情况,经过 4 分钟左右,竞选周期从 1 秒内增长到 7 秒。这个过程是线性增长的。

[2021-02-18T00:13:48,869][DEBUG]scheduleNextElection{ delayMillis=658}
[2021-02-18T00:17:53,743][DEBUG]scheduleNextElection{ delayMillis=7597}

从上面的实现可以看出,加大 cluster.election.duration可以降低选举激烈程度。

这里还有一个疑问,PreVote 是干什么去了,为什么没有拦截住?有两种情况:

  • 选民收到首次集群状态,才认为集群存在 Leader 了,后续的 Prevote 返回 false,但是在竞争激烈的时候没有节点被选为 leader。
  • 选民收到了首次集群状态,但在此之前又收到了其他节点的 RequestVote,导致自己的 term 更大了,首次集群状态因为 term 更低被忽略。如下图:

在这里插入图片描述
最后总结一下,虽然分析过程比较复杂,但是解决起来比较简单(不很完美):部署独立的主节点,并且可以考虑适当增大cluster.election.duration的配置

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值