发现和组建Elasticsearch集群

184 阅读18分钟

发现和组建Elasticsearch集群

发现和组建集群的机制能主要负责集群的节点发现、master的选举、组建集群、在集群有变化的时候发布集群的状态。下面的这些进程是发现和组建集群的一部分:

发现

发现机制通常在master未知的时候,让节点间相互发现。他通常出现在节点刚刚启动或者master挂了还未重新选举的时候。

选举

基于法定人数的选举机制可以让集群决策一件事情,尽管有的节点不可用的情况。

选举配置

在一个节点加入或者离开集群的时候,更新选举配置。

启动一个集群

当集群第一次启动的时候,启动一个集群是需要的。在开发环境中,发现配置是没有配置的,因此取决于节点自己。但是在生产环境则需要依据一定的经验小心配置。

增加或者删除合格master

强烈推荐配置一个固定的且小的合格的master数量,而且仅通过添加或者删除合格的master节点来扩缩容集群。然而,在某些情况下,向集群中添加或从集群中移除一些有资格成为主节点的节点可能是可取的。然而,在某些情况下,向集群中添加或从集群中移除一些有资格成为主节点的节点可能是可取的。

发布集群状态

这个进程主要是被选举出来的master在各个节点上更新集群的状态。

集群的失败节点

通过心跳机制检测集群的失败节点,然后移除他。

配置

这里的配置允许用户配置节点的发现机制、选举机制、失败节点的检测等。

发现

“Discovery” 是集群形成模块找到其他节点以形成集群的过程。这个过程在启动 Elasticsearch 节点时运行,或者当一个节点认为master失效时持续进行,直到找到主节点或者选出新的master。

这个过程从一个或多个种子主机提供者提供的种子地址列表以及上一个已知集群中的任何有资格成为master的地址开始。这个过程分两个阶段进行:首先,节点通过连接到每个地址来探测种子地址,试图识别它所连接的节点,并验证该节点是否有资格成为master。其次,如果成功,它会与远程节点共享其所有已知的有资格成为主节点的对等节点列表,远程节点则依次回应其对等节点。

然后,该节点探测它刚刚发现的所有新节点,请求它们的对等节点,依此类推。

如果节点没有资格成为主节点,那么它将继续这个发现过程,直到发现一个已选出的主节点。如果没有发现已选出的主节点,那么该节点将在 “discovery.find_peers_interval”(默认为 1 秒)后重试。

如果节点有资格成为主节点,那么它将继续这个发现过程,直到它要么发现一个已选出的主节点,要么发现足够多的无主的有资格成为主节点的节点以完成选举。如果这两种情况都没有发生,那么该节点将在 “discovery.find_peers_interval”(默认为 1 秒)后重试。

一旦选出一个主节点,它通常会一直作为已选出的主节点,直到被故意停止。如果故障检测确定集群有故障,它也可能停止作为主节点。当一个节点不再是已选出的主节点时,它会再次开始发现过程。参考 “Troubleshooting discovery” 以解决与发现相关的问题。

种子节点提供

默认情况下,集群形成模块提供两种方式提供种子节点列表:基于设置的和基于文件的种子主机提供程序。

它可以通过发现插件进行扩展,以支持云环境和其他形式的种子主机提供程序。

种子主机提供程序使用 discovery.seed_providers 设置进行配置,该设置默认为基于设置的主机提供程序。此设置接受不同提供程序的列表,允许您使用多种方式为集群查找种子主机。每个种子主机提供程序生成种子节点的 IP 地址或主机名。如果它返回任何主机名,则使用 DNS 查找将这些主机名解析为 IP 地址。如果一个主机名解析为多个 IP 地址,那么 Elasticsearch 会尝试在所有这些地址中找到一个种子节点。如果主机提供程序没有明确给出节点的 TCP 端口,那么它将隐式使用 transport.profiles.default.port 给出的端口范围中的第一个端口,如果未设置 transport.profiles.default.port,则使用 transport.port。并发查找的数量由 discovery.seed_resolver.max_concurrent_resolvers 控制,默认为 10,每个查找的超时时间由 discovery.seed_resolver.timeout 控制,默认为 5 秒。请注意,DNS 查找受 JVM DNS 缓存影响。

基于配置的种子列表

