Elasticsearch 技术分析(六): 自动发现机制 - Zen Discoveryedit
1|0发现方式
Zen discovery是内建的、默认的、用于Elasticsearch的发现模块。它提供了单播和基于文件的发现,可以通过插件扩展到支持云环境和其他形式的发现。
Zen Discovery 是与其他模块集成的,例如,节点之间的所有通信都使用 transport 模块完成。某个节点通过 发现机制 找到其他节点是使用 Ping 的方式实现的。
Zen Discovery 使用种子节点(seed nodes)列表来开始发现过程。在启动时,或者在选举新主节点的时候,Elasticsearch 会尝试连接到其列表中的每个种子节点,并与他们进行类似'闲聊'的对话,以查找其他节点并构建集群的完整成员图。
默认情况下,有两种方法可用于配置种子节点列表:单播和基于文件。建议种子节点列表主要由集群中那些 Master-eligible 的节点组成。
Master-eligible:node.master设置为 true(默认)的节点,使其有资格被选为控制集群的主节点。
1|1单播
单播发现 配置静态主机列表以用作种子节点。 可以将这些主机指定为 主机名 或 IP地址。 指定为主机名的主机在每轮 ping 操作期间解析为 IP 地址。 请注意,如果您处于 DNS 解析随时间变化的环境中,则可能需要调整 JVM安全设置。
可以在 elasticsearch.yml 配置文件中使用discovery.zen.ping.unicast.hosts静态设置设置主机列表。
discovery.zen.ping.unicast.hosts:["host1", "host2"]
具体的值是一个主机数组或逗号分隔的字符串。每个值应采用host:port或host的形式(其中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)。
1|2基于文件
除了静态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.510.10.10.6:930510.10.10.5:10005#anIPv6address[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9301
允许使用主机名而不是IP地址(类似于 discovery.zen.ping.unicast.hosts)。必须在括号中指定IPv6地址,并在括号后面添加端口。
也可以为此文件添加注释,所有注释必须在每行的开头显示_#_(即注释不能在一行中间开始)。
2|0选举主节点
作为 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.master为false的节点不参加主节点的选举,同时选票也不包含这种节点。
通过设置node.master为false,可以将节点设置为非备选主节点,永远没有机会成为主节点。
discovery.zen.minimum_master_nodes设置了最少有多少个备选主节点参加选举,同时也设置了一个主节点需要控制最少多少个备选主节点才能继续保持主节点身份。如果控制的备选主节点少于discovery.zen.minimum_master_nodes个,那么当前主节点下台,重新开始选举。
discovery.zen.minimum_master_nodes必须设置一个恰当的备选主节点值(quonum,一般设置 为备选主节点数/2+1),尽量避免只有两个备选主节点,因为两个备选主节点quonum应该为2,那么如果一个节点出现问题,另一个节点的同意人数最多只能为1,永远也不能选举出新的主节点,这时就发生了脑裂现象。
3|0集群故障检测
有两个故障检测进程在集群的生命周期中一直运行。一个是主节点的,ping集群中所有的其他节点,检查他们是否活着。另一种是每个节点都ping主节点,确认主节点是否仍在运行或者是否需要重新启动选举程序。
使用discovery.zen.fd前缀设置来控制故障检测过程,配置如下:
配置描述
discovery.zen.fd.ping_interval节点多久ping一次,默认1s
discovery.zen.fd.ping_timeout等待响应时间,默认30s
discovery.zen.fd.ping_retries失败或超时后重试的次数,默认3
4|0集群状态更新
主节点是唯一一个能够更新集群状态的节点。主节点一次处理一个群集状态更新,应用所需的更改并将更新的群集状态发布到群集中的所有其他节点。当其他节点接收到状态时,先确认收到消息,但是不应用最新状态。如果主节点在规定时间(discovery.zen.commit_timeout ,默认30s)内没有收到大多数节点(discovery.zen.minimum_master_nodes)的确认,集群状态更新不被通过。
一旦足够的节点响应了更新的消息,新的集群状态(cluster state)被提交并且会发送一条消息给所有的节点。这些节点开始在内部应用新的集群状态。在继续处理队列中的下一个更新之前,主节点等待所有节点响应,直到超时(discovery.zen.publish_timeout,默认设置为30秒)。上述两个超时设置都可以通过集群更新设置api动态更改。
5|0No master block
对于一个可以正常充分运作的集群来说,必须拥有一个活着的主节点和正常数量(discovery.zen.minimum_master_nodes个)活跃的备选主节点。discovery.zen.no_master_block设置了没有主节点时限制的操作。它又两个可选参数
all:所有操作均不可做,读写、包括集群状态的读写api,例如获得索引配置(index settings),putMapping,和集群状态(cluster state)api
write:默认为write,写操作被拒绝执行,基于最后一次已知的正常的集群状态可读,这也许会读取到已过时的数据。
discovery.zen.no_master_block,对于节点相关的基本api,这个参数是无效的,如集群统计信息(cluster stats),节点信息(node info),节点统计信息(node stats)。对这些api的请求不会被阻止,并且可以在任何可用节点上运行。