龙空技术网

Elasticsearch入门《一》

未来的王十一 80

前言:

如今大家对“bully 算法”大概比较关怀,同学们都想要剖析一些“bully 算法”的相关资讯。那么小编在网络上网罗了一些有关“bully 算法””的相关内容,希望你们能喜欢,你们快快来了解一下吧!

es基本概念

ElasticSearch是准实时的分布式全文搜索分析引擎,内部使用Lucene做索引与搜索。适合做中等数据量的业务。

Es数据模型

ES 使用开源的 Lucene 作为存储引擎,它赋予 ES 高性能的数据检索能力,但 Lucene 仅仅是一个单机索引库。ES 基于 Lucene 进行分布式封装,以支持集群管理、分布式查询、聚合分析等功能。从使用的直观感受看,ES 按照下图方式实现了分布式查询:

查询类型

QUERY_THEN_FETCH: 这是最常用的查询类型,可以完成大多数的分布式查询和聚合分析功能。在这类查询中,协调节点实际需要向其他节点分发两轮任务,也就说前面流程图描述的任务分发阶段(2&3)会有两轮,具体如下:

Query Phase: 进行分片粒度的数据检索和聚合,注意此轮调度仅返回文档id集合,并不返回实际数据。协调节点: 解析查询后,向目标数据分片发送查询命令。数据节点: 在每个分片内,按照过滤、排序等条件进行分片粒度的文档 id 检索和数据聚合,返回结果。Fetch Phase: 生成最终的检索、聚合结果。协调节点: 归并Query Phase的结果,得到最终的文档id集合和聚合结果,并向目标数据分片发送数据抓取命令。数据节点: 按需抓取实际需要的数据内容。

QUERY_AND_FETCH: 对于查询仅涉及单个分片的场景,ES 会自动对查询流程做优化,在数据节点进行Query Phase的最后,直接执行Fetch操作。此类查询为 QUERY_AND_FETCH。通过去除一轮任务调度优化查询性能,优化过程由 ES 自动完成,用户不感知。

DFS_QUERY_THEN_FETCH: 这类查询用于解决 ES 在多分片、少数据量的场景下计算相关度不准确的问题:以 TF/IDF 算法为例,ES 在计算相关度时仅考虑单个分片内的 IDF,可能导致查询结果中,类似的文档因为在不同分片而相关度大为不同的问题。此时可以使用此类查询,在 QUERY_THEN_FETCH 之前再增加一轮任务调度,用于计算分布式的 IDF。但通常情况下,局部和全局 IDF 的差异会随着索引里文档数的增多渐渐消失,在真实世界的数据量下,这个问题几乎没有影响,没有必要使用此类查询增加一轮任务调度的开销。

PacificA 算法

ES 的数据副本模型基于主从模式,在实现过程中参考了微软的 PacificA 算法:

Replica Group:一个互为副本的数据集合称为副本组,其中只有一个副本是主数据(Primary),其他为从数据(Secondary)。Configuration:配置信息中描述了一个副本组都有哪些副本,Primary 是谁,以及他们位于哪个节点。Configuration Version:配置信息的版本号,每次发生变更时递增。Serial Number:代表每个写操作的顺序,每次写操作时递增,简称 SN。每个主分片节点维护自己的递增 SN。Prepare List:写操作的准备序列。存储来自外部请求的列表,将请求按照 SN 排序,向列表中插入的序列号必须大于列表中最大的 SN,每个副本上都有自己的 Prepare List。Committed List:写操作的提交列表。PacificA 算法的这些概念对应在 ES 中:Master 负责维护索引元信息,类似配置管理器维护配置信息。集群状态中的 routing_table 存储了所有索引、索引有哪些 shard、各自的主分片,以及位于哪个节点等信息,类似副本组。SequenceNumber 和 Checkpoint 类似 PacificA 算法中的 Serial Number 和 Comited Point。
数据副本策略

分片副本使用主从模式。多个副本中存在一个主分片和多个副本分片。所有的数据写入操作都是进入主分片,当主分片出现故障无法访问时,系统从其他副本分片中选择合适的副本作为新的主分片

数据写入流程如下:

写请求进入主分片节点,节点为该写操作分配 SN,使用该 SN 创建 UpdateRequest 结构。然后将该 UpdateRequest 插入自己的 Prepare List。主分片将携带 SN 的 UpdateRequest 发送到副本分片节点,副本分片节点收到后同样插入到自己的 Prepare List,完成后给主分片节点回复一个 ACK。一旦主分片节点收到所有副本分片节点的响应,确定该数据已经被正确写入所有副本节点,此时认为可以提交了。将此 UpdateRequest 放入 Committed List,Committed List 向前移动。主分片节点恢复客户端更新成功完成。对每一个 Prepare 消息,主分片节点向副本分片节点发送一个 commit 通知,告诉它们自己的 committed point 位置,副本分片节点收到通知后根据指示移动 committed point 到相同位置。配置管理

