调优索引速度
Elasticsearch 提供了广泛的索引性能优化方案,这对于高吞吐量的数据导入工作负载尤其有用。本页提供了实用的建议,帮助您最大化索引速度,从批量大小和刷新间隔到硬件和线程管理。
索引性能还受分片和索引策略的影响。无论您是写入单个索引还是并行写入数百个索引,以及每个索引包含多少个分片,都会显著影响索引速度。
在调整索引速度时,请务必同时考虑集群的分片数量、索引布局和整体数据分布。有关分片策略和建议的更多详细信息,请参阅 调整分片大小。
批量请求的性能远优于单文档索引请求。为了解批量请求的最佳大小,您应该在带有单个分片的单节点上运行基准测试。首先尝试一次索引 100 个文档,然后是 200 个、400 个等,在每次基准测试运行中将批量请求中的文档数量加倍。当索引速度开始趋于平稳时,您就知道已达到适合您数据的批量请求最佳大小。如果难以抉择,最好倾向于文档数量稍少而不是稍多。请注意,当并发发送大量过大的批量请求时,可能会给集群带来内存压力,因此建议即使更大的请求性能更好,每个请求的大小也不要超过几十兆字节。
在 Elastic Cloud Serverless 中,单个批量索引请求的最小响应时间为 200 毫秒。
仅由单个线程发送批量请求不太可能充分利用 Elasticsearch 集群的索引能力。为了充分利用集群的所有资源,您应该通过多个线程或进程发送数据。除了更好地利用集群资源之外,这还有助于降低每次 fsync 的开销。
另一方面,从过多并发线程或进程向单个分片发送数据可能会使集群不堪重负。如果索引负载超过了 Elasticsearch 的处理能力,它可能会成为瓶颈并开始拒绝请求或降低整体性能。
请务必注意 TOO_MANY_REQUESTS (429) 响应代码(Java 客户端的 EsRejectedExecutionException),这是 Elasticsearch 告诉您它无法跟上当前索引速率的方式。发生这种情况时,您应该暂停索引一会儿再重试,最好使用随机指数退避。
与确定批量请求大小类似,只有通过测试才能知道最佳的工作线程数是多少。可以通过逐步增加工作线程数来进行测试,直到集群上的 I/O 或 CPU 饱和为止。
使更改对搜索可见的操作(称为 refresh)成本很高,如果在有持续索引活动的同时频繁调用它,会损害索引速度。
默认情况下,Elasticsearch 每秒定期刷新一次索引,但仅针对在过去 30 秒内收到过一次或多次搜索请求的索引。
如果您没有搜索流量或搜索流量极少(例如每 5 分钟少于一次搜索请求)并希望针对索引速度进行优化,这是最佳配置。此行为旨在当没有执行搜索时,在默认情况下自动优化批量索引。若要退出此行为,请显式设置刷新间隔。
另一方面,如果您的索引会经历规律的搜索请求,则此默认行为意味着 Elasticsearch 将每 1 秒刷新一次您的索引。如果您能容忍增加文档被索引与它变得可见之间的时间间隔,则将 index.refresh_interval 增加到更大的值(例如 30s)可能会有助于提高索引速度。
为了在大型批量操作期间最大化索引性能,您可以通过将刷新间隔设置为 -1 来禁用刷新。这可以防止 Elasticsearch 在批量索引过程中执行任何刷新。
要禁用刷新间隔,请运行以下请求
PUT /my-index-000001/_settings
{
"index" : {
"refresh_interval" : "-1"
}
}
在禁用刷新的同时,您新索引的文档将对搜索操作不可见。仅在批量索引完成且您需要数据可搜索之后,才重新启用刷新。
要恢复刷新间隔,请使用您期望的值运行以下请求
PUT /my-index-000001/_settings
{
"index" : {
"refresh_interval" : "5s"
}
}
- 对于 Elastic Cloud Serverless 部署,
refresh_interval必须为-1,或者大于等于5s
批量索引完成后,考虑运行 force merge 来优化搜索性能。强制合并在 Elastic Cloud Serverless 上不可用。
POST /my-index-000001/_forcemerge?max_num_segments=5
强制合并是一项开销很大的操作。
如果您有大量数据想要一次性加载到 Elasticsearch 中,将 index.number_of_replicas 设置为 0 可能会有利于加速索引。没有副本意味着丢失单个节点可能会导致数据丢失,因此确保数据在其他地方也存在是很重要的,以便在出现问题时可以重试此初始加载。初始加载完成后,您可以将 index.number_of_replicas 恢复为其原始值。
如果在索引设置中配置了 index.refresh_interval,在此初始加载期间取消设置它,并在初始加载完成后将其设置回其原始值,可能会进一步有所帮助。
您应确保操作系统不会通过 disabling swapping 将 java 进程换出。
文件系统缓存用于缓冲 I/O 操作,在 Elasticsearch 性能中起着至关重要的作用。您应确保将系统内存的至少一半分配给文件系统缓存。
默认情况下,Elasticsearch 会自动设置其 JVM heap size 以遵循此最佳实践。但是,在自管理或 Elastic Cloud on Kubernetes 部署中,您可以灵活地为文件系统缓存分配更多内存。
虽然文件系统缓存主要有利于搜索工作负载,但在某些场景下它也可以提高索引速度——尤其是当写入许多分片或执行涉及读取现有数据的频繁段合并时。
在 Linux 上,文件系统缓存使用应用程序未积极使用的任何内存。要为缓存分配内存,请确保有足够的系统内存保持可用,且未被 Elasticsearch 或其他进程消耗。
在索引具有显式 ID 的文档时,Elasticsearch 需要检查同一分片内是否已存在具有相同 ID 的文档,这是一项开销很大的操作,并且随着索引的增长开销会更大。通过使用自动生成的 ID,Elasticsearch 可以跳过此检查,从而加快索引速度。
如果索引受 I/O 限制,请考虑增加文件系统缓存的大小(见上文)或使用更快的存储。Elasticsearch 通常通过顺序写入来创建单独的文件。但是,索引涉及并发写入多个文件,并且还混合了随机和顺序读取,因此 SSD 驱动器的性能通常比机械硬盘更好。
通过配置 RAID 0 阵列将您的索引条带化跨越多个 SSD。请记住,这会增加故障风险,因为任何一个 SSD 的故障都会破坏索引。然而,这通常是正确的权衡:优化单个分片以获得最高性能,然后在不同节点之间添加副本,以便为任何节点故障提供冗余。您还可以使用 snapshot and restore 来备份索引以获得更多保障。
在 Elastic Cloud Hosted 和 Elastic Cloud Enterprise 中,您可以通过选择不同的硬件配置文件或部署模板来选择底层硬件。有关更多详细信息,请参阅 ECH > 管理硬件配置文件 和 ECE > 管理部署模板。
使用直接附加(本地)存储的 Elasticsearch 集群通常比使用远程存储的集群性能更好。直接存储通常为 I/O 操作提供更低的延迟,对于大多数 Elasticsearch 工作负载而言,这比远程存储通常可以实现的高吞吐量更为关键。
某些远程存储的性能非常差,尤其是在 Elasticsearch 施加的那种负载下。但是,在某些工作负载下并通过仔细调整,有时也可以使用远程存储获得可接受的性能。在确定特定的存储架构之前,请使用真实的工作负载对您的系统进行基准测试,以确定它是否能满足您的性能目标。如果您无法达到预期的性能,请与存储系统的供应商合作以确定合适的调优参数值。
对于 Elastic Cloud on Kubernetes 部署,请参考 ECK 存储建议 以全面了解 Kubernetes 中的存储选项及其影响和最佳实践。在 Kubernetes 中,远程存储解决方案非常常用且受支持良好。
如果您的节点仅执行大量索引操作,请确保 indices.memory.index_buffer_size 足够大,可以为每个执行大量索引的分片提供最多 512 MB 的索引缓冲区(超出此大小,索引性能通常不会提升)。Elasticsearch 采用该设置(Java 堆的百分比或绝对字节大小),并将其作为所有活动分片之间的共享缓冲区。非常活跃的分片自然会比执行轻量级索引的分片更多地使用此缓冲区。
默认值为 10%,这通常绰绰有余:例如,如果您给 JVM 分配 10GB 内存,它将给索引缓冲区分配 1GB,这足以容纳两个进行大量索引的分片。
在单个集群中,索引和搜索会争夺资源。通过设置两个集群,配置 cross-cluster replication 将数据从一个集群复制到另一个集群,并将所有搜索路由到具有 follower 索引的集群,搜索活动将不再抢占托管 leader 索引的集群上的索引资源。
当节点资源、分片或请求分布不均时,可能会发生 Hot Spotting。Elasticsearch 通过在节点之间同步集群状态来维护集群状态,因此持续出现热点的节点会导致整体集群性能下降。
调整磁盘使用率中概述的许多策略也有助于提高索引速度。