集群级分片分配和路由设置编辑

分片分配是将分片分配给节点的过程。这可能发生在初始恢复、副本分配、重新平衡或添加或删除节点时。

主节点的主要作用之一是决定将哪些分片分配给哪些节点,以及何时在节点之间移动分片以重新平衡集群。

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

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

集群级分片分配设置编辑

您可以使用以下设置来控制分片分配和恢复

cluster.routing.allocation.enable

(动态) 为特定类型的分片启用或禁用分配

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

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

cluster.routing.allocation.same_shard.host
(动态) 如果为 true,则禁止将分片的多个副本分配给同一主机(即具有相同网络地址)上的不同节点。默认为 false,这意味着分片的副本有时可能会分配给同一主机上的节点。此设置仅在您在每台主机上运行多个节点时才相关。
cluster.routing.allocation.node_concurrent_incoming_recoveries
(动态) 允许在节点上同时进行多少个传入分片恢复。传入恢复是指目标分片(除非分片正在重新定位,否则很可能是副本)分配在节点上的恢复。默认为 2。增加此设置可能会导致分片移动对集群中的其他活动产生性能影响,但可能不会使分片移动明显更快地完成。我们不建议将此设置调整为默认值 2
cluster.routing.allocation.node_concurrent_outgoing_recoveries
(动态) 允许在节点上同时进行多少个传出分片恢复。传出恢复是指源分片(除非分片正在重新定位,否则很可能是主分片)分配在节点上的恢复。默认为 2。增加此设置可能会导致分片移动对集群中的其他活动产生性能影响,但可能不会使分片移动明显更快地完成。我们不建议将此设置调整为默认值 2
cluster.routing.allocation.node_concurrent_recoveries
(动态) 设置 cluster.routing.allocation.node_concurrent_incoming_recoveriescluster.routing.allocation.node_concurrent_outgoing_recoveries 的快捷方式。仅当未配置更具体的设置时,此设置的值才会生效。默认为 2。增加此设置可能会导致分片移动对集群中的其他活动产生性能影响,但可能不会使分片移动明显更快地完成。我们不建议将此设置调整为默认值 2
cluster.routing.allocation.node_initial_primaries_recoveries
(动态) 虽然副本的恢复是通过网络进行的,但在节点重启后未分配主分片的恢复使用的是本地磁盘上的数据。这些应该很快,因此每个节点上可以并行进行更多初始主分片恢复。默认为 4。增加此设置可能会导致分片恢复对集群中的其他活动产生性能影响,但可能不会使分片恢复明显更快地完成。我们不建议将此设置调整为默认值 4

分片重新平衡设置编辑

当集群在每个节点上具有相同数量的分片,所有节点需要相等的资源,并且没有任何索引的分片集中在任何节点上时,该集群就是平衡的。Elasticsearch 运行一个称为重新平衡的自动过程,该过程在集群中的节点之间移动分片以改善其平衡。重新平衡遵循所有其他分片分配规则,例如分配过滤强制感知,这可能会阻止其完全平衡集群。在这种情况下,重新平衡会努力在您配置的规则内实现尽可能平衡的集群。如果您正在使用数据层,则 Elasticsearch 会自动应用分配过滤规则将每个分片放置在适当的层内。这些规则意味着平衡器在每一层内独立工作。

您可以使用以下设置来控制分片在集群中的重新平衡

cluster.routing.allocation.allow_rebalance

(动态) 指定何时允许分片重新平衡

  • always - 始终允许重新平衡。
  • indices_primaries_active - 仅当集群中的所有主分片都已分配时。
  • indices_all_active - (默认) 仅当集群中的所有分片(主分片和副本)都已分配时。
cluster.routing.rebalance.enable

(动态) 为特定类型的分片启用或禁用重新平衡

  • all - (默认) 允许为所有类型的分片进行分片平衡。
  • primaries - 仅允许为主分片进行分片平衡。
  • replicas - 仅允许为副本分片进行分片平衡。
  • none - 不允许为任何索引进行任何类型的分片平衡。

重新平衡对于确保集群在中断后返回到健康且完全弹性的状态非常重要。如果您调整此设置,请记住尽快将其设置回 all

