避免和纠正热点:Elasticsearch Serverless 如何平衡分片

作者:来自 Elastic Dianna Hohensee

Elasticsearch Serverless 用资源使用情况感知的再平衡机制取代了基于 Elasticsearch 节点权重的分片再平衡算法,从而避免索引分片共置、OOM 事件以及写入负载热点问题。

通过 Elastic Cloud Serverless 让自己从运维工作中解放出来。自动扩展、处理负载峰值,并专注于构建 ------ 开始 14 天的免费试用,亲自测试一下!

你可以按照这些指南来构建 AI 驱动的搜索体验,或者跨业务系统和软件进行搜索

Elasticsearch Serverless 平衡器解决写入负载热点问题,防止数据节点内存不足(OOM)事件,并避免 Elasticsearch Serverless 集群中的索引级热点:这些都是工作负载中的边缘情况,在非 Serverless 环境中通常需要手动干预并对集群设置进行自定义调优。Serverless 分片平衡的重点是确保处于节点级资源约束范围内。再平衡移动是可解释的,移动会被明确执行,以避免性能下降,或者在热点出现时纠正热点。同时,通常也会发现分片移动次数更少。

Elasticsearch 分片平衡如何工作

Elasticsearch 使用基于权重的算法来创建期望平衡(Desired Balance),即将分片分配给数据节点。平衡器使用线性算法,根据四个经过加权的关键指标来确定分片在集群节点之间的目标分配。系统会为每个节点计算总权重,分片平衡器的目标是使集群节点之间的总权重保持均衡。系统会根据最新的集群状态信息预先计算最终的期望平衡分片分配,然后由当选的主节点发起增量式分片移动,以达到期望的分片分配状态。

这四个指标是:

  • **写入负载:**每个节点上的写入线程池活动总量,使用每个数据流分片的线程池索引活动总和。

  • **磁盘使用量:**每个节点上分片的磁盘使用总量,使用每个分片所占用磁盘空间的总和。

  • **分片数量:**分配给一个节点的分片总数。

  • **索引平衡(分片反亲和性):**对于每个索引,分配给该节点的索引分片数量。

节点的总权重使用线性算法计算。该算法会计算每个指标相对于节点级集群平均值的偏差,为每个指标应用不同的权重因子乘数,然后将所有计算结果相加。权重因子乘数试图平衡每个指标的相对数量级,从而避免数值较大的指标压过那些自然数值较小的指标。写入负载通常是一个与线程使用情况相关的较小数值,因此会乘以相对较大的权重因子 10;而以字节为单位的磁盘使用量是一个非常大的数值,因此会乘以很小的权重因子 2e-11

以下是使用 默认值 的集群设置,它们代表不同的权重因子:

cluster.routing.allocation.balance.shard: 0.45

cluster.routing.allocation.balance.index: 0.55

cluster.routing.allocation.balance.disk_usage: 2e-11

cluster.routing.allocation.balance.write_load: 10.0

线性算法大致如下:

ini 复制代码
`

1.  final float shardWeightFactor =
2.      settingValue("cluster.routing.allocation.balance.shard");
3.  final float writeLoadWeightFactor = 
4.      settingValue("cluster.routing.allocation.balance.write_load");
5.  final float diskUsageWeightFactor = 
6.      settingValue("cluster.routing.allocation.balance.disk_usage");
7.  final float indexWeightFactor = 
8.      settingValue("cluster.routing.allocation.balance.index");

10.  final float shardCountDeviation = numShardsOnNode - averageShardsPerNode;
11.  final float writeLoadDeviation = totalWriteLoadOnNode - averageWriteLoadPerNode;
12.  final float diskUsageDeviation = totalShardDiskUsageOnNode - averageShardDiskUsagePerNode;
13.  final float indexDeviation = numIndexShardsOnNode - averageNumIndexShardsPerNode;

15.  return shardCountDeviation * shardWeightFactor
16.      + writeLoadDeviation * writeLoadWeightFactor
17.      + diskUsageDeviation * diskUsageWeightFactor
18.      + indexDeviation * indexWeightFactor;

`Lobster AI![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

触发分片移动,是为了确保集群节点之间的总节点权重差值保持在 cluster.routing.allocation.balance.threshold 以下,该设置的默认值为 1:每当超过该阈值时,分片就会从权重最高的节点移动到权重最低的节点,直到权重最高节点和权重最低节点之间的差值小于或等于 threshold

每当发生会改变分片分配的集群活动时(例如创建/删除索引、添加/删除节点,或者磁盘使用量增长),平衡器都会重新检查各节点之间的权重。如果权重最高节点和权重最低节点之间的差值超过配置的阈值,就会触发分片再平衡。基于阈值的方法试图在保持集群完美平衡和最小化分片移动之间取得平衡。对于使用资源更多节点的大型 Elasticsearch 部署 ,提高 threshold 设置通常会带来好处:节点之间更大的权重差值可以减少分片再平衡。

分片移动还受到严格的分片分配规则约束,这些规则会根据集群级别和索引级别的设置禁止某些节点分配。例如:不将同一个分片的副本分配到同一个节点或主机;不允许继续向没有多余磁盘空间的节点分配分片;以及将某些节点排除在特定索引的主机范围之外。下面将对此进行更多介绍。

一个平衡集群是什么样的(基于权重)

使用前面介绍的线性算法和集群设置默认值,下面是一个平衡器认为处于平衡状态的示例。值得注意的是,对于某一个特定指标,它有时允许不同节点之间存在相当大的偏差。为简单起见,这里不包括索引平衡。

scss 复制代码
`

1.  Weight Node1 = 0.45 (5 - 6) + 10 (0.3 - 0.33) + 2e-11 (1e+11 - 8e+10) =   - 0.35

3.  Weight Node2 = 0.45 (7 - 6) + 10 (0.4 - 0.33) + 2e-11 (4e+10 - 8e+10) =   0.35

5.  Weight Node3 = 0.45 (6 - 6) + 10 (0.3 - 0.33) + 2e-11 (1e+11 - 8e+10) =   0.10

`Lobster AI

基于权重的分片分配的局限性

Elasticsearch Serverless 部署由 Elastic 管理,可能会遇到许多边缘情况,而基于权重的分片分配在没有额外配置的情况下很难妥善处理这些情况。在自管理的 Elasticsearch 部署中,可以通过配置集群来适应用户的工作负载,从而绕过其中许多问题。然而,Elasticsearch Serverless 只需要配置一次,并且必须适用于所有客户的使用场景。一些 Elasticsearch 客户遇到的问题(其中包括 Serverless 的早期采用者)包括:

  • 活跃集群中持续进行再平衡所产生的后台噪声。这可能是因为需要调整 threshold 设置,也可能是因为集群非常繁忙。

  • 无法以可预测的方式调整平衡器的行为。调整平衡器设置(单独的权重因子)可能由于线性算法而导致不可预测的结果。例如,相对于其他权重因子降低分片数量权重因子,可能会在分片数量平衡优先级降低、过多分片堆积在单个节点上时导致数据节点发生 OOM 事件。

  • 不会解释平衡器为什么要移动分片。如果没有相关的节点指标,很难理解线性算法。

  • 线性算法允许一个指标中的高值抵消另一个指标中的低值。例如,一个节点的写入负载可能高于集群节点的平均值,但可以通过低于平均值的分片数量来抵消(反之亦然),于是线性算法会抵消这些峰值:不会移动分片来处理写入负载热点。

  • 可能出现索引级热点。当某个索引中不成比例数量的分片被分配到同一个节点,而不是分散到不同节点时,即使线性算法中存在索引平衡权重,也可能出现这种情况。在某些情况下,与其他权重因子相比,索引平衡权重可能很小。正如前面的条目所述,它还可能在线性算法中被另一个非平均的单独权重抵消,从而产生偏斜。

  • 没有搜索负载平衡。

  • 常规索引不支持写入负载估算,因此一些写入负载热点无法得到处理。只有数据流索引具有写入负载估算。

  • 可能遗漏写入负载热点。写入负载估算仅在滚动时刷新,而在某些配置中滚动可能并不频繁,从而导致新的负载在一段时间内被忽略。写入负载还是索引滚动事件之间可能很长时间窗口内的平均写入活动,因此临时的写入负载增加可能会在与非活跃写入时段进行平均后消失。

上述问题在一些 Elasticsearch 部署中仍然存在,并且在发生这些问题时需要通过监控和工作负载调优来进行管理。Elasticsearch Serverless 中的分片分配平衡旨在解决这些问题,并通过一种新的方法避免任何手动干预需求,后续章节将对此进行解释。

Elasticsearch Serverless 分片分配

Elasticsearch Serverless 会单独考虑每个节点的资源:当某个节点上的任何资源使用量增长到可能威胁性能时,分片就会从该节点重新平衡出去;而当向某个节点分配分片可能威胁该节点的性能时,则会拒绝将分片移动到该节点。

Elasticsearch 中每个节点的单一组合评分,在 Elasticsearch Serverless 中被独立的每资源决策所取代:

Elasticsearch 基于权重的平衡 Elasticsearch Serverless 资源感知决策器
决策依据 四个指标的单一加权总和 每种资源分别进行评估
指标交互 高值可以抵消低值 不进行抵消;每个决策器独立运行
决策类型 YES / NO YES / NO / NOT_PREFERRED
再平衡触发条件 节点之间的权重差值超过 threshold 每种资源分别配置安全限制
可解释性 只能进行推测性判断 每次移动都可以追溯到一个命名的决策器

Elasticsearch 平衡器按照优先级依次包含三个阶段,用于决定分片移动。第一阶段是分配未分配的分片。出于数据可用性的原因,分配未分配分片具有最高优先级。第二阶段是移动由于集群配置发生变化而无法继续留在当前分配位置的分片。在内部,AllocationDecider 实现负责执行集群设置,例如索引级分片分配过滤分片分配感知磁盘使用量阈值,或者在节点关闭之前将分片从该节点移走。第三阶段是在 cluster.routing.allocation.balance.threshold 超过时,使用前面介绍的权重算法对分片进行再平衡。

新的 Serverless 平衡方法在平衡器的第一阶段和第二阶段增加了额外逻辑,利用现有的 AllocationDecider 逻辑,并取消第三阶段。以前,每个 AllocationDecider 只有简单的 YESNO 响应。现在增加了 NOT_PREFERRED 决策 类 型,同时增加了多个新的 AllocationDecider 实现。当 AllocationDecider 发现将分片分配给某个特定集群节点可能导致性能下降时,它会返回 NOT_PREFERRED。Serverless 平衡器会优先选择一个节点来分配分片,使所有 AllocationDecider 实现都返回 YES

如果所有其他节点分配都返回 NONOT_PREFERRED,则 NOT_PREFERRED 的分片分配可能不会得到纠正。这些响应意味着,在不违反集群/索引规则或可能降低另一个集群节点性能的情况下,该分片无法被分配到其他位置。Serverless 自动扩展会在所有集群节点出现热点之前启动:即使只有一个无法解决的热点,也会触发扩容事件。针对重要的有限资源,例如可用堆内存(下面会进一步讨论),还增加了新的 AllocationDecider 实现,这些实现只使用原有的 YESNO 决策:超过某些类别的资源限制可能导致节点不可用。

平衡器线性算法中的单独权重指标已经被资源感知的 AllocationDecider 实现所取代,并且正在为其他资源构建新的 AllocationDecider 实现:Serverless 搜索层负载均衡改进目前正在开发中。每次分片迁移都会有明确的目的,即解决潜在的资源使用瓶颈。

内部统计数据显示,分片移动总体上大幅减少,同时没有出现明显的节点性能下降------其中一个工作负载在写入吞吐量相同的情况下,分片移动减少了 50%。更少的分片移动带来的好处包括:避免本地缓存预热造成的瞬时读写延迟;以及节省在服务器之间移动数据所产生的云基础设施成本。

Serverless IndexBalanceDecider:避免索引分片共置

IndexBalanceDecider 对索引分片反亲和性的保证,比原来的基于权重的线性算法能够实现的严格得多。除了严格的 NO 分配情况(目前在 Serverless 中基本不存在,关闭节点和滚动升级的不兼容版本检查除外),或者由于节点临时出现热点而导致的 NOT_PREFERRED 分配之外,系统会避免索引分片共置数量超过该索引在可用节点上的平均分片数量。

IndexBalanceDecider 是一种非常有效的预平衡写入负载和搜索负载的方法,可以在用户工作负载开始产生负载统计数据之前完成平衡:每个索引从创建之初,其分片就会尽可能分布到更多节点上。

IndexBalanceDecider 结果:集群节点之间更均匀的写入负载分布

在 Serverless 生产环境中启用 IndexBalanceDecider 后,数据节点之间的写入负载分布变得更加均匀。整个项目群通常都表现出均匀的摄取负载(以饱和的 WRITE 线程池线程数计算),这得益于 IndexBalanceDecider 的发布以及此前进行的许多其他改进:

一个可复现的工作负载展示了启用和未启用新 IndexBalanceDecider 时的影响,可以清晰地对比前后的结果:当运行摄取工作负载时:

IndexBalanceDecider 同样服务于 Serverless 搜索层,用于在允许的范围内尽可能分散同一索引的分片,其限制因素类似,只取决于该层的节点数量以及每个索引中的分片数量。

Serverless HeapUsageDecider:根据可用堆内存分配分片

HeapUsageDecider 根据节点可用的堆内存限制节点上的分片数量,以便在内存中保存分片元数据并运行相关的写入/读取操作,从而不再依赖每个节点的分片数量限制。

HeapUsageDecider 返回严格的 YESNO 决策,而不是使用新的 NOT_PREFERRED 决策类型,因为如果估算的可用堆内存被耗尽,数据节点就有发生 OOM 事件的风险。

HeapUsageDecider 结果:减少数据节点 OOM

随着 HeapUsageDecider 在 Serverless 生产环境中逐步推出,Serverless 索引层中的数据节点 OOM 显著减少。

尽管发生率已经大幅降低,Serverless 索引层中仍会不时出现索引层 OOM 错误,因为各种内存使用失控的边缘情况会逐渐暴露出来。随着这些问题被发现,剩余的 OOM 错误正在逐步得到解决,所采用的方法包括改进代码中的内存使用、增加组件级限制,以及更新内部 Elasticsearch Serverless 内存模型服务,以更加完整地计算内存使用量。

由于需要额外的不同指标,HeapUsageDecider 目前尚未在 Serverless 搜索层中启用,但相关工作正在积极开发中。

Serverless WriteLoadDecider:防止和纠正写入负载热点

WriteLoadDecider 接收定期刷新的每个分片和每个节点的写入负载统计数据(默认每 30 秒刷新一次),并利用这些数据纠正和避免写入负载热点。主节点直接从每个数据节点的写入线程池获取统计信息:Elasticsearch 节点会跟踪其 WRITE 线程池处于使用状态的总时间,而每个独立的 Elasticsearch 分片实例会跟踪其使用所在节点 WRITE 线程池的时间。

写入负载热点在节点级别进行识别。热点的判断标准是:WRITE 线程池队列延迟超过配置的阈值且达到足够高的水平,同时 WRITE 线程池线程持续处于高饱和状态。一旦检测到这种情况,平衡器就会收到信号,从出现热点的节点上选择要移动的分片,直到从该节点收到最新的、非热点状态的写入负载统计数据。如果所有节点同时都出现热点,平衡器将不会采取任何操作,而是预期自动扩展器通过向集群引入更多或更大的数据节点来解决问题。

WriteLoadDecider 使用一种启发式方法,从出现热点的节点上选择要移动的分片,目标是在有效降低节点写入负载的同时,尽量减少对摄取的影响。系统会在出现热点的节点上确定一个分片写入负载 threshold:目前,该 threshold 计算为该节点上最热分片摄取负载的 ½。随后,可移动的分片按照以下顺序进行优先级排序:

threshold = ½ * maxWriteLoadShardOnNode

  1. 写入负载位于 [thresholdmaxWriteLoadShardOnNode) 范围内的分片,其中优先选择写入负载等于或最接近 threshold 的分片。

  2. 写入负载位于(threshold0] 范围内的分片,其中优先选择最接近 threshold 的分片。

  3. 写入负载等于 maxWriteLoadShardOnNode 的分片。

  4. 写入负载为零的分片。

这种启发式方法倾向于避免对摄取负载最高的分片造成干扰,而是选择负载处于中等水平的分片。移动最热的分片会造成最大的延迟干扰;而移动最冷的分片对解决热点的效果最差。

平衡器将每个出现热点的节点的写入负载热点纠正分片移动限制为每个统计刷新周期一次,以便实时观察一次移动对节点级写入负载产生的影响,然后再尝试进一步纠正。这是一个简单的初始设计,但事实证明效果很好。此外,如果某个分片自身的写入负载就足以满足节点级热点标准,平衡器不会移动该分片:这样做只会将热点转移到另一个数据节点,而不会真正解决热点问题。对于无法通过重新分配分片解决的热点,则依赖 Serverless 自动扩展器和 Serverless 自动分片组件来解决。

当接受某个分片可能导致节点开始出现 WRITE 线程池队列延迟并形成热点时,WriteLoadDecider 会返回 NOT_PREFERRED。不过,该分片仍然可能被重新定位到一个 NOT_PREFERRED 节点,并承担一定的性能下降风险,因为与之相比,这可能是更好的选择。例如,可以避免因为将分片继续保留在 HeapUsageDecider 返回 NO 的数据节点上而导致数据节点发生 OOM。

WriteLoadDecider 结果:热点得到快速纠正

随着 WriteLoadDecider 在 Serverless 生产环境中逐步推出,热点统计数据显示整体情况有所改善,尤其是整个项目群纠正热点所需的时间大幅缩短:

自这些图表收集完成以来,又陆续发布了更多改进,以更好地预防和纠正热点问题,相关改进仍在持续进行中。

Serverless 自动扩展、自动平衡和自动分片

Elasticsearch Serverless 同时依赖新的自动平衡逻辑和新的自动扩展逻辑。Serverless 平衡器必须充分将分片资源使用量分布到各个节点上,才能充分利用集群的资源。Serverless 自动扩展器在收到报告,得知集群总资源中有一定百分比正在使用,并且需要更多资源时,就会触发扩容事件。如果一个节点出现热点,而另一个节点还有大量可用资源,自动扩展器不会扩展集群,因为资源使用量是跨节点汇总计算的。因此,平衡器必须首先做好负载分布,然后自动扩展器才会根据需要启动。

基于写入负载的自动分片功能也正在开发中,并即将推出,以解决分片热点问题。Elasticsearch Serverless 项目会根据项目类型,为每个索引设置默认的分片数量。这些默认值通常能够正常工作,但无法涵盖所有可能的工作负载。当一个索引的分片太少或太多时,都可能出现热点。

索引分片太少,会导致平衡器无法进一步将该索引的写入负载分布到可用的数据节点上,而此时自动扩展器又不会发现问题,因为集群级资源并没有被完全消耗。相反,索引默认情况下也不能拥有过多分片,因为这可能降低小型索引的搜索性能;如果集群中的分片总数增长过大,还可能给集群元数据操作带来压力。

生产环境示例:708 TB 数据集、37 个索引层节点(不包括搜索层)、4,100 个索引、30,000 个分片

下面的图表涵盖了这样一个时间段:在一个 Elasticsearch Serverless 项目中,索引层从 10 个节点扩展到 37 个索引节点,然后在写入负载峰值消退后,再缩减回 10 个节点。

每个索引节点的摄取负载图

该图显示负载分布相当均匀,不过在扩容期间,短时间内会稍微不那么均匀。负载达到峰值时,几乎有 250 个写入线程处于完全饱和状态。

每个索引节点的 CPU 饱和度图

CPU 使用率始终处于安全范围内。使用率大部分时间低于 60%,只有在写入负载上升、节点加入集群之前,会短暂出现达到 90% 左右的异常峰值。

每个节点的WRITE线程池队列延迟图

当一个节点的WRITE线程池完全饱和时,任务会被放入线程池的队列中。如果正在执行的写入任务运行时间较长,即使任务数量很少,也可能发生排队;当然,也可能只是因为任务数量非常多。

这张图的时间窗口比其他图进一步进行了放大。在扩容峰值期间,有一个节点的队列延迟达到 75 秒。当队列延迟在 19:25 达到峰值时,共有 29 个节点;随后自动扩展在 19:28 请求扩容到 37 个节点。

每秒集群总摄取量图(以文档数和 MB 为单位)

摄取速率峰值达到每秒 190,000 个文档和每秒 54.40 MB。按每个节点每秒 4,000--5,000 个文档计算,文档摄取速率相当可观。不过,在这个案例中,MB 级别的摄取速率非常低:当索引操作涉及大量计算时,就可能出现这种情况。文档摄取速率也可能根据文档大小而有所不同。

Elasticsearch Serverless 平衡的下一步

团队目前正在为 Serverless 搜索层开发分片平衡方面的改进,重点是为搜索性能创建指标和AllocationDecider实现。团队很期待很快与大家分享这些改进!

原文:Elasticsearch Serverless: shard balancing and hotspots | Elasticsearch Labs

相关推荐
Elastic 中国社区官方博客1 小时前
机构如何统一智慧城市数据以改善公共服务?
大数据·人工智能·物联网·elasticsearch·搜索引擎·全文检索·智慧城市
阿里云大数据AI技术17 小时前
Agentic Search 2.0:从单轮对话迈向企业级 AI 搜索自动驾驶Agent
人工智能·elasticsearch·agent
Elasticsearch19 小时前
你的 AI agent 需要一个不在场证明:Elastic 中 Agent Builder 的可观测性和审计追踪
elasticsearch
Elasticsearch1 天前
仪表板活动日志:了解哪些 Kibana 仪表板会被使用
elasticsearch
Elasticsearch2 天前
从 22.61GB 到 15.63GB:Elasticsearch 9.5 如何用「混合存储」重新定义日志数据库
elasticsearch
Elasticsearch2 天前
用于自托管 LLM 调优的 vLLM Prometheus 指标:TTFT、KV Cache 和 GPU 利用率
elasticsearch
Sayai2 天前
Elasticsearch 快照备份到 NAS(NFS)实战:SLM 自动化 + 365 天保留策略
elasticsearch·自动化·jenkins
JavaPub-rodert3 天前
写软著 - Copyright Forge Skill 完整闭环改造方案
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客3 天前
从建议到修复的 4 个阶段:使用 Elastic Workflows 实现人在回路中的自动化
运维·数据库·人工智能·后端·elasticsearch·ai·自动化