基于设置的种子主机提供程序使用节点设置来配置种子节点地址的静态列表。这些地址可以作为主机名或 IP 地址给出;指定为主机名的主机在每一轮发现过程中会被解析为 IP 地址。主机列表是使用 discovery.seed_hosts 静态设置进行设置的。例如:

discovery.seed_hosts:
   - 192.168.1.10:9300
   - 192.168.1.11 
   - seeds.mydomain.com 
  1. 如果没有指定,端口将默认为 transport.profiles.default.port,如果这个也未设置,则回退到 transport.port。
  2. 如果一个主机名解析为多个 IP 地址,那么 Elasticsearch 将尝试连接到每个已解析的地址。

基于文件的配置方式

基于文件的种子主机提供程序通过外部文件配置一系列主机。Elasticsearch 在该文件发生变化时重新加载它,这样种子节点列表可以动态更改,而无需重新启动每个节点。例如,这为在 Docker 容器中运行的 Elasticsearch 实例提供了一种便捷机制,当 IP 地址在节点启动时可能未知的情况下,可以动态地为其提供要连接的 IP 地址列表。要启用基于文件的发现功能,可在 elasticsearch.yml 文件中按如下方式配置文件主机提供程序。

discovery.seed_providers: file

然后在 $ES_PATH_CONF 路径下创建一个名为 unicast_hosts.txt 的文件,采用如下描述的格式。每当对 unicast_hosts.txt 文件进行更改时,Elasticsearch 会获取到这些新的更改,并且新的主机列表将会被使用。

请注意,基于文件的发现插件会扩充 elasticsearch.yml 中的单播主机列表:如果在 discovery.seed_hosts 中有有效的种子地址,那么 Elasticsearch 会使用这些地址同时也会使用unicast_hosts.txt 中提供的那些地址。

“unicast_hosts.txt” 文件每行包含一个节点。每个节点由主机(主机名或 IP 地址)以及一个可选的传输端口号组成。如果指定了端口号,它必须紧跟在主机后面(在同一行中),用冒号分隔。如果未指定端口号,Elasticsearch 将隐式使用由 “transport.profiles.default.port” 给出的端口范围中的第一个端口,如果未设置 “transport.profiles.default.port”,则使用 “transport.port”。

例如,这是一个具有四个参与发现的节点的集群的 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 地址,并且如上文所述由 DNS 解析。IPv6 地址必须放在括号中,如果需要端口,则放在括号后面。

你也可以向这个文件添加注释。所有注释必须在以 “#” 开头的行上出现(即注释不能在一行的中间开始)。

其他的方式

EC2 hosts provider(EC2 主机提供程序):AWS 的 EC2 发现插件添加的一种主机提供程序,它使用 AWS API 来查找种子节点列表。

Azure Classic hosts provider(Azure Classic 主机提供程序):Azure Classic 发现插件添加的一种主机提供程序,它使用 Azure Classic API 查找种子节点列表。

Google Compute Engine hosts provider(Google Compute Engine 主机提供程序):GCE 发现插件添加的一种主机提供程序,它使用 GCE API 查找种子节点列表。

基于选举制的决策

选举通常发生在更新集群状态或者选出一个master来,由具备选举资格的节点来共同进行。尽管即使有些节点已经fail了,这项活动依然可以继续进行。Elasticsearch 通过考虑接收到响应时每个操作都已成功来实现这种稳健性,参与投票选举的节点是整个集群的一个子集。只用接收到部分节点的响应结果就能做出选举的好处是,即使有部分节点failed了,依然可以保持集群的顺利运转。

“quorums”(法定人数)需要被精心挑选,以便集群不会出现 “脑裂” 情况。在 “脑裂” 场景中,集群被分成两部分,使得每一部分都可能做出与另一部分不一致的决策。

Elasticsearch 允许你向正在运行的集群添加和移除有资格成为主节点的节点。在很多情况下,你可以根据需要简单地通过启动或停止节点来实现这一点。参见 “在你的集群中添加和移除节点”。

Elasticsearch 在节点增加或移除时,通过更新集群的投票来维持最佳的容错水平。投票是一组有资格成为主节点的节点集合,在做出选举新主节点或提交新集群状态等决策时,投票会被计数。只有在投票中超过一半的节点响应后才会做出决策。通常情况下,投票与集群中当前所有有资格成为主节点的节点集合相同,但在某些情况下可能会不同。