cluster.routing.allocation.cluster_concurrent_rebalance
(动态) 定义整个集群中允许的并发分片重新平衡数。默认为 2。请注意,此设置仅控制由于集群不平衡导致的并发分片重新定位的数量。此设置不限制由于分配过滤强制感知导致的分片重新定位。增加此设置可能会导致集群使用额外的资源在节点之间移动分片,因此我们通常不建议将此设置调整为默认值 2
cluster.routing.allocation.type

选择用于计算集群平衡的算法。默认为 desired_balance,它选择期望平衡分配器。此分配器运行一个后台任务,该任务计算集群中分片的期望平衡。此后台任务完成后,Elasticsearch 会将分片移动到其期望的位置。

[8.8] 在 8.8 中已弃用。balanced 分配器类型已弃用,不再推荐 也可以设置为 balanced 以选择旧版平衡分配器。此分配器是 8.6.0 之前版本的 Elasticsearch 中的默认分配器。它在前台运行,阻止主节点并行执行其他工作。它的工作原理是选择少量可以立即改善集群平衡的分片移动,当这些分片移动完成后,它会再次运行并选择另外几个分片进行移动。由于此分配器仅根据集群的当前状态做出决策,因此在平衡集群时,它有时会多次移动一个分片。

分片平衡启发式设置编辑

重新平衡的工作原理是根据每个节点的分片分配情况计算其权重,然后在节点之间移动分片以减少较重节点的权重并增加较轻节点的权重。当没有任何可能的分片移动可以使任何节点的权重更接近任何其他节点的权重超过可配置阈值时,集群就平衡了。

节点的权重取决于它持有的分片数量,以及这些分片估计使用的总资源量,这些资源量用磁盘上的分片大小和支持写入分片的线程数量来表示。Elasticsearch 在数据流所属的分片由滚动创建时估计其资源使用情况。新分片的估计磁盘大小是数据流中其他分片的平均大小。新分片的估计写入负载是数据流中最近分片的实际写入负载的加权平均值。不属于数据流写入索引的分片的估计写入负载为零。

以下设置控制 Elasticsearch 如何将这些值组合成每个节点权重的总体度量。

cluster.routing.allocation.balance.threshold
(浮点数,动态)触发重新平衡分片移动的权重最小改进量。默认为 1.0f。提高此值将导致 Elasticsearch 更快地停止重新平衡分片,从而使集群处于更加不平衡的状态。
cluster.routing.allocation.balance.shard
(浮点数,动态)定义分配给每个节点的分片总数的权重因子。默认为 0.45f。提高此值会增加 Elasticsearch 在其他平衡变量之前均衡节点间分片总数的趋势。
cluster.routing.allocation.balance.index
(浮点数,动态)定义分配给每个节点的每个索引的分片数量的权重因子。默认为 0.55f。提高此值会增加 Elasticsearch 在其他平衡变量之前均衡节点间每个索引的分片数量的趋势。
cluster.routing.allocation.balance.disk_usage
(浮点数,动态)定义根据分片的预测磁盘大小(以字节为单位)来平衡分片的权重因子。默认为 2e-11f。提高此值会增加 Elasticsearch 在其他平衡变量之前均衡节点间总磁盘使用量的趋势。
cluster.routing.allocation.balance.write_load
(浮点数,动态)定义每个分片的写入负载的权重因子,以分片所需的估计索引线程数表示。默认为 10.0f。提高此值会增加 Elasticsearch 在其他平衡变量之前均衡节点间总写入负载的趋势。
  • 如果您有一个大型集群,则可能不需要始终将其保持在完全平衡的状态。对于集群来说,在某种程度上不平衡的状态下运行比执行实现完美平衡所需的所有分片移动更节省资源。如果是这样,请增加 cluster.routing.allocation.balance.threshold 的值以定义节点之间可接受的不平衡程度。例如,如果您的每个节点平均有 500 个分片,并且可以接受节点之间相差 5%(通常为 25 个分片),则将 cluster.routing.allocation.balance.threshold 设置为 25
  • 我们不建议调整启发式权重因子设置的值。默认值适用于所有合理的集群。尽管不同的值可能会在某些方面改善当前的平衡,但它们有可能在将来造成意外问题,或阻止其优雅地处理意外中断。
  • 无论平衡算法的结果如何,由于强制感知和分配过滤等分配规则,可能不允许重新平衡。使用 集群分配说明 API 来解释分片的当前分配。

