原英文版地址: https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-cluster.html, 原文档版权归 www.elastic.co 所有
本地英文版地址: ../en/modules-cluster.html

集群级分片分配和路由设置 (Cluster-level shard allocation and routing settings)

分片分配 (shard allocation) 是分配分片到节点的过程。 这可能在 初始化恢复(initial recovery)、副本分配(replica allocation)、再平衡(rebalancing),或 添加/删除节点时发生。

主节点的主要角色之一是决定将哪些分片分配到哪个节点,以及何时在节点之间移动分片,以再平衡集群。

有许多可用于控制分片分配过程的设置:

除此之外,还有其他一些其他的集群级设置

这些设置都是动态的 (dynamic),而且可以使用 集群更新设置 API 在运行中的集群上更新。

集群级(cluster-level)分片分配设置

以下 动态的 (dynamic) 设置可以用来控制分片分配和恢复:

cluster.routing.allocation.enable

启用或禁用对特定类型的分片的分配:

  • all - (默认) 允许为所有类型的分片分配分片。
  • primaries - 仅允许为主分片分配分片。
  • new_primaries - 仅允许为新索引的主分片分配分片。
  • none - 任何索引都不允许任何类型的分片。

这个设置不影响重启一个节点时本地主分片的恢复。 具有未分配主分片副本的节点重启后,如果其分配 id 与集群状态下的活动的分配 id 之一匹配,则将立即恢复该主分片。

cluster.routing.allocation.node_concurrent_incoming_recoveries
一个节点上允许并发的 传入分片(incoming shard) 恢复的个数。 传入恢复(incoming recovery) 是在节点上分配目标分片(很可能是副本,除非分片被重新定位)的恢复。默认为 2
cluster.routing.allocation.node_concurrent_outgoing_recoveries
一个节点上允许并发的 传出分片(outgoing shard) 恢复的个数。 传出恢复(outgoing recovery)是在节点上分配源分片(很可能是主分片,除非分片被重新定位)的恢复。默认为 2
cluster.routing.allocation.node_concurrent_recoveries
同时设置cluster.routing.allocation.node_concurrent_incoming_recoveriescluster.routing.allocation.node_concurrent_outgoing_recoveries的快捷方式。
cluster.routing.allocation.node_initial_primaries_recoveries
虽然副本的恢复发生在网络上,但是节点重启后恢复未分配的主节点时使用的是本地磁盘中的数据。 这些恢复应该很快,这样就可以在同一个节点上并行地进行更多的初始主分片恢复。默认为4
cluster.routing.allocation.same_shard.host
允许根据主机名和主机地址执行检查,以防止在单个主机上分配同一分片的多个实例。 默认为 false,即不执行检查。 这个设置仅适用于在同一台机器上启动了多个节点。

分片再平衡设置

以下 动态的 (dynamic) 设置可以用于控制跨集群的分片的再平衡:

cluster.routing.rebalance.enable

启用或禁用对特定类型的分片的再平衡:

  • all - (默认) 允许各种分片的分片再平衡
  • primaries - 仅允许主分片的分片再平衡
  • replicas - 仅允许副本分片的分片再平衡
  • none - 任何索引都不允许任何类型的分片平衡。
cluster.routing.allocation.allow_rebalance

指定什么时候允许分片再平衡:

  • always - 始终允许再平衡
  • indices_primaries_active - 仅当集群中的所有主分片已分配(处于激活状态)
  • indices_all_active - (默认) 仅当集群中的所有分片(主和副本)已分配(处于激活状态)
cluster.routing.allocation.cluster_concurrent_rebalance
允许控制集群范围内允许多少个并发的分片再平衡。默认为 2。 请注意,此设置仅控制由于集群不平衡而导致的并发分片重定位的数量。 此设置不会限制由于 分配过滤 (allocation filtering)强制感知 (forced awareness) 而导致的分片重新定位。
更多阅读参考: ElasticSearch集群shard均衡策略 (v6.x, 来自知乎)

