C/C++教程

Elasticsearch不可不知的shard分片分配原理和配置

本文主要是介绍Elasticsearch不可不知的shard分片分配原理和配置,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

注:本文基于Elasticsearch8.2版本

shard分配

master node作为集群的管理节点,它主要存储集群的一些元信息,其中就包含哪些shard分配给哪些data node,以及什么情况下需要自动迁移分片,让各个数据节点的主副分片趋于平衡。
当集群中分片数发生变化时,就有可能触发分片的重平衡,默认情况下,ES会竟可能确保每个节点的总分片数一致。节点长时间下线,或者索引被删除,调整副本数都可能触发分片的重新分配。我们可以通过以下层面上来控制分片的分配
(1)集群层面的分片分配(cluster level shard allocation),可以在集群层面来控制shard allocation和rebalance的过程
(2)基于磁盘空间的分片分配(disk-based shard allocation),es会在shard分配的时候,考虑可用的磁盘空间
(3)分片分配感知(shard allocation awareness),控制shard如何在不同的机架上进行分布
(4)分片分配过滤器(shard allocation filter),可以控制有些node不参与allocation的过程,这样的话,这些node就可以被安全的下线

集群层面的分片分配(cluster level shard allocation)

shard allocation,就是将shard分配给具有data角色节点的过程,一般是索引创建或者新增副本分片时触发
集群层面分片分配的一些设置:
(1)cluster.routing.allocation.enable
它的配置值如下:

  • all,默认,对所有类型的shard都允许分配
  • primaries,仅仅允许primary shard被分配
  • new_primaries,仅仅对新建索引的primary shard允许分配
  • none,不允许任何shard被分配
    如果我们不希望分片自动分配,可以将cluster.routing.allocation.enable设置为none,通常在集群重启的时候我们会设置cluster.routing.allocation.enable为primaries,也就是只允许主分片被分配,防止集群重启期间集群误认为分片丢失而重新从其他节点拷贝副本分片

注意:此设置不影响重启节点时本地主分片的恢复

这些配置支持通过resetAPI动态调整,设置方式如下:

PUT _cluster/settings 
{ 
  "persistent": { 
    "cluster.routing.allocation.enable": "all"
  }
}

(2)cluster.routing.allocation.node_concurrent_incoming_recoveries:在一个node上允许同时恢复多少个shard,这里的shard recovery过程,指的就是要将某个shard分配给这个node。这个设置的默认值是2.

(3)cluster.routing.allocation.node_concurrent_outgoing_recoveries:一个node上允许同时进行多少个shard recovery outgoing。
比如这个node上,有一个primary shard,现在要将replica shard分配给其他的node,那么就是outgoing shard recovery。默认值也是2.

(4)cluster.routing.allocation.node_concurrent_recoveries:同时设置上面两个值

如果一台机器上部署了多个ES数据节点,需要慎重设置这个值。对于单机双节点的部署,一个节点的同时恢复分片数对整个机器来说就是双倍。分片的恢复操作会产生大量IO,如果需要集群仍然稳定提供服务,这个值不要设置过大,一般使用默认值就可以了。

(5)cluster.routing.allocation.node_initial_primaries_recoveries:如果replica shard recovery通过网络传输来分配,那么一个未被分配的primary shard会在node重启之后使用本地磁盘上的数据,这个过程因为是使用本地的数据,因此会比较快,默认值是4.
(6)cluster.routing.allocation.same_shard.host:默认值是false,如果设置为true,那么就不允许将一个primary shard和replica shard分配到同一个物理机上。
首先ES默认是不允许同一个主分片和它的副本分配到同一个节点的,但是单机部署了多个ES实例,就可能导致虽然同一个主分片和它的副本没有分配到同一个节点,但却分配到了同一个台机器上的不同节点,基于可用性考虑,如果这个机器宕机,这个分片的主副本都将丢失,就有一定的风险会丢失数据,而且重启机器也会导致集群变红,无法正常提供服务。所以在单机多节点的部署中,cluster.routing.allocation.same_shard.host需要设置为true

如果是固态硬盘,CPU比较充裕的前提下,想加快分片恢复和迁移的速度,我们可以适当调整这些配置

PUT _cluster/settings
{
  "transient": {
    "cluster": {
      "routing": {
        "allocation": {
          "cluster_concurrent_rebalance": "5",
          "node_concurrent_recoveries": "5"
        }
      }
    },
    "indices": {
      "recovery": {
        "max_bytes_per_sec": "500m"
      }
    }
  }
}

分片重平衡 (shard rebalance)相关配置

分片重平衡一般发生在集群中具有data角色的节点重启时,data节点分片初始化进行恢复的时可能会触发rebalance,也会发生在replica shard被分配的时候,集群进行rebalance的时候,或者是有新的node加入,有旧的node被下线,以及索引被删除,调整了副本分片数等情况,总之当集群的分片数发生变化时,就有可能触发分片的重新分配分片重平衡是一个高IO和网络消耗的操作,会给集群带来很大的负担,一般遇到会触发集群重平衡的操作需要选择在业务低峰期进行。