基于磁盘的分片分配设置编辑

基于磁盘的分片分配器可确保所有节点都具有足够的磁盘空间,而无需执行不必要的分片移动。它根据称为“低水位线”和“高水位线”的一对阈值来分配分片。其主要目标是确保任何节点都不会超过高水位线,或者至少任何此类超额都只是暂时的。如果某个节点超过了高水位线,则 Elasticsearch 将通过将其某些分片移动到集群中的其他节点来解决此问题。

节点暂时超过高水位线是正常的。

分配器还尝试通过禁止将更多分片分配给超过低水位线的节点来使节点远离高水位线。重要的是,如果您的所有节点都超过了低水位线,则无法分配新的分片,并且 Elasticsearch 将无法在节点之间移动任何分片以使磁盘使用率低于高水位线。您必须确保您的集群总共有足够的磁盘空间,并且始终有一些节点低于低水位线。

由基于磁盘的分片分配器触发的分片移动还必须满足所有其他分片分配规则,例如 分配过滤强制感知。如果这些规则过于严格,则它们还会阻止控制节点磁盘使用率所需的分片移动。如果您正在使用 数据层,则 Elasticsearch 会自动配置分配过滤规则以将分片放置在适当的层中,这意味着基于磁盘的分片分配器在每个层中独立工作。

如果某个节点填充磁盘的速度快于 Elasticsearch 可以将分片移动到其他位置的速度,则存在磁盘完全填满的风险。为了防止这种情况发生,作为最后的手段,一旦磁盘使用率达到“泛滥阶段”水位线,Elasticsearch 将阻止写入受影响节点上具有分片的索引。它还将继续将分片移动到集群中的其他节点。当受影响节点上的磁盘使用率降至高水位线以下时,Elasticsearch 会自动删除写入块。请参阅 修复水位线错误 以解决持久性水位线错误。

集群中的节点使用非常不同数量的磁盘空间是正常的。集群的 平衡 取决于多种因素的组合,包括每个节点上的分片数量、这些分片所属的索引,以及每个分片在其磁盘大小和 CPU 使用率方面的资源需求。Elasticsearch 必须权衡所有这些因素,如果只关注其中一个因素,那么在考虑所有这些因素的组合时平衡的集群可能看起来并不平衡。

您可以使用以下设置来控制基于磁盘的分配

cluster.routing.allocation.disk.threshold_enabled
动态)默认为 true。设置为 false 以禁用磁盘分配决策器。禁用后,它还将删除任何现有的 index.blocks.read_only_allow_delete 索引块。
cluster.routing.allocation.disk.watermark.low logo cloud
动态)控制磁盘使用量的低水位线。它默认为 85%,这意味着 Elasticsearch 不会将分片分配给磁盘使用率超过 85% 的节点。它也可以设置为比率值,例如 0.85。它还可以设置为绝对字节值(如 500mb),以防止 Elasticsearch 在可用空间少于指定数量时分配分片。此设置对新创建索引的主分片没有影响,但会阻止分配其副本。
cluster.routing.allocation.disk.watermark.low.max_headroom
动态)控制低水位线的最大净空(以百分比/比率值表示)。当未显式设置 cluster.routing.allocation.disk.watermark.low 时,默认为 200GB。这会限制所需的可用空间量。
cluster.routing.allocation.disk.watermark.high logo cloud
动态)控制高水位线。它默认为 90%,这意味着 Elasticsearch 将尝试将分片从磁盘使用率超过 90% 的节点上移走。它也可以设置为比率值,例如 0.9。它还可以设置为绝对字节值(类似于低水位线),以便在节点的可用空间少于指定数量时将分片从该节点上移走。此设置会影响所有分片的分配,无论之前是否已分配。
cluster.routing.allocation.disk.watermark.high.max_headroom
动态)控制高水位线的最大净空(以百分比/比率值表示)。当未显式设置 cluster.routing.allocation.disk.watermark.high 时,默认为 150GB。这会限制所需的可用空间量。
cluster.routing.allocation.disk.watermark.enable_for_single_data_node
静态)在早期版本中,默认行为是在做出分配决策时忽略单个数据节点集群的磁盘水位线。此行为自 7.14 版起已弃用,并在 8.0 版中已删除。此设置现在唯一有效的值为 true。该设置将在未来版本中删除。
cluster.routing.allocation.disk.watermark.flood_stage logo cloud