分片平衡启发式设置 (shard balancing heuristics settings)

下面的设置一起用于确定每个分片的放置位置。 当任何允许的再平衡操作都不能使任何节点的权重(weight) 与 任何其他节点的权重 之间的密切性比 balance.threshold 更接近时,集群就是平衡的(原文: The cluster is balanced when no allowed rebalancing operation can bring the weight of any node closer to the weight of any other node by more than the balance.threshold.)

cluster.routing.allocation.balance.shard
定义节点上分配的分片总数的权重(weight)因子(浮点型)。默认为 0.45f。 提高这个值会增加集群中所有节点之间分片数量均衡的趋势。
cluster.routing.allocation.balance.index
定义在特定节点上分配的每个索引的分片数的权重因子(浮点型)。默认为 0.55f。 提高这个值会使集群中所有节点的每个索引的分片数量更加趋于均衡。
cluster.routing.allocation.balance.threshold
应该执行的最小优化值(非负浮点数)。默认为 1.0f。 提高该值将导致集群在优化分片平衡方面不那么积极。

不管平衡算法的结果如何,强制感知(forced awareness) 或 分配过滤(allocation filtering) 可能会导致不允许重新平衡。

基于磁盘的分片分配设置 (Disk-based shard allocation settings)

Elasticsearch 会考量节点上的可用磁盘空间,然后决定是向该节点分配新的分片,还是主动将分片从该节点移走。

以下是可以在配置文件 elasticsearch.yml 中配置的设置,或者使用 集群更新设置 API 在实时集群上动态更新的设置:

cluster.routing.allocation.disk.threshold_enabled
默认为 true。设置为 false 将禁用磁盘分配决策器。
cluster.routing.allocation.disk.watermark.low
控制磁盘使用的 低 水位线(watermark)。默认为 85%,表示 Elasticsearch 不会给磁盘使用率超过 85% 的节点分配分片。 也可以将其设置为绝对字节值(如500mb),以防止Elasticsearch 在可用空间少于指定的值时分配分片。 该设置对新创建的索引的主分片没有影响,但会阻止它们的副本的分配。
cluster.routing.allocation.disk.watermark.high
控制磁盘使用的 高 水位线(watermark)。默认为 90%,表示 Elasticsearch 将尝试从磁盘使用率超过 90% 的节点上移走分片。 也可以将其设置为绝对字节值(类似于低水位线),以便在节点的可用空间少于指定的值时将分片从该节点移走并重新定位。 这个设置影响所有分片的分配,无论之前是否已分配。
cluster.routing.allocation.disk.watermark.flood_stage

控制洪水位水位线,默认为 95%。 Elasticsearch 在每个索引上强制执行一个只读索引块(index.blocks.read_only_allow_delete),该索引块在节点上分配了一个或多个分片,并且至少有一个磁盘超过了洪水位。 此设置是防止节点磁盘空间耗尽的最后手段。 当磁盘使用率低于高水位线时,索引块会自动释放。

在这些设置中,不能混合使用百分比值和字节值。 要么所有值都设置为百分比值,要么所有值都设置为字节值。 这样做是为了让 Elasticsearch 可以验证设置在内部是一致的,确保低磁盘阈值小于高磁盘阈值,高磁盘阈值小于洪水位阈值。

重置索引twitter上的只读索引块的示例:

PUT /twitter/_settings
{
  "index.blocks.read_only_allow_delete": null
}
cluster.info.update.interval
Elasticsearch 应该多久检查一次集群中每个节点的磁盘使用情况。默认 30s
cluster.routing.allocation.disk.include_relocations
[7.5.0] 在 7.5.0 版本中废弃。未来的版本将始终考虑 重定位(relocations)。 默认为 true,这意味着在计算节点的磁盘使用量时,Elasticsearch 会将当前重定位到目标节点的分片考虑在内。 然而,考虑重定位分片的大小,可能意味着节点的磁盘使用量被错误地估计为偏高,因为重定位可能完成了90%,而最近检索的磁盘使用量会包括重定位分片的总大小以及正在运行的重定位已经使用的空间。

