Elasticsearch:我的 Elasticsearch 集群中应该有多少个分片?

2022年8月25日   |   by mebius

作者:Christian Dahlqvist

编者注:“每 GB 堆内存的目标是 20 个或更少分片” 的经验法则在 8.3 版中已弃用。 此博客已更新以反映新建议

Elasticsearch 是一个非常通用的平台,它支持各种用例,并在数据组织和复制策tgcode略方面提供了极大的灵活性。但是,这种灵活性有时会导致难以预先确定如何最好地将数据组织到索引和分片中,尤其是在你不熟悉 Elastic Stack 的情况下。虽然次优选择在刚开始时不一定会导致问题,但随着数据量的增长,它们有可能导致性能问题。集群拥有的数据越多,纠正问题也就越困难,因为有时可能需要对大量数据进行重新索引。

当我们遇到遇到性能问题的用户时,通常可以追溯到有关数据索引方式和集群中分片数量的问题。对于涉及多租户和/或使用基于时间的索引的用例尤其如此。在与用户讨论这个问题时,无论是在活动或会议上当面还是通过我们的论坛,一些最常见的问题是 “我应该拥有多少分片?” 和 “我的分片应该有多大?

这篇博文旨在帮助您回答这些问题,并为涉及在一个地方使用基于时间的索引(例如,日志记录或安全分析)的用例提供实用指南。

什么是分片?

在开始之前,我们需要确定一些我们在后面的章节中需要用到的事实和术语。

Elasticsearch 中的数据被组织成索引。每个索引由一个或多个分片组成。每个分片都是 Lucene 索引的一个实例,你可以将其视为一个独立的搜索引擎,它为 Elasticsearch 集群中的数据子集编制索引并处理查询。

%title插图%num

当数据写入分片时,它会定期发布到磁盘上新的不可变 Lucene 段中,此时它可以用于查询。这称为刷新。 Elasticsearch: the Definitive Guide 中更详细地描述了它的工作原理。

随着分段数量的增加,这些分段会定期合并为更大的分段。这个过程称为合并。由于所有段都是不可变的,这意味着使用的磁盘空间通常会在索引期间波动,因为需要先创建新的合并段,然后才能删除它们替换的段。合并可能会占用大量资源,尤其是在磁盘 I/O 方面。

%title插图%num

分片是 Elasticsearch 在集群周围分布数据的单位。 Elasticsearch 在重新平衡数据时可以移动分片的速度,例如发生故障后,将取决于分片的大小和数量以及网络和磁盘性能。

提示:避免使用非常大的分片,因为这会对集群从故障中恢复的能力产生负面影响。 分片的大小没有固定限制,但通常引用 50GB 的分片大小作为已被视为适用于各种用例的限制。

一个 shard 的性能会随着它的大下而改变:

%title插图%num

如上图所示,我们建议 50G 为索引的大小以求得最好的性能。在我们实际的 Beats 的使用中,默认的 ILM 索引大小就是 50G。为了最大限度地提高索引/搜索性能,分片应尽可能均匀分布在节点之间,以利用底层节点资源。 每个分片应保存 30 GB 到 50 GB 的数据,具体取tgcode决于数据类型及其使用方式。 例如,高性能搜索用例可以受益于整体较小的分片以运行快速搜索和聚合请求,而日志记录用例可能适合稍大的分片以在集群中存储更多数据。 可以根据你的性能要求、硬件和用例根据需要调整分片大小和每个节点的分片数量。

按保留期索引

由于段是不可变的,因此更新文档需要 Elasticsearch 首先找到现有文档,然后将其标记为已删除并添加更新版本。 删除文档还需要找到该文档并将其标记为已删除。 因此,被删除的文档会不断占用磁盘空间和部分系统资源,直到合并出来,会消耗大量系统资源。

Elasticsearch 允许直接从文件系统中非常有效地删除完整的索引,而无需明确地单独删除所有记录。 这是迄今为止从 Elasticsearch 中删除数据的最有效方法。