为了确保集群保持可用,你一定不能同时停止投票中一半或更多的节点。只要超过一半的投票节点可用,集群仍然可以正常工作。这意味着如果有三个或四个有资格成为主节点的节点,集群可以容忍其中一个不可用。如果有两个或更少有资格成为主节点的节点,它们必须全部保持可用。

这点类似于zk的工作模式,超过半数必须存活,如果有4个节点,最多允许一个节点当机(超过半数4/2=2,大于2为3,最少需要3个存活)。如果有3个节点,同样最多也只允许1个节点当机(3/2=1.5,最少需要2个存活)。如果只有2个节点,2/2=1,至少需要2台存活,集群失去了容错性。这就是为什么我们一般配置3台master资格的原因。

一个节点加入或离开集群后,当选的主节点必须发布一个集群状态更新,以调整投票使其匹配,这可能需要一小段时间才能完成。在从集群中移除更多节点之前,等待这个调整完成是很重要的。

选主

Elasticsearch 使用选举过程来确定一个被选举出的主节点,无论是在启动时还是在现有的被选举出的主节点出现故障时。任何有资格成为主节点的节点都可以启动选举,通常情况下,第一个发起的选举会成功。选举通常只有在两个节点恰好同时开始选举时才会失败,所以在每个节点上随机安排选举以降低这种情况发生的概率。节点会重试选举直到选出一个主节点,在失败时进行回退,这样最终选举会成功(具有极高的概率)。主节点选举的安排由主节点选举设置控制。

集群的滚动重启、维护和迁移

许多集群维护任务涉及暂时关闭一个或多个节点,然后再重新启动它们。默认情况下,如果 Elasticsearch 的一个有资格成为主节点的节点离线(例如在滚动升级期间),Elasticsearch 可以保持可用状态。此外,如果多个节点停止然后再次启动,那么它将自动恢复,例如在全集群重新启动期间。在这些情况下,由于主节点集没有永久改变,所以无需对这里描述的 API 采取任何进一步的操作。

投票配置(姑且这么)

每个 Elasticsearch 集群都有一个投票配置,这是一组有资格成为主节点的节点集合。在做出诸如选举新的主节点或提交新的集群状态等决策时,只有在投票配置中的大多数(超过一半)节点做出响应后,才会做出决策生效。

通常情况下,投票配置与当前集群中所有有主节点资格的节点集合相同。然而,在某些情况下,它们可能会不同。

为确保集群保持可用状态,绝不能同时停止投票配置中一半或更多的节点。只要超过一半的投票节点可用,集群就能正常工作。例如,如果有三个或四个有资格成为主节点的节点,集群可以容忍一个不可用的节点。如果有两个或更少有资格成为主节点的节点,那么它们必须全部保持可用状态。

在一个节点加入或离开集群后,Elasticsearch 会通过自动对投票配置进行相应的更改来做出反应,以确保集群尽可能具有弹性。在从集群中移除更多节点之前,等待这个调整完成是很重要的。更多信息,请参阅 “在你的集群中添加和移除节点”。

当前的投票配置存储在集群状态中,所以你可以如下检查它当前的内容。

GET /_cluster/state?filter_path=metadata.cluster_coordination.last_committed_config

当前的投票配置不一定与集群中所有可用的主节点候选节点集合相同。改变投票配置需要进行投票,所以当节点加入或离开集群时,调整配置需要一些时间。此外,在某些情况下,最具弹性的配置可能包括不可用的节点,或者不包括一些可用的节点。在这些情况下,投票配置与集群中可用的主节点候选节点集合不同。

较大的投票配置通常更具弹性,因此 Elasticsearch 通常倾向于在符合主节点条件的节点加入集群后将其添加到投票配置中。类似地,如果投票配置中的一个节点离开集群,并且集群中还有另一个符合主节点条件但不在投票配置中的节点,那么最好将这两个节点进行交换。这样投票配置的大小保持不变,但弹性增加了。在节点离开集群后自动从投票配置中删除节点并非那么简单直接。不同的策略有不同的优点和缺点,所以正确的选择取决于集群的使用方式。你可以通过使用 cluster.auto_shrink_voting_configuration 设置来控制投票配置是否自动收缩。注意。

