Elasticsearch——集群自动发现机制 Zen Discovery和Zen2

前言

Elasticsearch如此广泛流行的原因之一是因为其易于扩展,可以从仅具有几个节点的小集群扩展到有数百个节点的大型集群,并且保证不管集群规模的大小,其核心的分布式协调功能始终是稳定运行的。Elasticsearch 7.0版本开始引入了新的集群分布式协调子系统,与早期版本相比具有许多优势。

集群分布式协调

Elasticsearch集群可以执行许多需要多个节点参与协同工作的任务。如,将每个搜索路由到所有正确节点的分片上,以确保其结果准确无误。索引或删除某些文档时,必须更新相应节点上的每个副本。确保将每个客户端的请求从接收他的节点转发到可以处理它的节点。每个节点都维持了一份集群元信息的视图,节点根据集群元信息,执行搜索,索引和其他协调任务。这个集群元信息也称为集群状态(cluster state)。集群状态描述每个索引的映射和设置,决定每个分片分配到节点的位置,确定需要同步的分片副本数等。在整个集群中保持集群状态的一致性非常重要。很多近期发布的功能,如sequence-number、ccr,只有在集群状态一致性的保证下才能正常的工作。

协调子系统通过从节点中选举出主节点来工作。主节点会确保集群中所有的节点都能接收到集群状态的更新。这项工作是比较有挑战性的,因为像Elasticsearch这样的分布式系统必须准备好应对许多复杂的情况,如节点有时运行缓慢,Full GC导致的暂停,突然断电,网络分区,数据包丢失,高延迟时段,消息乱序等等。上述问题有可能会多个问题同时发生或间歇性的发生。即便在这样的复杂情况下,协调子系统必须依然能够保证每个节点都具有一致性的集群状态。

重要的是,Elasticsearch必须能够适应各类故障。它通过集群状态的更新必须被法定数量的节点确认这个规则来保证集群的可靠性。“法定节点数”是一个被精心选择的所有候选主节点的子集。仅要求法定节点响应状态更新请求的有点是集群的某些节点可能会在不影响集群可用性的情况下发生故障。必须仔细选择“法定节点”的集合,以确保集群不发生脑裂的情况,防止导致数据的丢失。

通常,我们建议集群有三个候选主节点,以便其中一个节点出现故障时,其他两个节点仍能安全的达成更新的法定节点数。如果集群的候选主节点数少于3个,则无法安全地容忍丢失任何节点。相反,如果集群有多余3个候选主节点,则选举和集群状态更新可能需要更长的时间。

Discovery发现模块

Discover是在集群Master节点未知时,互相发现对方的过程,例如新节点的加入或是先前的主节点宕机,如果一个节点不满足Master资格,则它将继续发现,直到发现了选定的主节点为止,其中,重试配置的属性为:discovery.find_peers_interval,默认值1s。

官网上Master-eligible的含义:设置了node-master:true的节点,表示有资格成为Master的节点,即控制集群的主节点。

发现方式

Elasticsearch6.x及更早版本使用Zen Discovery作为集群分布式协调子系统模块。这个子系统多年来不断地发展和成熟,成功的为各类规模的集群服务。

Zen discovery是内建的、默认的、用于Elasticsearch的发现模块。它提供了单播和基于文件的发现,可以通过插件扩展到支持云环境和其他形式的发现。

Zen Discovery 是与其他模块集成的,例如,节点之间的所有通信都使用 transport 模块完成。某个节点通过发现机制找到其他节点是使用 Ping 的方式实现的。

Zen Discovery 使用种子节点(seed nodes)列表来开始发现过程。在启动时,或者在选举新主节点的时候,Elasticsearch 会尝试连接到其列表中的每个种子节点,并与他们进行类似'闲聊'的对话,以查找其他节点并构建集群的完整成员图。

默认情况下,有两种方法可用于配置种子节点列表:单播基于文件。建议种子节点列表主要由集群中那些 Master-eligible 的节点组成。

单播

单播发现 配置静态主机列表以用作种子节点。 可以将这些主机指定为主机名IP地址。 指定为主机名的主机在每轮ping操作期间解析为 IP 地址。 请注意,如果您处于 DNS 解析随时间变化的环境中,则可能需要调整 JVM安全设置。