全局的配置管理器负责管理所有副本组的配置。节点可以向管理器提出添加/移除副本的请求,每次请求都需要附带当前配置的版本号,只有这个版本号和管理器记录的版本号一致才会被执行,如果请求成功,则这个新配置会被赋予新的版本号。

错误检测

分布式系统经常存在网络分区、节点离线等异常。全局的配置管理器维护权威配置信息。但其他各节点上的配置信息不一定同步,我们必须处理旧的主副本和新的主副本同时存在的情况。旧的主副本可能没有意识到重新分配了一个新的主副本,从而违反了强一致性。PacificA 使用了租约(lease)机制来解决这个问题。

主副本定期向其他从副本获取租约。这个过程中可能产生两种情况:

如果主副本节点在一定时间内(lease period)未收到从副本节点的租约回复,则主副本节点认为从副本节点异常,向配置管理器汇报,将该异常从副本从副本组中移除,同时,它也将自己降级,不再作为主副本节点。如果从副本节点在一定时间内(grace period)未收到主副本节点的租约请求,则认为主副本异常,向配置管理器汇报,将主副本从副本组中移除,同时将自己提升为新的主。如果存在多个从副本,则哪个从副本先执行成功,哪个从副本就被提升为新主。

假设没有时钟漂移,只要 grace period ≥ lease period,则租约机制就可以保证主副本会比任意从副本先感知到租约失效。同时任何一个从副本只有在它租约失效时才会争取去当新的主副本,因此保证了新主副本产生之前,旧的主分片已降级,不会产生两个主副本。

其他系统也经常将租约机制作为故障检测手段,如 GFS、Bigtable.

数据副本模型

定义:保持分片副本之间的同步,以及从中读取的过程

ES 的数据副本模型基于主备模式(primary-backup model),主分片是所有索引操作的入口。它负责验证索引操作是否有效。一旦主分片接受一个索引操作,主分片的副分片也会接受该操作

基本写入模型

客户端发送索引请求到达协调节点,协调节点先验证操作,如果有错就拒绝该操作。然后根据当前集群状态,请求被路由到主分片所在节点。该索引操作在主分片上本地执行,例如,索引、更新或删除文档。这也会验证字段的内容,如果未通过就拒绝操作(例如,字段串的长度超出Lucene定义的长度)。主分片操作成功执行后, 转发该操作到当前in-sync副本组的所有副分片。 如果有多个副分片,则会并行转发。一旦所有的副分片成功执行操作并回复主分片,主分片会把请求执行成功的信息返回给协调节点,协调节点返回给客户端。

Lucene仅支持对文档的整体更新,ES为了支持局部更新,在LuceneStore索引中存储了一个_source字段,该字段的key值是文档ID, 内容是文档的原文。当进行更新操作时先从_source中获取原文,与更新部分合并后,再调用lucene API进行全量更新。 对于写入了 ES 但是还没有 refresh 的文档,可以从 translog 中获取。另外为了防止读取文档过程后执行更新前有其他线程修改了文档,ES 增加了版本机制,当执行更新操作时发现当前文档的版本与预期不符,则会重新获取文档再更新。

写故障处理

写入期间可能会发生很多错误一硬盘损坏、 节点离线,或者某些配置错误,这些错误都可能导致无法在副分片上执行某个操作,虽然这比较少见,但是主分片必须汇报这些错误信息。

对于主分片自身错误的情况,它所在的节点会发送一个消息到Master节点,同时将有问题的分片从in-sync replica set中移除。这个索引操作会等待(默认为最多一分钟) Master节点提升一个副分片为主分片。 这个操作会被转发给新的主分片。注意,Master同样会监控节点的健康,并且可能会主动降级主分片。这通常发生在主分片所在的节点离线的时候。

在主分片上执行的操作成功后,该主分片必须处理在副分片上潜在发生的错误。错误发生的原因可能是在副分片上执行操作时发生的错误,也可能是因为网络阻塞,导致主分片无注转发操作到副分片,或者副分片无法返回结果给主分片。这些错误都会导致相同的结果:in-sync replica set中的一个分片丢失一个即将要向用户确认的操作。 为了避免出现不一致,主分片会发送一条消息到Master节点,要求它把有问题的分片从in-sync replica set中移除。一旦Master确认移除了该分片,主分片就会确认这次操作。注意,Master也会指导另一个节点建立个新的分片副本,以便把系统恢复成健康状态。