百分比值是指已用磁盘空间,而字节值是指可用磁盘空间。 这可能会令人困惑,因为它颠倒了高和低的含义。 例如,将低水位设置为 10gb,高水位设置为 5gb 是有意义的,但反过来则不行。

下面的例子, 将低水位线更新为至少 100gb 字节可用空间,高水位线更新为至少 50gb 字节可用空间,洪水位水位线更新为 10gb 字节可用空间,并每分钟更新一次集群的信息:

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "100gb",
    "cluster.routing.allocation.disk.watermark.high": "50gb",
    "cluster.routing.allocation.disk.watermark.flood_stage": "10gb",
    "cluster.info.update.interval": "1m"
  }
}

分片分配感知 (shard allocation awareness)

您可以使用自定义节点属性作为感知属性(awareness attributes),使Elasticsearch 在分配分片时考虑物理硬件配置。 如果 Elasticsearch 知道哪些节点在同一个物理服务器上、在同一个机架上,或者在同一个区域中,它可以分发主分片及其副本分片,以最大限度地降低故障时丢失所有分片副本的风险。

当使用cluster.routing.allocation.awareness.attributes设置启用分片分配感知时,分片仅分配给具有为指定感知属性设置的值的节点。 如果使用了多个感知属性,Elasticsearch 在分配分片时会单独考虑每个属性。

分配感知设置可以在elasticsearch.yml中配置,也可以使用集群更新设置 API动态更新。

默认情况下,Elasticsearch 使用 自适应副本选择(adaptive replica selection) 来路由搜索或 GET 请求。 然而,由于分配感知属性的存在,Elasticsearch 将更倾向于使用相同位置的分片(具有相同的感知属性值)来处理这些请求。 要禁用此行为,可以在集群的每个节点上指定系统属性export ES_JAVA_OPTS="$ES_JAVA_OPTS -Des.search.ignore_awareness_attributes=true"

属性值的数量决定了在每个位置分配多少个分片的副本。 如果每个位置的节点数量不均衡,且有大量副本,则副本分片可能会保持未分配状态。

启用分片分配感知

要启用分片分配感知:

  1. 使用自定义节点属性指定每个节点的位置。 例如,如果希望 Elasticsearch 将分片分布在不同的机架上,可以在每个节点的配置文件 elasticsearch.yml 中设置一个名为rack_id (机架id)的感知属性。

    node.attr.rack_id: rack_one

    还可以在启动节点时设置自定义属性:

    `./bin/elasticsearch -Enode.attr.rack_id=rack_one`
  2. 通过在每个符合主节点条件的节点的配置文件 elasticsearch.yml 中设置cluster.routing.allocation.awareness.attributes,告诉 Elasticsearch 在分配分片时考虑一个或多个感知属性。

    cluster.routing.allocation.awareness.attributes: rack_id 

    以逗号分隔的列表形式指定多个属性。

    还可以使用 集群更新设置 API来设置或更新集群的感知属性。

在此示例配置中,如果启动两个节点且将 node.attr.rack_id 设置为 rack_one (机架1),并创建一个包含 5 个主分片和每个主分片 1 个副本的索引,则所有主分片和副本都将在这两个节点之间分配。

如果在 node.attr.rack_id 设置为 rack_two(机架2) 的情况下添加两个节点,Elasticsearch 会将分片移动到新节点,确保(如果可能的话)没有同一个分片的两个副本都在同一个机架中。

如果 rack_two(机架2) 出现故障并关闭了它的两个节点,默认情况下,Elasticsearch 会将丢失的分片副本分配给 rack_one (机架1) 上的节点。 为了防止在同一位置分配特定分片的多个副本,可以启用 强制感知 (forced awareness)

强制感知 (forced awareness)