(7)cluster.routing.rebalance.enable

  • all,默认,允许对所有类型的shard进行rebalance过程
  • primaries,仅仅允许对primary shard进行rebalance过程
  • replicas,仅仅允许对replica shard进行rebalance
  • none,不允许对任何shard进行rebalance

(8)cluster.routing.allocation.allow_rebalance:

  • always,任何时候都允许rebalance
  • indices_primaries_active,仅仅只有在所有的primary shard都被分配之后才允许rebalance
  • indices_all_active,默认,仅仅允许所有的primary shard和replica shard都被分配之后,才能rebalance

(9)cluster.routing.allocation.cluster_concurrent_rebalance :允许控制多少个shard rebalance的操作同时运行,默认是2
(10)cluster.routing.allocation.balance.shard:设置每个node的shard分配的权重因子,默认是0.45f,提高权重因子,就会尽可能让均匀的shard分配给集群中的所有node
(11)cluster.routing.allocation.balance.index:定义每个index在一个node上的shard数量因子,默认是0.55f,提高这个参数,就会尽可能让每个index的shard均匀分配到所有的node上
(12)cluster.routing.allocation.balance.threshold:默认是1.0f,提高这个权重因子会导致集群对shard balance有更小的侵略性
es在进行shard allocation的时候,会充分考虑每一个node的可用磁盘空间,当磁盘空间达到一定阈值将会迁移分片到空间更充裕的节点,如果磁盘空间达到洪水线(可配置剩余空间阈值)就不再分配新分片,集群上的全部索引变成只读。
(13)cluster.routing.allocation.disk.threshold_enabled:默认是true,如果是false会禁用磁盘水位线的配置
(14)cluster.routing.allocation.disk.watermark.low:控制磁盘使用率的低水位,默认是85%,如果一个节点的磁盘空间使用率已经超过了85%,那么就不会分配shard给这个node了
(15)cluster.routing.allocation.disk.watermark.high:控制磁盘使用率的高水位线,默认是90%,如果一个节点的磁盘空间使用率已经超过90%了,那么就会将这个node上的部分shard移动走。
分配器还试图通过禁止向超过低水位线的节点分配更多的碎片来保持节点远离高水位线。重要的是,如果你的所有节点都超过了低水位,那么就不能分配新的碎片,Elasticsearch也不能在节点之间移动任何碎片,以保持磁盘使用率低于高水位。你必须确保你的集群有足够的磁盘空间,并且总是有一些节点低于低水位线。
(16)cluster.routing.allocation.disk.watermark.flood_stage:控制磁盘使用率的洪水线,默认是磁盘空间的95%。当磁盘空间达到洪水线,该磁盘上的索引将会执行只读索引块(index.blocks.read_only_allow_delete),也就是索引变成只读状态,不能修改写入和删除,只能查询。这个设置是防止节点耗尽磁盘空间的最后手段。当磁盘利用率下降到高水位以下时,索引块就会自动释放。

由基于磁盘的分片分配器触发的分片移动也必须满足所有其他分片分配规则,如分配过滤和强制意识。如果这些规则过于严格,那么它们也会阻止分片移动,以保持节点的磁盘使用得到控制。如果你使用的是数据层,那么Elasticsearch会自动配置分配过滤规则,将分片放在适当的层中,这意味着基于磁盘的分片分配器在每个层中独立工作。

如果一个节点填满其磁盘的速度超过了Elasticsearch将分片转移到其他地方的速度,那么就有可能出现磁盘完全填满的情况。为了防止这种情况,作为最后的手段,一旦磁盘使用量达到洪水阶段的水位,Elasticsearch就会阻止对受影响节点上有分片的索引进行写入。它还会继续将分片转移到集群中的其他节点上。当受影响的节点上的磁盘使用量下降到高水位标志以下时,Elasticsearch会自动删除写块。

(17)cluster.info.update.interval:es检查集群中每个node的磁盘使用率的时间间隔,默认是30s
(18)cluster.routing.allocation.disk.include_relocations:默认是true,意味着es在计算一个node的磁盘使用率的时候,会考虑正在分配给这个node的shard。

分片分分配感知(shard allocation awareness)

1. 机架感知特性

如果在一个物理机上运行多个虚拟机,并且在多个虚拟机中运行了多个es节点,或者在多个机架上,多个机房,都有可能有多个es节点在相同的物理机上,或者在相同的机架上,或者在相同的机房里,那么这些节点就可能会因为物理机,机架,机房的问题,一起崩溃
如果es可以感知到硬件的物理布局,就可以确保说,priamry shard和replica shard一定是分配到不同的物理机,或者物理机架,或者不同的机房,这样可以最小化物理机,机架,机房崩溃的风险
shard allocation awareness可以告诉es我们需要将分片按照指定规则分配到期望的节点上。
典型的使用场景是如果我们有多个机房或者节点分布在不同的机架,那么我们启动一个node的时候,在这个node上,可以给它一个rack_id,比如下面的命令:

