《Elastic Stack 实战手册》——三、产品能力——3.5 进阶篇——3.5.5.Shard allocation (2) https://developer.aliyun.com/article/1228684
管理节点
系统资源吃紧,需要通过横向扩容增加集群容量。
节点扩/缩容
当向集群扩容节点时,其他节点会迁移部分分片到新节点,如果并发迁移的分片过多,可能造成瞬时的高 IO 负载,引起服务抖动。
我们可以通过 cluster.routing.allocation.node_concurrent_incoming_recoveries 参数控制分片迁移的速度,如果是在集群负载较高的情况下横向扩容新节点,建议分开两步操作:
l 关闭 cluster.routing.rebalance.enable (主要是考虑到分片移出后可能会引起集群重平衡操作)
l 通过手动对目标索引进行 index.routing.allocation.include 配置,将新节点纳入到分片的分布范围,逐个迁移索引分片。目的是减少大规模持续的分片迁移,导致集群负载继续升高,甚至发生雪球效应。
同样的,在缩容集群时,如果直接关闭节点,可能存在两个风险点:
l 在集群规模较大情况下,会有大量索引同时进行分片主从切换和分片重新分配操作,瞬时对 master 节点带来很大的负载,尤其是日志类数据的大集群。因为分片数较多,可能导致
l master 节点 CPU 飙高,使得新创建索引等操作被阻塞。
l 小概率情况下。如果其他节点发生意外宕机,索引将存在数据丢失风险。
对于类似缩容,存在一定风险性的主动操作,建议与扩容类似,首先设置全部索引的 index.routing.allocation.exclude 或者直接在集群范围内设置 cluster.routing.allocation.exclude 属性将待下线的节点排除,待分片全部移出之后再关闭节点进程。
节点重启
除了横向扩容外,对节点纵向扩容,或者升级 Elasticsearch 版本,都需要对节点进行重启操作。
在重启节点时,自然会有节点的上下线操作,节点下线同时会让该节点所属的分片处于
unassigned 状态。正常情况下,集群会将这些未分配分片,重新分配到集群内其他节点上,在日常运维的节点重启操作中,这显然不是我们期望的,无端的带来了大量的 IO 操作。
正常的滚动重启操作中,建议是:
l 通过 cluster.routing.allocation.enable: none 关闭分片分配;
l 重启节点;
l 将 cluster.routing.allocation.enable 重置为 all 打开分片分配。
调控分片的物理分配
因为日志检索方面表现良好,公司决定将商品、订单等系统的检索功能也迁移到 Elasticsearch集群,并提供了高配机器用于集群搭建。
分片在单台物理机的分配
在实际的部署过程中,有时会遇到大容量高配机器,比如 32 核 128GB 内存,我们可以考虑单节点部署,将对内存数据量扩大到 32GB 以上 (一个是对象指针压缩技术不再可用,造成内存空间膨胀,另一个是堆内存回收压力也增大,可能造成 gc 停顿时间变长);
也可以考虑单机多节点的部署方式,在这种情况下,为了数据可用性的考虑,索引内同一分片的主副本数据,需要分配到不同的物理节点上,这时可以使用如下参数:
l cluster.routing.allocation.same_shard.host
l 阻止同一分片的多个实例 (主副本) 落到同一个主机,同一主机的判定条件为相同的主机名 (host name) 和主机地址 (host address),默认情况下该参数为关闭状态,强烈建议在单机多节点部署的情况打开该配置,避免可能的数据丢失风险。
对商品、订单的搜索场景,一般单节点的负载会控制在最大值的 50% 左右,以提供足够的余量来承载瞬时的流量高峰,为了达到这个目的,在分片分配层面,可以设置单节点的分片数上限:
l cluster.routing.allocation.total_shards_per_node
l 单节点最多能支撑的分片数,当节点包含的分片数高于该数值时,新分片不会在该节点创建。
分片在机房内的分配
为了数据高可用的考虑,我们在管理集群的时候,可能会考虑索引的主从分片,不要都落到某一台宿主机,或者同一个机架上,这个时候可以通过一些提示性参数,让集群在选择节点时有一定的倾向性:
l cluster.routing.allocation.awareness.attributes
l 设置分片分布时,会考虑将分布交叉分布到属性不同的节点上,比如集群包含两个节点 N1 node.attr.zone=zone1、N2 node.attr.zone=zone2,如果我们在 elasticsearch.yml 中设置cluster.routing.allocation.awareness.attributes: zone,则我们新建带一个副本的索引时,集群会将同一分片的主副本交叉分布在不同的节点上。节点属性可通过上述自定义属性方式设置。
l cluster.routing.allocation.awareness.force.zone.values
l 假设集群节点仍然是 N1、N2,如果 N2 因为故障宕机,默认情况下,N2 所属的分片会在 N1 节点重新恢复出来,但是在同一个节点运行相同分片的主副本并没有实际意义,这时我们在 elasticsearch.yml 中设置 cluster.routing.allocation.awareness.force.zone.values: zone1,zone2 来避免这种操作,集群会在 zone2 属性节点恢复后再将相应的副本分片恢复到该节点。
集群分片上限
系统跑起来了,那么集群最多能负载的分片数是多少呢?
对日志类的数据,通常会以应用、时间、日志级别等多个维度建立索引,这样一来集群内的总分片数变得相当可观,那么集群最多能负载的分片数是多少呢?
答案也很简单,就是节点数与单个节点能最多能支撑的分片的积,但是这里的单节点最多支撑的分片数:
l cluster.max_shards_per_node
l 用于限制整个集群最多能支撑的分片数,当集群内活跃分片数大于 cluster.max_shards_per_node * number_of_data_node 时,集群会阻止新索引的创建,直到有索引被删除或者关闭 (closed) ,使得活跃分片总数低于阈值。这里的活跃分片数是指非 closed 状态的分片,包括 unassigned / initializing / relocating / started。
不会像 cluster.routing.allocation.total_shards_per_node 真正的限制单节点的分片数。
这里列举了部分较为常用的配置,更多参数可以参阅官方文档。
小结
我们调整或干预集群的分片参数,从根本上说,是为了在集群稳定的情况下将性能最大化,从分片分配 (allocation) 的角度来说,稳定意味着分片尽量少的移动,性能意味着同一个索引的分片尽量均匀分布到各节点,而不要集中到少数几个节点。
《Elastic Stack 实战手册》——三、产品能力——3.5 进阶篇——3.5.5.Shard allocation (4) https://developer.aliyun.com/article/1228681