提示:尽可能使用基于时间的索引来管理数据保留。 根据保留期将数据分组到索引中。 基于时间的索引还可以轻松地随时间改变主分片和副本的数量,因为这可以更改以生成下一个索引。 这简化了适应不断变化的数据量和要求的过程。

索引和分片不是免费的吗?

对于每个 Elasticsearch 索引,有关映射和状态的信息都存储在集群状态中。 这被保存在内存中以便快速访问。 因此,在集群中拥有大量索引和分片会导致集群状态变大,尤其是在映射很大的情况下。 这可能会变得很慢,因为所有更新都需要通过单个线程完成,以保证在更改分布到集群中之前的一致性。

提示:为了减少索引的数量并避免大型和蔓延的映射,请考虑将具有相似结构的数据存储在同一索引中,而不是根据数据的来源拆分为单独的索引。 在索引和分片的数量以及每个单独索引的映射大小之间找到良好的平衡非常重要。 因为集群状态被加载到每个节点(包括主节点)的堆中,并且堆的数量与索引、每个索引的字段和分片的数量成正比,因此还必须监控主节点上的堆使用情况 并确保它们的大小合适。

每个分片都有需要保存在内存中并使用堆空间的数据。 这包括在分片级别保存信息的数据结构,也包括在段级别以定义数据在磁盘上的位置。 这些数据结构的大小不是固定的,会因用例而异。

然而,与段相关的开销的一个重要特征是它与段的大小并不严格成比例。 这意味着与较小的段相比,较大的段具有更少的每个数据量的开销。 差异可能很大。

为了能够在每个节点上存储尽可能多的数据,管理堆使用并尽可能减少开销变得很重要。 节点拥有的堆空间越多,它可以处理的数据和分片就越多。

因此,从集群的角度来看,索引和分片并不是免费的,因为每个索引和分片都有一定程度的资源开销。

提示:小分片会导致小段,这会增加开销。 旨在将平均分片大小保持在至少几 GB 到几十 GB 之间。 对于具有基于时间的数据的用例,通常会看到大小在 20GB 到 40GB 之间的分片。

提示:由于每个分片的开销取决于段数和大小,因此通过 forcemerge 操作强制将较小的段合并到较大的段中可以减少开销并提高查询性能。 理想情况下,一旦没有更多数据写入索引,就应该这样做。 请注意,这是一项昂贵的操作,最好在非高峰时间执行。