动态)控制泛滥阶段水位线,默认为 95%。Elasticsearch 对在节点上分配了一个或多个分片并且至少有一个磁盘超过泛滥阶段的每个索引强制执行只读索引块 (index.blocks.read_only_allow_delete)。此设置是防止节点磁盘空间不足的最后手段。当磁盘利用率降至高水位线以下时,索引块会自动释放。与低水位线和高水位线值类似,它也可以设置为比率值(例如 0.95)或绝对字节值。

my-index-000001 索引上重置只读索引块的示例

response = client.indices.put_settings(
  index: 'my-index-000001',
  body: {
    'index.blocks.read_only_allow_delete' => nil
  }
)
puts response
PUT /my-index-000001/_settings
{
  "index.blocks.read_only_allow_delete": null
}
cluster.routing.allocation.disk.watermark.flood_stage.max_headroom
(动态) 控制溢出阶段水印的最大预留空间(以百分比/比率值表示)。当未明确设置 cluster.routing.allocation.disk.watermark.flood_stage 时,默认为 100GB。这限制了所需的可用空间量。

您不能在 cluster.routing.allocation.disk.watermark.lowcluster.routing.allocation.disk.watermark.highcluster.routing.allocation.disk.watermark.flood_stage 设置中混合使用百分比/比率值和字节值。所有值要么都设置为百分比/比率值,要么都设置为字节值。此强制要求是为了让 Elasticsearch 可以验证设置在内部是否一致,确保低磁盘阈值小于高磁盘阈值,并且高磁盘阈值小于溢出阶段阈值。对最大预留空间值执行类似的比较检查。

cluster.routing.allocation.disk.watermark.flood_stage.frozen logo cloud
(动态) 控制专用冻结节点的溢出阶段水印,默认为 95%。
cluster.routing.allocation.disk.watermark.flood_stage.frozen.max_headroom logo cloud
(动态) 控制专用冻结节点的溢出阶段水印的最大预留空间(以百分比/比率值表示)。当未明确设置 cluster.routing.allocation.disk.watermark.flood_stage.frozen 时,默认为 20GB。这限制了专用冻结节点上所需的可用空间量。
cluster.info.update.interval
(动态) Elasticsearch 检查集群中每个节点的磁盘使用情况的频率。默认为 30s

百分比值指的是已用磁盘空间,而字节值指的是可用磁盘空间。这可能会造成混淆,因为它颠倒了高和低的含义。例如,将低水印设置为 10GB,将高水印设置为 5GB 是合理的,但反过来则不合理。

以下示例将低水印更新为至少 100GB 可用空间,将高水印更新为至少 50GB 可用空间,将溢出阶段水印更新为 10GB 可用空间,并将集群信息的更新频率更新为每分钟一次

response = client.cluster.put_settings(
  body: {
    persistent: {
      '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'
    }
  }
)
puts response
PUT _cluster/settings
{
  "persistent": {
    "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"
  }
}

关于水印的最大预留空间设置,请注意,这些设置仅在水印设置为百分比/比率时适用。最大预留空间值的目的是在达到相应水印之前限制所需的可用磁盘空间。这对于具有较大磁盘的服务器特别有用,因为百分比/比率水印可能会转化为很大的可用磁盘空间需求,并且可以使用最大预留空间来限制所需的可用磁盘空间量。例如,让我们看一下溢出水印的默认设置。它的默认值为 95%,溢出最大预留空间设置的默认值为 100GB。这意味着

  • 对于较小的磁盘(例如 100GB),溢出水印将在 95% 时达到,这意味着在 5GB 可用空间时,因为 5GB 小于 100GB 的最大预留空间值。
  • 对于较大的磁盘(例如 100TB),溢出水印将在 100GB 可用空间时达到。这是因为仅 95% 的溢出水印就需要 5TB 的可用磁盘空间,但这被最大预留空间设置限制为 100GB。