./bin/elasticsearch -Enode.attr.rack_id=rack_one

也可以在elasticsearch.yml中设置这个机架id

cluster.routing.allocation.awareness.attributes: rack_id
node.attr.rack_id=rack_one

上面的两个设置里,第一个是设置机架id的属性名称,第二个是用那个机架id属性名称设置具体的机架id
如果启动两个data node(分别为node1和node2),都在一个机架上,此时创建一个有5个primary shard和5个replica shard的索引,分片会被分配到刚启动的这两个节点上。
如果再启动两个data node(分别为node3和node4),设置node.attr.rack_id=rack_two,此时es会将部分主副本分片移动到node3和node4上,使得同一个分片的主副分配到不同的机架上。但是如果机架rack_two发生故障了,为了恢复集群到正常状态,还是会将丢失的分片全部恢复到rack_one上。

我们可以指定多个awareness属性,比如机架id和机房名称:

cluster.routing.allocation.awareness.attributes: rack_id,zone

在执行search或者get请求的时候,如果启用了shard awareness特性,那么es会尽量使用local shard来执行请求,也就是在同一个rack_id的分片来执行请求,也就是说尽量用同一个机架或者一个机房中的shard来执行请求,而不要跨机架或者跨机房来执行请求,显然这样能避免跨机架或者机房获取数据。

2. 强制性的感知

上面的机架感知特性在只有两个机架或者机房的时候,当其中一个机房或机架出问题后,所有分片还是会恢复到同一个机房或者机架。这样在故障发生后还是会打破我们设定的规则,如果另一机房或者机架的节点不足以容纳恢复的分片,还是会出问题。
强制感知特性会解决这个问题
比如现在有两个机房zone1和zone2
node1和node2的node.attr.rack_id值为zone1
node3和node4的node.attr.rack_id值为zone2
强制感知设置如下:

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

上面的配置,luster.routing.allocation.awareness.force.zone.values指定了zone1和zone2,假如zone1上的node1和node2,离线了。这事不会立马恢复分片副本到node3和node4,需要等zone1上有节点启动后才会开始恢复分片副本。

分片分配过滤器 (shard allocation filtering )

分片分配过滤器 可以让我们允许或者不允许某些index的shard分配给一些特殊的节点,典型的用途,就是如果我们要下线一些node,就可以用这个feature禁止shard分配给这些即将下线的node,而且我们还可以将这些即将下线的节点的shard移动到其他节点。
用下面的api可以下线一个节点:

PUT _cluster/settings
{
"transient" : { 
"cluster.routing.allocation.exclude._ip" : "192.168.1.5,192.168.1.6"
	}
}

也可以使用通配符

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

node下线时的shard延迟分配

如果从集群中下线一个节点,master会做下面这些事情:
(1)如果那个节点上有primary shard,那么master会将那些primary shard在其他节点上的replica shard提升为primary shard;
(2)分配新的replica shard来保证replica数量充足;
(3)在剩下的各个node上进行shard rebalance,确保分片均匀分布到各个data节点;
这些操作可以保护集群不会丢失数据,因为会对每个shard都复制充足的副本分片
但这个过程,可能会导致集群中出现很重的负载,包括网络负载和磁盘IO负载,如果那个下线的节点只是暂时离线,后续会自愈或者经过运维处理可以快速启动。那么这种立即执行的shard recovery过程是不需要的。
这时候只要等待几分钟,那么丢失的那个node自己会回来,丢失的shard也会自动恢复过来,因为数据都在节点的本地,不需要重新拷贝数据以及网络传输,整个恢复过程会更快.

index.unassigned.node_left.delayed_timeout,这个参数可以设置某个节点下线之后,对应的replica shard被重新复制和分配的时间等待期,默认是1m,可以通过下面的命令来修改:

PUT _all/_settings</p><p>{
"settings":
  "index.unassigned.node_left.delayed_timeout": "5m"
   }
}

如果某个node确定了永久离线,那么可以通过下面的命令快速触发分片恢复(待恢复完成后再修改到5m

PUT _all/_settings
{
"settings": {
"index.unassigned.node_left.delayed_timeout": "0"
	}
}

索引恢复的优先级

没有被分配的shard都是按照优先级来分配的,有下面几个优先级:
index.priority:索引的创建日期和索引名称,设置方式如下:

PUT test_index
{
 "settings": {
   "index.priority": 2
 }
}

每个节点的shard数量设置

cluster.routing.allocation.total_shards_per_node:设置每个节点最多承载的shard数量,默认无限制

这篇关于Elasticsearch不可不知的shard分片分配原理和配置的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!