默认情况下,如果一个位置失效,Elasticsearch 会将所有丢失的副本分片分配给其余位置。 虽然可能在所有的位置上都有足够的资源来承载主分片和副本分片,但是单个位置可能无法承载所有的分片。

为了防止单个位置在发生故障时超负荷,可以设置 cluster.routing.allocation.awareness.force,以便在其他位置的节点可用之前不会分配副本。

例如,如果有一个名为zone的感知属性,并在zone1zone2中配置节点,可以使用强制感知来防止 Elasticearch 在只有一个区域可用时分配副本:

cluster.routing.allocation.awareness.attributes: zone
cluster.routing.allocation.awareness.force.zone.values: zone1,zone2 

为感知属性指定所有可能的值。

使用上面这个示例的配置,如果启动两个节点,并将node.attr.zone 设置为 zone1,并创建一个包含 5 个分片和 1 个副本的索引,则 Elasticsearch 将创建索引并分配 5 个主分片,但不分配副本。副本只有在 node.attr.zone 值为zone2 的节点可用时才会分配。

集群级分片分配过滤 (cluster-level shard allocation filtering)

可以使用集群级别的分片分配过滤器来控制 Elasticearch 从任何索引中分配分片的位置。 这些集群范围的过滤器与 每个索引的分配过滤分配感知 一起应用。

分片分配过滤可以基于自定义的节点属性,或者内置的_name, _host_ip, _publish_ip, _ip, _host_id属性。

cluster.routing.allocation 是动态的,允许将活动索引从一组节点移动到另一组节点。 只有在不破坏另一个路由约束的情况下,才能重新定位分片,例如永远不要在同一节点上分配主分片和副本分片。

集群级分片分配过滤最常见的使用场景是当你想 关闭(decommission) 一个节点时。 若要在关闭节点之前将分片移出节点,可以创建一个过滤器,根据节点的 IP 地址将其排除在外:

PUT _cluster/settings
{
  "transient" : {
    "cluster.routing.allocation.exclude._ip" : "10.0.0.1"
  }
}

集群路由设置

cluster.routing.allocation.include.{attribute}
将分片分配给 {attribute} 至少有一个逗号分隔值的节点。
cluster.routing.allocation.require.{attribute}
仅将分片分配给 {attribute} 具有所有逗号分隔值的节点。
cluster.routing.allocation.exclude.{attribute}
不要将分片分配给其{attribute}具有任何逗号分隔值的节点。

集群分配设置支持以下几个内置的属性:

_name

按节点名匹配节点

_host_ip

通过主机IP地址匹配节点(IP与主机名关联)

_publish_ip

通过外部IP地址匹配节点

_ip

匹配 _host_ip_publish_ip

_host

按主机名匹配节点

_id

按节点id匹配节点

指定属性的值时可以使用通配符,例如:

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": "192.168.2.*"
  }
}

其他集群设置

元数据 (metadata)

可以使用以下动态(dynamic)设置将整个集群设置为只读:

cluster.blocks.read_only
使整个集群只读(索引不接受写操作),不允许修改元数据(创建或删除索引)。
cluster.blocks.read_only_allow_delete
cluster.blocks.read_only相同,但允许删除索引以释放资源。

不要依赖此设置来阻止对集群的更改。 任何有权访问 集群更新设置 API 的用户都可以让集群再次可读写。

集群分片限制

基于集群中的节点数量,集群中的分片数量有一个软限制。这是为了防止可能无意中破坏集群稳定性的操作。

该限制旨在作为一种保护措施,而非大小建议。 集群可以安全支持的分片的确切数量取决于硬件配置和工作负载,但几乎所有情况下都应保持在该限制以下,因为默认限制设置得相当高。

如果某项操作(如创建新索引、恢复索引的快照或打开关闭的索引)会导致集群中的分片数量超过此限制,则该操作将失败,并给出错误,指示分片限制。

如果集群由于节点成员的变化或设置的变化已经超过限制,则所有创建或打开索引的操作都将失败,直到增加限制(如下所述),或者关闭删除一些索引以使分片数低于这个限制。

