使用bulk请求
批量请求将比单文档索引请求产生更好的性能。为了知道批量请求的最佳大小,您应该在具有单个分片的单个节点上运行基准测试。首先尝试一次索引 100 个文档,然后是 200,然后是 400,等等。在每次基准测试中,批量请求中的文档数量加倍。当索引速度开始趋于平稳时,您就知道已达到数据批量请求的最佳大小。需要注意的是,当许多请求同时发送时,过大的bulk请求可能会使集群承受内存压力,因此建议避免每个请求超过几十兆字节,即使较大的请求似乎性能更好。
使用多线程发送数据到Elasticsearch
发送bulk请求的单个线程不太可能最大化 Elasticsearch 集群的索引容量。为了使用集群的所有资源,您应该从多个线程或进程发送数据。除了更好地利用集群的资源之外,这应该有助于降低每个 fsync 的成本。
确保注意TOO_MANY_REQUESTS (429)响应代码(EsRejectedExecutionException使用 Java 客户端),这是 Elasticsearch 告诉您无法跟上当前索引速率的方式。当它发生时,您应该在再次尝试之前暂停索引,最好使用随机指数退避。
与调整批量请求的大小类似,只有测试才能判断最佳工作线程数量是多少。这可以通过逐渐增加工作线程的数量来测试,直到集群上的 I/O 或 CPU 饱和。
增加刷新(refresh)间隔
默认index.refresh_interval值为1s,这会强制 Elasticsearch 每秒创建一个新段。增加这个值(比如,30s)将允许更大的段刷新并降低未来的合并压力。
在初始加载时禁用刷新和副本
如果需要一次性加载大量数据,则应通过设置index.refresh_interval为-1和 设置index.number_of_replicas 为0来禁用刷新。这将暂时使您的索引处于危险之中,因为任何分片的丢失都会导致数据丢失,但同时索引会更快,因为文档只会被索引一次。初始加载完成后,您可以设置index.refresh_interval并index.number_of_replicas返回其原始值。
禁用内存交换(swap)
您应该通过禁用 swapping来确保操作系统不会换出 java 进程。
为文件系统缓存提供内存
文件系统缓存(filesystem cache)将用于缓冲 I/O 操作。您应该确保至少将运行 Elasticsearch 的机器的一半内存分配给文件系统缓存。
使用自动生成ID
在索引具有显式 id 的文档时,Elasticsearch 需要检查具有相同 id 的文档是否已存在于同一个分片中,这是一项代价高昂的操作,并且随着索引的增长而变得更加昂贵。通过使用自动生成的 id,Elasticsearch 可以跳过此检查,从而加快索引速度。
使用更快的硬件
如果索引受 I/O 限制,您应该研究为文件系统缓存提供更多内存或购买更快的硬盘。特别是 SSD 硬盘的性能比机械磁盘更好。始终使用本地存储,远程文件系统,例如NFS或SMB应避免使用。还要注意虚拟化存储,例如 Amazon 的Elastic Block Storage. 虚拟化存储与 Elasticsearch 配合得非常好,它很吸引人,因为它设置起来如此快速和简单,但不幸的是,与专用本地存储相比,它在持续的基础上本质上更慢。如果您将索引放在EBS上,请确保使用预配置的 IOPS,否则操作可能会很快受到限制。
通过配置 RAID 0 阵列,跨多个 SSD 对索引进行优化。请记住,它会增加失败的风险,因为任何一个 SSD 的故障都会破坏索引。然而,这通常是正确的权衡:优化单个分片以获得最大性能,然后跨不同节点添加副本,以便为任何节点故障提供冗余。您还可以使用快照和还原来备份索引以进一步增强数据安全性。
索引缓冲区的大小
如果您的节点仅执行大量索引,请确保 indices.memory.index_buffer_size足够大,以便为每个分片提供最多 512 MB 的索引缓冲区进行大量索引(除此之外,索引性能通常不会提高)。Elasticsearch 采用该设置(Java 堆的百分比或绝对字节大小),并将其用作所有活动分片的共享缓冲区。非常活跃的分片自然会比执行轻量级索引的分片更多地使用此缓冲区。
默认值10%通常是充足的:例如,如果您给 JVM 10GB 的内存,它将为索引缓冲区提供 1GB,这足以承载两个大量索引的分片。
禁用_field_names
该_field_names字段引入了一些索引时间开销,因此如果您永远不需要运行exists查询,您可能希望禁用它。
强制合并(merge)
Elasticsearch 中的索引存储在一个或多个分片中。每个分片都是一个 Lucene 索引,由一个或多个段组成——磁盘上的实际文件。更大的段对于存储数据更有效。
所述_forcemerge API可以用来减少每个碎片的段的数量。在许多情况下,可以通过设置将段数减少到每个分片一个max_num_segments=1。
Translog设置
对 Lucene 的更改仅在 Lucene 提交期间持久保存到磁盘,这是一项相对昂贵的操作,因此无法在每次索引或删除操作后执行。在进程退出或硬件故障的情况下,在一次提交之后和另一次提交之前发生的更改将被 Lucene 从索引中删除。
由于Lucene的提交在执行上对每一个变化过于昂贵,每个分片副本也有一个事物日志称它为translog。所有的索引和删除操作都是在被内部Lucene索引处理之后,在没有被确认之前写入translog的。在发生崩溃的情况下,可以在分片恢复时从 translog 中恢复已确认但尚未包含在最后一次 Lucene 提交中的最近事务。
Elasticsearch 刷新(flush)是执行 Lucene 提交并开始新的 translog 的过程。刷新是在后台自动执行的,以确保 translog 不会变得太大,这将使得在恢复期间重放其操作不会需要相当长的时间。手动执行刷新的能力也通过 API 公开,尽管很少需要这样做。
translog 中的数据只有在 translog 被fsync 和 commit时才会持久化到磁盘 。如果发生硬件故障或操作系统崩溃或 JVM 崩溃或分片故障,自上次 translog 提交以来写入的任何数据都将丢失。
默认情况下,如果index.translog.durability设置为async,Elasticsearch每 5 秒 s 并提交一次 translog ,如果设置为request (默认),则在每个index、delete、 update或 bulk请求的末尾 fsync。更准确地说,如果设置为request,则 Elasticsearch 只会在 translog在主分片和副本上成功fsync并提交后,才会向客户端报告索引、删除、更新或bulk请求的成功 。
以下动态可更新的每个索引设置控制 translog 的行为:
index.translog.sync_interval 无论写操作如何,translog 被写入磁盘并提交的频率。默认为5s. 不允许小于100ms。
index.translog.durability 是否在每次索引、删除、更新或批量请求后提交 translog。此设置接受以下参数: request (默认)在每次请求后fsync并提交。在硬件故障的情况下,所有确认的写入都已经提交到磁盘。 async 每个sync_interval后fsync并提交. 如果发生故障,自上次自动提交以来的所有已确认写入都将被丢弃。
index.translog.flush_threshold_size translog 存储所有尚未安全持久化在 Lucene 中的操作(即,不是 Lucene 提交点的一部分)。尽管这些操作可用于读取,但如果要关闭分片并且必须恢复它们,则需要重新索引它们。此设置控制这些操作的最大总大小,以防止恢复时间过长。一旦达到最大大小,就会发生刷新,生成一个新的 Lucene 提交点。默认为512mb.
index.translog.retention.size 要保留的 translog 文件的总大小。保留更多的 translog 文件会增加在恢复副本时执行基于同步操作的机会。如果 translog 文件不足,副本恢复将回退到基于文件的同步。默认为512mb。
index.translog.retention.age translog 文件将被保留的最长时间。默认为12h.
|