在转发请求到副分片时,主分片会使用副分片来验证它是否仍是一个活跃的主分片。如果主分片因为网络原因(或很长时间的GC)被隔离,则在它意识到被降级之前可能会继续处理传入的索引操作。来自陈旧的主分片的操作将会被副分片拒绝。当它接收来自副分片的拒绝其请求的响应时,它将会访问一下Master节点, 然后就会知道自己已被替换。最后将操作路由到新的主分片。

如果没有副分片呢,出现这种场景可能是因为索引配置或所有副分片都发生故障。在这种情况下,主分片处理的操作没有经过任何外部验证,可能会导致问题。另一方面,主分片节点将副分片失效的消息告知主节点,主节点知道主分片是唯一可用的副本。 因此我们确保主节点不会提升任何其他分片副本(过时的)为主分片,并且索引到主分片上的任何操作都不会丢失。当然,由于只运行单个数据副本,当物理硬件出问题时可能会丢失数据。可以使用 wait for active shards 缓解此类问题。

在写操作返回应答之前读取: 主分片首先在本地进行索引,然后转发请求,由于主分片已经写成功,因此在并行的读请求中,有可能在写请求返回成功之前就可以读取更新的内容。

基本读取模型

把读请求发送到相关分片。 注意,因为大多数搜索都会发送到一个或多个索引,通常需要从多个分片中读取, 每个分片都保存这些数据的一部分。从副本组中选择一个相关分片的活跃副本。它可以是主分片或副分片。默认情况下,ES 会简单地循环遍历这些分片。发送分片级的读请求到被选中的副本。协调节点合井结果并给客户端返回响应。注意,针对通过ID查找的get请求,会跳过这个步骤,因为只有一个相关的分片。
读故障处理

当分片不能响应一个读请求时,协调节点会从副本组中选择另一个副本,将请求转发给它。没有可用的分片副本会导致重复的错误。在某些情况下,例如,_searchES倾向于尽早响应,即使只有部分结果,也不等待问题被解决(可以在响应结果的shards字段中检查本次结果是完整的还是部分的)。

高效读取:在正常操作下,读操作在相关副本组中只执行一次。只有在出错的时候,才会在同一个分片的不同副本中执行多次

Es集群启动流程selectMaster(选举主节点)

Bully算法,核心要解决的问题是脑裂

Gateway(选举元信息)

被选举的Master和集群元信息的新旧程度没有关系。确定最新元信息

Allocation(选举主分片)

在初时阶段,所有的shard都处于unassigned状态;Es中通过分配过程决定哪个分片位于哪个节点,重构内容路由表。首先要做的是分配主分片

recovery(数据恢复)

主分片可能有数据未刷盘,副分片一是未刷盘,二是主分片写完了,副分片还没写;

主分片的recovery不会等待副分片分配完成,副分片的recovery需要等待主分片回复完毕后才开始

选主流程

Discovery模块负责发现集群中的节点,以及选择主节点。支持多种不同Discovery类型选择,内置实现称为Zen Discovery;

一致性策略:试图避免不一致;定义发生不一致后如何协调

选举算法:Bully算法 Paxos算法

Bully算法

假定所有节点都有一个唯一的ID,使用该ID对节点进行排序

任何时候的当前Leader都是参与集群的最高ID节点

附加约定条件:

参选人数过半得票人数过半当探测到节点离开时,必须判断当前节点数是否过半

Es采用的改进策略是:推迟选举,只要当前主节点不挂掉,就不重新选主;

详细流程

选举临时Master

ping所有节点,获取节点列表fullPingResponses,把本节点单独加入到fullPingResponses中

构建activeMasters和masterCandidates列表

If activeMasters 不为空

Then 从activeMasters中选择

Else 从masterCandidates中选择(取列表中的最小值或者自定义比较函数)

候选者达到法定人数

选主成功

确立Master或加入集群

发送投票:JoinRequest请求

收集投票:ZenDiscovery#handlerJoinRequest方法收集到的连接保存起来

如果临时Master是本节点:

等待足够多具备Master资格的节点加入本节点(投票达到法定人数)以完成选举

超时(默认30s)后还没有满足数量的join请求,则选举失败,进行新一轮选举

成功后发布新的clusterState

如果其他节点被选为Master

不再接收其他节点的join请求

向master发送joinRequest,并等待回复。超时时间默认1分钟,异常后重试3次

节点失效检测

Master节点启动NodesFD,定期探测加入集群的节点是否活跃。发现当前集群节点数量不足法定人数时,放弃Master身份,避免脑裂

非Master节点启动MasterFD,定期探测Master节点是否活跃,发现Master离线时,重新加入集群,即重新执行一遍选主流程

标签: #bully 算法