可以在 elasticsearch.yml 配置文件中使用discovery.zen.ping.unicast.hosts静态设置设置主机列表。

discovery.zen.ping.unicast.hosts: ["host1", "host2"]

具体的值是一个主机数组或逗号分隔的字符串。每个值应采用host:porthost的形式(其中port默认为设置transport.profiles.default.port,如果未设置则返回transport.tcp.port)。 请注意,必须将IPv6主机置于括号内。 此设置的默认值为127.0.0.1,[:: 1]

另外,discovery.zen.ping.unicast.resolve_timeout 配置在每轮ping操作中等待DNS查找的时间。需要指定时间单位,默认为5秒。

单播发现(unicast discovery)应用 transport 模块实现发现(discovery)。

基于文件

除了静态discovery.zen.ping.unicast.hosts设置提供的主机之外,还可以通过外部文件提供主机列表。Elasticsearch在更改时会重新加载此文件,以便种子节点列表可以动态更改,而无需重新启动每个节点。例如,这为在Docker容器中运行的Elasticsearch实例提供了一种方便的机制,可以动态提供一个IP地址列表,以便在节点启动时无法知道这些IP地址时连接到Zen discovery。

要启用基于文件的发现,请file按如下方式配置hosts提供程序

discovery.zen.hosts_provider:file

然后以$ES_PATH_CONF/unicast_hosts.txt下面描述的格式创建文件。每当对unicast_hosts.txt文件进行更改时,Elasticsearch都会选择新的更改,并使用新的主机列表。

请注意,基于文件的发现插件会增强单播主机列表 elasticsearch.yml:如果存在有效的单播主机条目, discovery.zen.ping.unicast.hosts则除了提供的那些之外,还将使用它们 unicast_hosts.txt。

discovery.zen.ping.unicast.resolve_timeout设置还适用于通过基于文件的发现由地址指定的节点的DNS查找。同样需要指定时间单位,默认为5秒。

该文件的格式是每行指定一个节点条目。每个节点条目由主机(主机名或IP地址)和可选的传输端口号组成。如果指定了端口号,必须在主机(在同一行)之后使用“:”分割。如果未指定端口号,则使用默认值9300。

例如,这是 unicast_hosts.txt 具有四个参与单播发现的节点的集群的示例,其中一些节点未在默认端口上运行:

10.10.10.5
10.10.10.6:9305
10.10.10.5:10005
# an IPv6 address
[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9301

允许使用主机名而不是IP地址(类似于 discovery.zen.ping.unicast.hosts)。必须在括号中指定IPv6地址,并在括号后面添加端口。

也可以为此文件添加注释,所有注释必须在每行的开头显示#(即注释不能在一行中间开始)。

文件配置方式为主机ip,主机ip:端口,也可以使用主机名配置,这会触发DNS查找,每次在DNS查找中的等待时间属性:discovery.zen.ping.unicast.resolve_timeout,默认为5S,如不指定端口,默认按顺序搜索transport.profiles.default.port、transport.port。

注意: 如果还配置了discovery.seed_hosts,则会把两个配置合并起来。

选举主节点

作为 ping 过程的一部分,一个集群的主节点需要是被选举或者加入进来的(即选举主节点也会执行ping,其他的操作也会执行ping)。这个过程是自动执行的。通过配置discovery.zen.ping_timeout来控制节点加入某个集群或者开始选举的响应时间(默认3s)。

在这段时间内有3个 ping 会发出。如果超时,重新启动 ping 程序。在网络缓慢时,3秒时间可能不够,这种情况下,需要慎重增加超时时间,增加超时时间会减慢选举进程。

一旦节点决定加入一个存在的集群,它会发出一个加入请求给主节点,这个请求的超时时间由discovery.zen.join_time控制,默认是 ping 超时时间(discovery.zen.ping_timeout)的20倍。

当主节点停止或者出现问题,集群中的节点会重新 ping 并选举一个新节点。有时一个节点也许会错误的认为主节点已死,所以这种 ping 操作也可以作为部分网络故障的保护性措施。在这种情况下,节点将只从其他节点监听有关当前活动主节点的信息。

如果discovery.zen.master_election.ignore_non_master_pings设置为true时(默认值为false),node.masterfalse的节点不参加主节点的选举,同时选票也不包含这种节点。

通过设置node.masterfalse,可以将节点设置为非备选主节点,永远没有机会成为主节点。

discovery.zen.minimum_master_nodes设置了最少有多少个备选主节点参加选举,同时也设置了一个主节点需要控制最少多少个备选主节点才能继续保持主节点身份。如果控制的备选主节点少于discovery.zen.minimum_master_nodes个,那么当前主节点下台,重新开始选举。

discovery.zen.minimum_master_nodes必须设置一个恰当的备选主节点值(quonum,一般设置 为备选主节点数/2+1),尽量避免只有两个备选主节点,因为两个备选主节点quonum应该为2,那么如果一个节点出现问题,另一个节点的同意人数最多只能为1,永远也不能选举出新的主节点,这时就发生了脑裂现象。

集群故障检测

当选的主节点会定期检查群集中的每个节点,以确保它们仍处于连接状态并且运行状况良好。群集中的每个节点还定期检查当选的主机的运行状况。这些检查分别称为 follower checks 和 leader checks。

7.0以后相关配置cluster.fault开头,更改默认设置可能会导致群集变得不稳定,不建议修改。

使用discovery.zen.fd前缀设置来控制故障检测过程,配置如下:

配置 描述
discovery.zen.fd.ping_interval 节点多久ping一次,默认1s
discovery.zen.fd.ping_timeout 等待响应时间,默认30s
discovery.zen.fd.ping_retries 失败或超时后重试的次数,默认3

集群状态更新

主节点是唯一一个能够更新集群状态的节点。主节点一次处理一个群集状态更新,应用所需的更改并将更新的群集状态发布到群集中的所有其他节点。当其他节点接收到状态时,先确认收到消息,但是不应用最新状态。如果主节点在规定时间(discovery.zen.commit_timeout ,默认30s)内没有收到大多数节点(discovery.zen.minimum_master_nodes)的确认,集群状态更新不被通过。

一旦足够的节点响应了更新的消息,新的集群状态(cluster state)被提交并且会发送一条消息给所有的节点。这些节点开始在内部应用新的集群状态。在继续处理队列中的下一个更新之前,主节点等待所有节点响应,直到超时(discovery.zen.publish_timeout,默认设置为30秒)。上述两个超时设置都可以通过集群更新设置api动态更改。

改变集群状态

投票配置

在elasticsearch7的版本中,当有一半的候选主节点宕机后,集群将不会自动恢复,在剩下的,这种极端情况下,最容易的解决办法就是让这些节点重新上线,在三个节点的集群中,通常能容忍一个节点的宕机。节点加入或离开集群后,Elasticsearch会通过自动对投票配置进行相应的更改来做出反应,以确保集群尽可能具有弹性。相关配置如下:

# 将节点加入投票配置排除列表中
# 默认超时时间30s,可以指定超时时间
POST /_cluster/voting_config_exclusions/node_name?timeout=1m

集群启动项

集群自举

首次启动Elasticsearch集群需要在集群中的一个或多个Master候选节点上显式定义初始一组主资格节点 . 这个行为称为集群自举。
符合主机要求的初始节点集是在cluster.initial_master_nodes设置中,要求如下:

节点的节点名称。
该节点的主机名,如果node.name没有设置,因为node.name默认为节点的主机名. 根据系统配置,必须使用标准主机名或裸机主机名.
节点的发布地址的IP地址(如果无法使用该节点的node.name 。这是network.host解析到的IP地址,但是可以覆盖此IP地址。
节点发布地址的IP地址和端口,格式为IP:PORT ,如果不可能使用节点的node.name ,并且有多个节点共享一个IP地址

注意:

  • 启动Master候选节点时,可以在命令行上或elasticsearch.yml文件中提供此设置. 群集形成后,不再需要此设置,并且会忽略它,也就是说,这个属性就只是在集群首次启动时有用。并且可以不需要在非Master候选节点上设置。
  • 特别要小心的是,对于Master候选节点的配置最好采用持久化的方式来替代使用CMD命令行的方式启动,因为如果一旦重启Master候选节点时,指定错误,则有可能形成两套不相同的集群。这有可能带来数据丢失的。

通过cluster.name设置,可以创建彼此分离的多个群集. 节点在首次相互连接时会验证它们是否同意其集群名称,并且Elasticsearch将仅由具有相同集群名称的节点组成集群. 集群名称的默认值是elasticsearch ,但是建议更改此值以反映集群的逻辑名称。

添加OR删除节点

由于elasticsearch集群节点时可以动态上线下线的,那在这个过程中,我们能够理解或需要够操作什么呢。在主服务器选举期间或加入现有的已形成集群时,节点会向主服务器发送加入请求,以便将其正式添加到集群中. 可以使用cluster.join.timeout设置来配置节点在发送加入集群的请求后等待多长时间. 其默认值为30s。

删除符合主机资格的节点时,重要的是不要同时删除太多节点。 例如,如果当前有七个Master候选的节点,希望将其减少到三个,则不可能简单地一次停止四个节点:这样做将只剩下三个节点,这少于一半投票配置,这意味着群集无法采取任何进一步的措施.只要集群中至少有三个符合主控条件的节点,通常,最好一次删除一个节点,从而为集群留出足够的时间来自动调整表决配置并适应故障新节点集的容差级别。

这里,我们需要注意,节点上线下线,我们都需要关注防止“脑裂”的配置,通过调用Elasticsearch APi的方式,将配置持久化下来,而不用重启节点。

curl  -uelastic:passwd -XGET "EsIP:9200/_cluster/settings" -H "Content-Type:application/json" -d '
{
    "persistent" : {
        "discovery.zen.minimum_master_nodes" : 2
    }
}

发布集群的状态

只有Master节点可以更改集群状态。更改后会将更新的状态发布到集群中所有的节点上,每个节点都会接受这个消息,并进行Ack确认。但是不会应用这个更新。主节点需要在discovery.zen.commit_timeout配置的时间内获取discovery.zen.minimum_master_nodes个Ack响应,才算是状态成功的发布,否则这次发布就是失败的,不会被应用。

对于那些未收到确认的节点被称为滞后,因为它们的群集状态已落后于主服务器的最新状态。主机等待滞后的节点再追赶一段时间,通过cluster.follower_lag.timeout ,默认为90s . 如果节点在此时间内仍未成功应用集群状态更新,则认为该节点已失败并从集群中删除。

Master确认Ack数量满足后,才会继续发送确认消息给所有节点,此时节点才会真正的应用这个集群的状态信息,这第二个过程是通过discovery.zen.publish_timeout配置的,默认是30s,这个超时等待时长是从第二次发布时开始计算的。

由上述可以,在发布集群状态时,获取Master候选节点的Ack是很重要的,节点数量由discovery.zen.minimum_master_nodes配置。而没有主节点时,也有相关配置需要了解,它就是:discovery.zen.no_master_block

No master block

对于一个可以正常充分运作的集群来说,必须拥有一个活着的主节点和正常数量(discovery.zen.minimum_master_nodes个)活跃的备选主节点。discovery.zen.no_master_block设置了没有主节点时限制的操作。它又两个可选参数:

  • all:所有操作均不可做,读写、包括集群状态的读写api,例如获得索引配置(index settings),putMapping,和集群状态(cluster state)api
  • write:默认为write,写操作被拒绝执行,基于最后一次已知的正常的集群状态可读,这也许会读取到已过时的数据。同时需要注意,这个属性对Node level相关的api是无效的。

discovery.zen.no_master_block,对于节点相关的基本api,这个参数是无效的,如集群统计信息(cluster stats),节点信息(node info),节点统计信息(node stats)。对这些api的请求不会被阻止,并且可以在任何可用节点上运行。

发现和形成集群的配置

这里列举几个必要重要的配置:

discovery.seed_hosts
  • 提供集群中符合主机要求的节点的列表. 每个值的格式为host:porthost,其中port默认为设置transport.profiles.default.port
discovery.seed_providers
  • 以文件的方式提供主机列表,可以动态修改,而不用重启节点(容器化环境适用)
cluster.initial_master_nodes
  • 设置全新群集中符合主机要求的节点的初始集合.。默认情况下,该列表为空,这意味着该节点希望加入已经被引导的集群。
discovery.find_peers_interval
  • 选定主节点发现时间间隔,默认1S。

Zen2

从Elasticserch7.0开始,重新设计并重写了集群协调子系统:

  • minimum_master_nodes配置被移除,有利于允许Elasticsearch自己选择由哪些节点组成法定选举节点。
  • 典型的主节点选举可以在1s内完成。
  • 增长和缩小集群变得更安全,更容易,并且错误配置导致数据丢失的机会变少了。
  • 节点增加更多的记录状态的日志,帮助诊断无法加入集群或无法选举出主节点的原因。

在添加或删除节点时,Elasticsearch会自动的通过更新集群的投票配置(voting configuration)来维持最佳的容错级别。voting configuration是一组当前可以参与投票的的候选主节点。通常,voting configurations包含集群中所有符合条件的候选主节点。所有集群状态的更新都需要有voting configurations中一半以上的节点同意。由于现在交由系统来管理voting configurations,即投票的法定数量节点,即使在添加或删除节点的时候也可以避免因错误的人工配置导致的数据丢失。

如果节点无法发现当前主节点并且无法赢得选举,那么从7.0版本开始,Elasticsearch将定期记录一条警告日志,详细描述其当前的状态,以帮助诊断许多常见问题。

另外,老版本的Zen Discovery有一种非常罕见的故障模式,在Elasticsearch Resiliency Status页面上记录为“重复多次的网络分区故障可能导致集群状态更新丢失”,这个问题在新版本中已解决。

如何使用Zen2

如果您使用默认配置启动一些新安装的Elasticsearch节点,那么它们将自动寻找在同一主机上运行的其他节点,并在几秒钟后形成一个集群。如果在同一主机上启动更多节点,则默认情况下它们也会发现并加入此集群。使用Elasticsearch 7.0版本可以和早期版本一样轻松部署多个节点。

这种全自动的集群发现机制在单个物理主机上运行良好,单不够鲁棒性,无法在生产或其它严格的分布式环境中使用。这里存在很多风险,节点可能不会及时发现彼此从而形成多个独立的集群。从7.0版本开始,如果要启动在多个物理主机上启动一个全新的集群,必须指定参与第一次投票选举的候选主节点。这个过程称为集群启动引导,仅在集群第一次启动时才需要。已加入集群的节点会将投票配置存储在数据文件中,并在重启后使用这份配置。一个已经存在的集群如果新加入一个节点,可以从集群的当前主节点上接收这个配置。

启动集群时设置的cluster.initial_master_nodes可以指定node nameIP。可以在启动命令或yml配置中指定。同时还需要指定发现子系统的相关配置以便节点可以互相发现。

如果一个新节点启动时,未设置cluster.initial_master_nodes,那么它会尝试发现并加入现有的集群。如果节点找不到要加入的集群,那么它将定期记录一个警告日志。

master not discovered yet, this node has not previously joined a bootstrapped (v7+) cluster,

and cluster.initial\_master\_nodes is empty on this node

添加新的候选主节点不需要任何特殊的步骤。只需要配置新节点发现配置,启动节点,集群将会安全自动的重新配置voting configuration。您也可以随时安全的删除节点,只要保证不同时停止一半以上的候选主节点。如果确实需要停止一半或更多的候选主节点,后者您有更复杂的扩展需求,Elasticsearch提供一个更有针对性的扩展过程,使用API直接调整voting configuration。

升级

可以通过滚动升级或完全重启升级两种方式,将Elasticsearch集群从6.x版本升级到7.0版本,建议进行滚动升级,因为滚动升级过程中集群可以保持可用。在执行滚动升级到7.0版本之前,必须将6.x版本的集群升级到6.7版本。完全重启升级方式允许您从任何的6.x版本升级到7.0版本,但需要关闭整个集群。7.0版本相比于6.x版本增加了很多改动,不仅仅只是集群协调的改进。为了确保顺利升级,应该详细的查看升级说明。

如果执行滚动升级,集群会根据节点数和老版本的minimum_master_nodes配置自动执行集群初次启动引导。这意味着在开始升级前要正确的设置这个配置项。此处无需设置initial_master_nodes,因为集群执行升级时会自动执行初次启动引导。7.0版本的候选主节点会优先投票给6.7版本的节点,因此升级过程中6.7版本的节点会称为主节点,直到集群中所有的节点都升级为7.0版本。

如果要执行完全重启升级,则必须按上述方法设置启动引导:在重新启动集群前,必须将initial_master_nodes设置为所有候选主节点的名字或IP地址。

在6.x版本以及更早的版本中,还有一些其他的设置允许配置Zen Discovery的行为。其中一些设置不再有任何作用,已经被删除。另外一些已经更名。已经重新命名的设置,在7.0版本中不推荐使用旧的名称,您应该调整配置来使用新的名称:

原名 新名
discovery.zen.ping.unicast.hosts discovery.seed_hosts
discovery.zen.hosts_provider discovery.seed_providers
discovery.zen.no_master_block cluster.no_master_block

新的集群协调子系统包括一个新的故障检测机制。这意味着discovery.zen.fd.*命名空间中的Zen Discovery故障检测设置不再具有任何效果。大多数用户应该使用7.0版本及更高版本中的默认故障检测配置cluster.fault_detection.*

安全第一

7.0之前的Elasticsearch版本有时会让您无意中执行一系列的步骤,这些步骤会让集群的一致性处于危险的情况。相比之下,7.0及更高版本将使您充分意识到您可能正在做一些不安全的事情,并且需要确认是否继续。

比如,在Elasticsearch7.0版本中,当一半以上的候选主节点永久丢失,集群将不会自动恢复。通常在有三个候选主节点的集群中,允许集群在不停机的情况下容忍其中一个节点丢失。如果其中两个永久丢失,则剩余的一个节点无法继续安全的工作。

7.0之前的版本允许集群悄然的从这种情况中恢复。用户可以通过启动全新的候选主节点来替换任意数量的丢失节点,从而使集群恢复工作。当候选主节点永久丢失一半以上时,集群自动恢复是不安全的,因为剩余的节点都不能确定是否有集群状态的最新版本,这很有可能会导致数据丢失。例如,部分节点丢失前,可能已经删除了某分片的副本,如果剩余的节点不知道这个状态,那么旧的分片副本可能会被提升为主分片。最危险的地方在于,用户完全没有意识到这一系列步骤使他们的集群处于数据丢失的危险之中,而意识到数据不一致时可能已经隔了数周或数月之久。

在Elasticsearch 7.0及以上的版本,与上面类似的不安全的操作将受到更多的限制,集群宁愿不可用等待人工修复而不是冒这种丢失数据的风险。如果您判断有绝对的必要,仍然可以执行这类不安全的操作,只需要采取一些额外步骤即可向集群确认您已经意识到风险并采取了很多措施。

如果您真的丢失了一半或以上的候选主节点,那么首先要尝试的是将丢失的候选主节点重新上线。如果节点的数据目录完好无损,那么最好的办法是使用这些数据启动新节点,通过采取这些措施,集群会同步最新的集群状态并安全的恢复工作。

接下来要尝试从最近的快照还原集群,但丢失了自拍摄快照以来所写的任何数据。然后,您可以再次重新索引任何丢失的数据,因为您知道缺少的数据的时间段。快照是增量的,因此您可以非常频繁地执行他们。每隔30分钟拍摄一次快照以限制此类恢复中丢失的数据量并不罕见。

如果上面这些恢复操作都不可行,最后的手段就是elasticsearch-node unsafe recovery tool。这是一个命令行工具,系统管理员可以运行该工具来执行不安全的操作,例如从少数节点中集群状态版本比较旧的节点为主节点。通过把破坏集群一致性的操作都明显的暴露给用户,Elasticsearch 7.0消除了许多无意中导致数据丢失风险的情况。

如何工作

如果熟悉分布式系统的理论,则可以将集群协调视为分布式共识协议的一种实现。在开发Elasticsearch早期版本的时候,分布式共识并未被广泛理解,然而近几个版本以来在这方面的技术有着显著的提高。

Zen Discovery模块从分布式共识算法中吸收了很多好的想法,但并不是完全严格遵循理论规定的模型。模块的实现具有非常保守的超时时间,使其有时在失败后恢复非常缓慢。在7.0中引入新的集群协调子系统使我们有机会更加密切地遵循理论模型。

分布式协调是一个公认的技术难点。在很大程度上依靠正式的方法来预先验证我们的设计,自动化工具在正确性和安全性方面提供了强有力的保证。您可以在我们的公共代码库中找到Elasticsearch新的集群协调算法的正式规范。该算法的核心安全模块非常简洁,并且算法模型与实现代码之间有一一对应的关系。

如果您了解过相关的分布式共识算法,如Paxos,Raft和Viewstamped Replication(VR),会发现Elasticsearch核心的模块看起来会很熟悉。他模拟一个可重写的寄存器,并使用一个master term的概念,与Paxos的ballots,Raft的term,VR算法的view非常相似。分布式协调的核心安全模块及模型还覆盖了集群引导,跨节点重启的持久性以及动态重新配置。所有这些功能对于确保系统在所有情况下都能正常运行非常重要。

围绕这个健壮性理论的核心,构建了一个活跃层,以确保无论集群发生什么故障,一旦网络恢复且足够的节点恢复在线,集群将会立刻选出一个主节点并能够发布最新的集群状态更新。活跃层使用了许多最先进的技术来避免许多常见问题。选举调度程序能适配网络的条件来改变执行的行为来避免有争议的选举。学习了Raft风格的投票前阶段来抑制无法取胜的选举,避免了流氓节点的破坏。数据版本滞后检测可防止节点数据滞后主节点数据情况下破坏集群。主动双向故障检测可保证集群中的节点始终可以互相通信。尽量让大多数的集一个节点复制到另一个节点。集群状态更新为小差异的增量发布,避免将全量集群状态从一个节点复制到另一个节点。优雅的停止主节点将显示的放弃选择后继,避免全面选举来减少故障转移期间的停机时间。我们部署了测试的基础架构,可以有效地模拟可能持续数秒,数分钟或数小时的异常中断的情况,从而使我们能够验证在中断解决后集群始终能够快速恢复。

为何不直接采用Raft协议?

在社区中,我们常常会被问到一个问题,为什么Elasticsearch不简单的置入标准的分布式共识算法,如Raft协议。我们调研了很多知名的算法,每种都会根据场景在算法实现上做出不同的权衡考量。我们仔细评估各类算法并从所有能找到的文献中汲取灵感。我们早期的一个Poc使用了更接近Raft的协议,通过这次经验,我们了解到将其与Elasticsearch完全集成兼容所需要的工作量是巨大的。许多Raft中的标准算法还限定了一些对Elasticsearch来说不是最理想的设计决策。如:

它们通常围绕操作日志构建,而Elasticsearch的集群协调更直接地基于集群状态本身。这使得如批量这类重要的优化可以实现的更简单。
它们通常只有有限的扩容或缩容的能力,需要一系列的步骤来实现许多维护任务,而Elasticsearch的集群协调可以在一个步骤中安全地执行任意的变更。这是通过避免有问题的中间状态来简化系统间的实现。
他们通常非常注重安全性,但是并没有将如何包活的细节暴露出来,并且也没有描述清楚如果发现节点不健康应该如何处理。Elasticsearch的监控检查很复杂,已经在生产环境中使用和改进了很多年,对我们来说保持其现有行为非常重要。事实上,实现系统的安全特性所需要的工作要不保活及健康检查要少的多。大部分的工作主要都集中在系统的可用性检查上。
改进过程中有一个重要的目标是要支持从运行老的Zen Discovery的6.7集群不停机滚动升级至运行7.x的版本。将任何标准算法调整为允许这种滚动升级似乎都是行不通的。
要实现一个工业级的分布式共识算法,需要耗费大量的精力及人力来开发,并且实际情况已经超出了学术文献所概述的范围。在实践中不可避免的需要定制,但因为协议很复杂,任何定制化都有引入错误的风险。从工程角度来看,最有效的方法是吸纳一些好的思想,基于定制化的需求开发一套新的协议。

总结
Elasticsearch 7.0 新增了一个更快,更安全,更易于使用的新的集群分布式协调子系统。它支持从6.7开始不停机的滚动升级,并为弹性复制集提供基础。要试用新的集群协调子系统,请下载最新的7.0版本,查阅文档,了解它。

参考:
https://www.cnblogs.com/jajian/p/10176707.html

https://cloud.tencent.com/developer/article/1421861

https://www.cnblogs.com/hyq0823/p/11569606.html

https://www.elastic.co/cn/blog/a-new-era-for-cluster-coordination-in-elasticsearch

你可能感兴趣的:(Elasticsearch——集群自动发现机制 Zen Discovery和Zen2)