【架构师面试-搜索-3】-ElasticSearch集群启动过程

理解原理对于解决或避免集群维护过程中可能遇到的脑裂、无主、恢复慢、丢数据等问题很有帮助。

1 集群启动主要流程 

【架构师面试-搜索-3】-ElasticSearch集群启动过程

1. Elect-master

选出临时Master【参选人数过半】

确定Master【得票过半】

检测集群节点数【离开节点】

2. Gateway

Master 索取MetaState

选举元信息,发布元信息

参与元信息选举的节点数过半

3. Allocation

向所有节点询问shard信息

磁盘且in-sync列表存在为主分片

磁盘存在选为副本否则延迟分配

4. Recovery

两阶段恢复

translog事件日志

2 Elect-master

集群选举,集群启动的第一件事:从已知的活跃机器列表中选择一个作为主节点。选主之后的流程由主节点触发。

选主算法:基于Bully算法进行了改进。

主要思路:对节点ID排序,取ID值最大的节点作为Master,每个节点都运行这个流程。简单来说就是基于节点ID排序的简单选举算法。

为什么不使用Raft算法,为什么不使用Paxos算法?

选主目的:确定唯一的主节点

3 Gateway

选举元信息,被选出的 Master 和集群元信息的新旧程度没有关系。因此它的第一个任务是选举元信息,让各节点把各自存储的元信息发过来,根据版本号确定最新的元信息,然后把这个信息广播下去,这样集群的所有节点都有了最新的元信息。

集群元信息的选举包括两个级别:集群级和索引级。不包含哪个shard存于哪个节点这种信息。这种信息以节点磁盘存储的为准,需要上报。为什么呢?因为读写流程是不经过Master的,Master 不知道各shard 副本直接的数据差异。

集群元信息选举完毕后,Master发布首次集群状态,然后开始选举shard级元信息。选举shard级元信息,构建内容路由表,是在allocation模块完成的。

4 allocation

在初始阶段,所有的shard都处于UNASSIGNED(未分配)状态。

ES中通过分配过程决定哪个分片位于哪个节点,重构内容路由表。此时,首先要做的是分配主分片。

1 分配主分片

主分片如何分配?

Master节点向集群中所有节点询问:所有节点将分片的元信息返回给Master,根据返回的 shard 信息,配合主节点内的分配策略选一个分片作为主分片。

这种做法效率怎么样?

询问量=shard 数×节点数。所以说我们最好控制shard的总规模别太大。有了shard的分片的多份信息,剩下的就是选出主分片。

主分片选举方式:

ES 5.x之前,通过对比shard级元信息的版本号来决定潜在问题:在多副本的情况下,考虑到如果只有一个 shard 信息汇报上来,则它一定会被选为主分片,但数据不一定是最新的。可能版本号比它大的那个shard所在节点还没启动。

ES 5.x之后:通过集群级元信息中记录的“最新主分片列表”确定主分片【汇报信息中存在,并且这个列表中也存在】

给每个 shard 都设置一个 UUID,然后在集群级的元信息中记录哪个shard是最新的。

因为ES是先写主分片,再由主分片节点转发请求去写副分片,所以主分片所在节点肯定是最新的。

主分片数量取决于什么?

2 分配副分片

主分片选举完成后,从上一个过程汇总的 shard 信息中选出副本。

如果汇总信息中不存在,则分配一个全新副本。分配的时间依赖于延迟配置项:index.unassigned.node_left.delayed_timeout

tip:我们的生产环境中最大的集群有100+节点,掉节点的情况并不罕见,很多时候不能第一时间处理,这个延迟我们一般配置为以天为单位。

allocation过程中允许新启动的节点加入集群。分片分配成功后进入recovery流程。

5 recovery

为什么需要recovery?

对于主分片来说,可能有一些数据没来得及刷盘

对于副分片来说,一是没刷盘,二是数据的不一致【主分片写完了,副分片还没来得及写,主副分片】

1 主分片recovery

将最后一次提交之后的 translog重放,建立Lucene索引,如此完成主分片的recovery

每次写操作都会记录translog【事务日志中记录了哪种操作以及相关数据】。

Lucene 的一次提交就是一次 fsync 刷盘的过程

2 副分片recovery

在ES的版本迭代中,副本分片的恢复策略有过不少调整,比较复杂。

副分片需要恢复成与主分片一致,同时,恢复期间还需要允许新的索引操作。

在6.0版本中,恢复分成两个阶段执行:

phase1:

在主分片所在节点,获取translog保留锁,从获取保留锁开始,会保留translog不受其刷盘清空的影响。

然后调用Lucene接口把已经刷磁盘中的shard做快照。然后把这些shard数据复制到副本节点。

在phase1完毕前,会向副分片节点发送告知对方启动engine

在phase2开始前,副分片就可以正常处理写请求了。

phase2:

对translog做快照,这个快照里包含从phase1开始,到执行translog快照期间的新增索引。

将这些translog发送到副分片所在节点进行重放。

思考:第二阶段运行期间,如果刷盘并清空tranlog怎么办?

3 恢复需重点关注4个问题

由于需要支持恢复期间的新增写操作(让ES的可用性更强),需要重点关注以下几个问题。

1. 分片数据完整性:如何做到副分片不丢数据?

第二阶段的 translog 快照包括第一阶段所有的新增操作。那么第一阶段执行期间如果发生“Lucene commit”(将文件系统写缓冲中的数据刷盘,并清空translog),清除translog怎办?

在ES 2.0之前:阻止了刷新操作,以此让translog都保留下来。

从ES 2.0之后:为了避免这种做法产生过大的translog,引入了translog.view的概念,创建 view 可以获取后续的所有操作。

从ES 6.0之后:translog.view 被移除,引入TranslogDeletionPolicy的概念,它将translog做一个快照来保持translog不被清理。这样实现了在第一阶段允许Lucenecommit。

2. 数据一致性

在ES 2.0之前:副分片恢复过程其实是三个阶段,第三阶段会阻塞新的索引操作,传输第二阶段执行期间新增的translog,这个时间很短。

在ES2.0之后:第三阶段被删除,恢复期间没有任何写阻塞过程。但是在副分片节点,重放translog时,phase1和phase2之间的写操作与phase2重放操作之间的时序错误和冲突【极少】。

通过写流程中异常处理,和对比版本号来过滤掉过期操作对于特定的 doc,只有最新一次操作生效,保证了主副分片的数据一致性

3. 第一阶段操作优化:第一阶段尤其漫长,因为它需要从主分片拉取全量的数据。

索引数据恢复是最漫长的过程。当shard总量达到十万级的时候,6.x之前的版本集群从Red变为Green的时间可能需要小时级。

在ES 6.x之后:增量同步,对第一阶段再次优化,标记每个操作。

在正常的写操作中,每次写入成功的操作都分配一个序号,通过对比序号就可以计算出差异范围然后同步。

ES 6.x中的translog恢复是一次重大改进,避免了从主分片所在节点拉取全量数据,为恢复过程节约了大量时间。

4. 集群启动过程中,集群健康值变化含义

当一个索引的主分片分配成功后,到此分片的写操作就是允许的。

当一个索引所有的主分片都分配成功后,该索引变为Yellow。

当全部索引的主分片都分配成功后,整个集群变为Yellow。

当一个索引全部分片分配成功后,该索引变为 Green。

当全部索引的索引分片分配成功后,整个集群变为Green。

上一篇:ES动态模板配置


下一篇:es~日期类型需要注意的