如果集群的 “auto_shrink_voting_configuration” 被设置为 true(这是默认值且是推荐值),并且在集群中至少有三个有资格成为主节点的节点,那么只要除了一个有资格成为主节点的节点之外的所有节点都是健康的,Elasticsearch 就仍然能够处理集群状态更新。

在某些情况下,Elasticsearch 可能会容忍多个节点的丢失,但这在所有的故障序列下都不能保证。如果 cluster.auto_shrink_voting_configuration 设置为 false,必须手动从投票配置中删除已离开的节点。无论如何配置,Elasticsearch 都不会遭受 “脑裂” 不一致性问题。cluster.auto_shrink_voting_configuration 集群的自动收缩投票配置设置仅在其一些节点发生故障时以及当节点加入和离开集群时必须执行的管理任务中影响其可用性。

偶数个集群投票配置

在一个集群中,通常应该有奇数个有资格成为主节点的节点。如果是偶数个,Elasticsearch 会将其中一个节点排除在投票配置之外,以确保投票配置的规模为奇数。这种排除不会降低集群的容错能力。实际上,它还会略微提高容错能力:如果集群遭受网络分区,将其分成两个大小相等的部分,那么其中一部分将包含投票配置的大多数,并且能够继续运行。如果计算所有有资格成为主节点的节点的投票,那么任何一方都不会包含严格多数的节点,因此集群将无法取得任何进展。

让我们举个例子来理解这个事情。如果集群有4个节点,按照半数原则,至少需要超过4/2=2个节点,也就是3个节点才能保证正常的选举。那么也就是可以容忍挂掉1个节点。但是如果4个节点发生了脑裂现象,没一半分到了2台机器,解决就是没有任何一半能够拥有3台机器,导致整个集群无法完成选举。

而如果是3台的情况,按照半数原则 3/2=1.5至少需要2台机器存活才能保证选举,那么他最多也是能容忍1台挂掉,跟4台的效果是一模一样的。但是当此时发生了网络分裂,那么一半是2台,一半是1台,拥有2台的那部分网络依然能够选举,因为这里还有2台机器。

设置最初的投票配置

当一个全新的集群首次启动时,它必须选出第一个主节点。为了进行这次选举,它需要知道那些有资格成为主节点的节点集合,这些节点的投票应该被计算在内。这个初始的投票配置被称为引导配置,并在集群引导过程中进行设置。

启动程序配置必须配置哪些节点可以参与选举,仅仅配置一个数量是远远不够的。同时你这个启动配置必须来自外部集群,他自己是没办法决定这个配置的。

如果启动配置不正确,会导致集群启动后分裂成两个独立集群,这可能会导致数据丢失。

在一个包含三个节点的集群环境中,所谓的 “多数”(通常用于判定集群达成一致等情况的一个概念)指的是两个节点。正常情况下,最先互相发现彼此的两个节点会先形成一个集群,然后过不了多久,第三个节点就会加入到这个已经形成的集群当中来。

不过,现在设想一下,原本应该启动三个节点的,却错误地启动了四个节点。在这样的状况下,由于节点数量足够多,就有可能形成两个相互独立、互不关联的集群了,而不是按预期形成一个完整的集群。

当然了,如果每个节点都是通过人工手动去启动的话,出现启动过多节点这种情况的概率是比较低的。因为人工操作时,人们一般会清楚应该启动几个节点,不太容易出现数量上的差错。但是,如果使用的是自动化的编排工具(比如一些用于管理、协调多个节点启动和集群组建等操作的软件工具)来启动节点的话,那陷入上述那种启动了错误数量节点,进而形成两个独立集群这种糟糕情况的可能性就比较大了。特别是当这个自动化编排工具对于像网络分区(也就是网络出现部分隔离、断开等故障情况)这类故障缺乏应对能力、不够健壮的时候,就更容易出现这样的问题了。

初始法定人数仅在整个集群首次启动时才需要。加入已建立集群的新节点可以从当选的主节点安全地获取它们所需的所有信息。先前属于集群一部分的节点在重新启动时将把所需的所有信息存储到磁盘中。