最后,只有在未明确设置相应的水印设置时(因此,它们具有默认的百分比值),最大预留空间设置才会具有默认值。如果明确设置了水印,则最大预留空间设置将没有默认值,如果需要,则需要明确设置。

分片分配感知编辑

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

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

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

详细了解设计弹性集群

启用分片分配感知编辑

要启用分片分配感知,请执行以下操作

  1. 使用自定义节点属性指定每个节点的位置。例如,如果您希望 Elasticsearch 在不同机架之间分发分片,则可以使用名为 rack_id 的感知属性。

    您可以通过以下两种方式设置自定义属性

    • 通过编辑 elasticsearch.yml 配置文件

      node.attr.rack_id: rack_one
    • 在启动节点时使用 -E 命令行参数

      ./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 来设置或更新集群的感知属性

    response = client.cluster.put_settings(
      body: {
        persistent: {
          'cluster.routing.allocation.awareness.attributes' => 'rack_id'
        }
      }
    )
    puts response
    PUT /_cluster/settings
    {
      "persistent" : {
        "cluster.routing.allocation.awareness.attributes" : "rack_id"
      }
    }

使用此示例配置,如果您启动两个 node.attr.rack_id 设置为 rack_one 的节点,并创建一个包含 5 个主分片和每个主分片的 1 个副本的索引,则所有主分片和副本都将分配到这两个节点上。

All primaries and replicas are allocated across two nodes in the same rack
图 1. 所有主分片和副本都分配到同一机架中的两个节点上

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

Primaries and replicas are allocated across four nodes in two racks with no two copies of the same shard in the same rack
图 2. 主分片和副本分配到两个机架中的四个节点上,同一个分片的两个副本不在同一个机架中

如果 rack_two 发生故障并导致其两个节点都关闭,默认情况下,Elasticsearch 会将丢失的分片副本分配给 rack_one 中的节点。为了防止将特定分片的多个副本分配到同一位置,您可以启用强制感知。

强制感知编辑

默认情况下,如果一个位置发生故障,Elasticsearch 会将其分片分散到其余位置。如果集群在缺少一个位置时没有足够的资源来托管其所有分片,这可能是不可取的。

为了防止在整个位置发生故障时剩余位置过载,请使用 cluster.routing.allocation.awareness.force.* 设置指定应该存在的属性值。这意味着如果只有一个区域可用,Elasticsearch 将更愿意将一半的分片副本保留为未分配状态,而不是使剩余区域中的节点过载。

例如,如果您有一个名为 zone 的感知属性,并在 zone1zone2 中配置节点,则可以使用强制感知使 Elasticsearch 在只有一个区域可用时将一半的分片副本保留为未分配状态

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

指定所有可能的 zone 属性值。

使用此示例配置,如果您有两个 node.attr.zone 设置为 zone1 的节点,并且有一个 number_of_replicas 设置为 1 的索引,则 Elasticsearch 会分配所有主分片,但不分配任何副本。一旦 node.attr.zone 设置为不同值的节点加入集群,它就会分配副本分片。相反,如果您没有配置强制感知,即使两个节点位于同一区域中,Elasticsearch 也会将所有主分片和副本分配给这两个节点。

集群级分片分配过滤编辑

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

分片分配过滤器可以基于自定义节点属性或内置的 _name_host_ip_publish_ip_ip_host_id_tier 属性。

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

集群级分片分配过滤最常见的用例是当您想要停用某个节点时。要在关闭节点之前将分片从该节点移走,您可以创建一个按 IP 地址排除该节点的过滤器

response = client.cluster.put_settings(
  body: {
    persistent: {
      'cluster.routing.allocation.exclude._ip' => '10.0.0.1'
    }
  }
)
puts response
PUT _cluster/settings
{
  "persistent" : {
    "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 匹配节点

_tier

按节点的 数据层 角色匹配节点

_tier 过滤基于 节点 角色。只有一部分角色是 数据层 角色,并且通用的 数据角色 将匹配任何层过滤。一部分角色是 数据层 角色,但通用的 数据角色 将匹配任何层过滤。

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

response = client.cluster.put_settings(
  body: {
    persistent: {
      'cluster.routing.allocation.exclude._ip' => '192.168.2.*'
    }
  }
)
puts response
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.exclude._ip": "192.168.2.*"
  }
}