副本数量计入此限制,但关闭的索引不计入。 包含 5 个主分片和 2 个副本的索引将被计为 15 个分片。 任何关闭的索引都计为 0,不管它包含多少分片和副本。

该限制默认为每个数据节点 1,000 个分片,可以使用以下属性进行动态调整:

cluster.max_shards_per_node
控制集群中每个数据节点允许的分片数量。

例如,使用默认设置的 3 个节点的集群将允许所有打开的索引中共有 3,000 个分片。 如果将上述设置更改为 500,那么集群将总共允许 1,500 个分片。

如果集群中没有数据节点,将不会强制实施该限制。如果在数据节点之前设置专用的主节点,将允许在集群创建期间创建索引。

用户定义的集群元数据 (user-defined cluster metadata)

可以使用 集群设置(Cluster Settings) API 存储和检索用户定义的元数据。 这可以用来存储关于集群的任意、不经常改变的数据,而不需要创建索引来存储这些数据。 可以使用以 cluster.metadata.为前缀的任何键来存储该数据。 例如,要在键 cluster.metadata.administrator下存储集群管理员的 email 地址,请发送以下请求:

PUT /_cluster/settings
{
  "persistent": {
    "cluster.metadata.administrator": "sysadmin@example.com"
  }
}

用户定义的集群元数据不要用于存储敏感或机密信息。 存储在用户定义的集群元数据中的任何信息都可以被任何能够访问 集群获取设置 API 的人查看,并被记录在 Elasticsearch 日志中。

索引墓碑 (index tombstones)

集群状态维护 索引墓碑 (index tombstones),以明确表示已被删除的索引。 在集群状态下维护的 墓碑 数量由下面这个不能动态更新的属性控制:

cluster.indices.tombstones.size
索引墓碑可防止发生删除时不属于集群的节点加入集群并重新导入索引,就好像从未执行过删除一样 (原文: Index tombstones prevent nodes that are not part of the cluster when a delete occurs from joining the cluster and reimporting the index as though the delete was never issued.)。 为了防止集群状态变得过大,只保留最后的cluster.indices.tombstones.size 个删除,默认为 500。 如果你期望节点不在集群中,并且错过的删除次数超过500次,则可以增加该值(原文: You can increase it if you expect nodes to be absent from the cluster and miss more than 500 deletes.)。 我们认为这是罕见的,因此使用这个默认值。 墓碑不占太多空间,但我们也觉得 50,000 这样的数字可能太大了。

日志 (logger)

控制记录的设置可以用 logger. 前缀动态更新。 例如,要提高 indices.recovery 模块的日志记录级别到 DEBUG,请发送以下请求:

PUT /_cluster/settings
{
  "transient": {
    "logger.org.elasticsearch.indices.recovery": "DEBUG"
  }
}

持久任务分配 (persistent tasks allocation)

插件可以创建一种叫做持久任务 (persistent tasks)的任务。 这些任务通常是长期存在的任务,存储在集群状态中,允许在整个集群重新启动后重新启动这些任务。

每次创建持久任务时,主节点负责将任务分配给集群中的一个节点,然后被分配的节点将接受该任务并在本地执行。 将持久任务分配给节点的过程由下面几个可以动态更新的属性控制:

cluster.persistent_tasks.allocation.enable

启用或禁用持久任务的分配:

  • all - (默认) 允许给节点分配持久任务
  • none - 任何类型的持久任务都不允许分配

此设置不影响已经在执行的持久任务。 只有新创建的持久任务或必须重新分配的任务(例如,节点离开集群后)才受此设置的影响。

cluster.persistent_tasks.allocation.recheck_interval
当集群状态发生重大变化时,主节点将自动检查是否需要分配持久任务。 但是,可能有其他因素,如内存使用率,会影响持久任务是否可以分配给节点,但又不会导致集群状态发生变化。 此设置控制为响应这些因素而执行分配检查的频率。 默认为 30 秒。允许的最小值为 10 秒。