提示:你可以在一个节点上持有的分片数量将与你可用的堆数量成正比,但 Elasticsearch 没有强制实施固定限制。 一个好的经验法则是确保将每个节点的分片数量保持在其配置的每 GB 堆的 20 以下。 因此,具有 30GB 堆的节点最多应该有 600 个分片,但越低于此限制,您可以保持它越好。 这通常会帮助集群保持良好状态。 (编者注:从 8.3 开始,我们大幅减少了每个分片的堆使用量,因此更新了本博客中的经验法则。请按照以下提示了解 8.3+ 版本的 Elasticsearch。

新提示数据节点上每个索引的每个字段允许 1kB 堆,加上开销
每个映射字段的确切资源使用取决于其类型,但经验法则是每个数据节点持有的每个索引允许每个映射字段大约 1kB 的堆开销。 你还必须为 Elasticsearch 的基线使用以及你的工作负载(例如索引、搜索和聚合)留出足够的堆。 0.5GB 的额外堆足以满足许多合理的工作负载,如果你的工作负载非常轻,你可能需要更少,而繁重的工作负载可能需要更多。

例如,如果一个数据节点拥有来自 1000 个索引的分片,每个索引包含 4000 个映射字段,那么你应该为字段留出大约 1000 4000 1kB = 4GB 的堆空间,并为其工作负载和其他开销留出另外 0.5GB 的堆空间,以及 因此该节点需要至少 4.5GB 的堆大小。

分片大小如何影响性能?

在 Elasticsearch 中,每个查询在每个分片的单个线程中执行。 然而,多个分片可以并行处理,针对同一个分片的多个查询和聚合也可以。

这意味着在不涉及缓存的情况下,最小查询延迟将取决于数据、查询类型以及分片的大小。 查询大量小分片会使每个分片的处理速度更快,但由于需要排队处理的任务更多,因此不一定比查询少量大分片更快。 如果有多个并发查询,拥有大量小分片也会降低查询吞吐量。

提示:从查询性能角度确定最大分片大小的最佳方法是使用真实数据和查询进行基准测试。 始终使用代表节点在生产中需要处理的查询和索引负载进行基准测试,因为针对单个查询进行优化可能会产生误导性结果。

如何管理分片大小?

使用基于时间的索引时,传统上每个索引都与固定时间段相关联。 每日索引非常常见,通常用于保存保留期短或每日量大的数据。 这些允许以良好的粒度管理保留期,并且可以轻松地根据每天的变化量进行调整。 保留期较长的数据,特别是如果每日数量不保证使用每日索引,通常使用每周或每月索引以保持分片大小。 随着时间的推移,这减少了需要存储在集群中的索引和分片的数量。

提示:如果使用覆盖固定时间段的基于时间的索引,请根据保留期和预期数据量调整每个索引覆盖的时间段,以达到目标分片大小。

当数据量可以合理预测并且变化缓慢时,具有固定时间间隔的基于时间的索引效果很好。如果索引率可以快速变化,则很难保持统一的目标分片大小。

为了能够更好地处理此类场景,引入了 Rollover 和 Shrink API。这些为索引和分片的管理方式增加了很大的灵活性,特别是对于基于时间的索引。

Rollover index API 可以指定索引应包含的文档数和/或应写入的最长文档周期。一旦超过其中一个标准,Elasticsearch 就可以触发创建新索引以进行写入,而无需停机。现在可以切换到特定大小的新索引,而不是让每个索引覆盖特定时间段,这使得可以更轻松地为所有索引实现均匀的分片大小。

在可能更新数据的情况下,使用此 API 时,事件的时间戳和它所在的索引之间不再有明显的链接,这可能会显着降低更新效率,因为每次更新之前可能需要进行搜索.

提示:如果你有基于时间的不可变数据,其中卷(volumes)可能随时间发生显着变化,请考虑使用 rollover index API 通过动态改变每个索引覆盖的时间段来实现最佳目标分片大小。 这提供了极大的灵活性,并且可以帮助避免在容量不可预测时拥有太大或太小的分片。

Shrink index API允许你将现有索引收缩为具有更少主分片的新索引。 如果在索引期间希望跨节点均匀分布分片,但这会导致分片太小,一旦索引不再被索引到,此 API 可用于减少主分片的数量。 这将产生更大的分片,更适合长期存储数据tgcode

提示:如果你需要让每个索引覆盖特定的时间段,但仍希望能够将索引分散到大量节点,请考虑在索引不再被索引后使用收缩 API 减少主分片的数量 进入。 如果你最初配置的分片过多,此 API 还可用于减少分片的数量。

结论

这篇博文提供了有关如何在 Elasticsearch 中最好地管理数据的技巧和实用指南。 如果你有兴趣了解更多信息,“Elasticsearch:权威指南”包含有关规模设计的部分,尽管它有点旧,但仍然值得一读。

然而,关于如何在索引和分片之间最好地分布数据的许多决定将取决于用例的具体情况,有时很难确定如何最好地应用可用的建议。 如需更深入的个人建议,你可以通过订阅与我们进行商业合作,让我们的支持和咨询团队帮助你加速项目。 如果你乐于公开讨论你的用例,你还可以从我们的社区和我们的公共论坛获得帮助。

原文:How many shards should I have in my Elasticsearch cluster? | Elastic Blog

文章来源于互联网:Elasticsearch:我的 Elasticsearch 集群中应该有多少个分片?