【发布时间】:2020-02-20 19:46:59
【问题描述】:
当我通过一个批量请求将 200 个文档添加到 ElasticSearch 时 - 速度非常快。
但我想知道是否有机会通过并发执行来加快进程:20 个并发执行,每个执行 10 个文档。
我知道它效率不高,但也许有机会通过并发执行来加快进程?
【问题讨论】:
当我通过一个批量请求将 200 个文档添加到 ElasticSearch 时 - 速度非常快。
但我想知道是否有机会通过并发执行来加快进程:20 个并发执行,每个执行 10 个文档。
我知道它效率不高,但也许有机会通过并发执行来加快进程?
【问题讨论】:
对于批量文档插入,最好使用较低的并发性。一些并发在某些情况下是有帮助的——It Depends™,我会介绍它——但不是主要的或自动的胜利。
在写入 Elasticsearch 的性能方面,有很多可以调整的地方。您应该检查一个真正快速的胜利:您是否使用 HTTP keep-alive 进行连接?这将节省大量设置每个连接的 TCP 和 TLS 开销。仅此更改即可大幅提升性能,并为您的索引管道揭示一些有意义的架构考虑因素。
所以检查一下,看看它是怎么回事。从那里,我们应该走到底部,然后向上走。
磁盘上的索引是Lucene。 Lucene 是一个分段索引。 index 部分是您首先使用 Elasticsearch 的核心原因:可以在 O(log N) 时间内搜索排序术语的字典。这是超级快速和可扩展的。段部分是因为插入索引并不是特别快——根据您的实现,维护排序需要花费 O(log N) 或 O(N log N)。
所以 Lucene 的诀窍是缓冲这些更新并追加一个新段;本质上是迷你指数的集合。搜索一些相对少量的段仍然比每次更新都花时间维护排序索引要快得多。随着时间的推移,Lucene 会合并这些片段以将它们保持在合理的大小范围内,并在此过程中删除已删除和覆盖的文档。
在 Elasticsearch 中,每个分片都是一个不同的 Lucene 索引。如果您有一个带有单个分片的索引,那么拥有多个并发批量更新流几乎没有什么好处。应用程序端的并发可能有一些好处,具体取决于索引管道收集和组装每批文档所需的时间。但在 Elasticsearch 方面,这只是一组缓冲区被一个接一个地写入一个段。
分片让这变得更有趣。
Elasticsearch 的优势之一是能够跨多个分片分区索引数据。这有助于提高可用性,并有助于将工作负载扩展到单个服务器的资源之外。
唉,说并发性应该等于或成比例于索引拥有的主分片的数量并不是那么简单。虽然,作为一个粗略的启发式,这并不可怕。
您会看到,在内部,第一个处理请求的 Elasticsearch 节点会将批量请求转换为一系列单独的文档更新操作。每个文档更新都会发送到托管该文档所属分片的适当节点。响应由批量操作收集,以便它可以在响应中向客户端发送批量操作的摘要。
因此,此时,根据文档分片路由,在处理传入批量请求的过程中,某些分片可能比其他分片更忙。这可能很重要吗?我的直觉说不重要。这是可能的,但它是不寻常的。
在我见过的大多数测试和分析中,以及在我使用 Lucene 十多年的经验中,索引的缓慢部分是将文档的值转换为倒排索引格式。解析文本、将其分析为术语等可能非常复杂且成本高昂。只要批量请求有足够多的文档在分片之间分布得足够好,并发性就没有在分片和段级别完成的工作饱和那么有意义。
在调整批量请求时,我的建议是这样的。
持久队列可以解锁很多功能。如果可以获取和组装文档并将它们插入到 Kafka 中,那么该过程可以并行运行以使数据库饱和并并行化任何非规范化或文档准备。然后,一个不同的进程从队列中拉出并向服务器发送请求,并且通过一些轻微的协调,您可以在不同阶段测试和调整不同的并发。当有助于将集群置于只读模式一段时间时,队列还允许您暂停更新以进行各种迁移和维护任务。
我在整个答案中都避免了复制,因为我建议调整复制的原因只有一个。那就是当您批量创建不为任何生产流量提供服务的索引时。在这种情况下,它可以帮助通过您的服务器组节省一些资源,以关闭对索引的所有复制,并在索引基本上完成加载数据后启用复制。
要关闭,如果您无论如何都提高并发性怎么办?有什么风险?一些工作负载不控制并发性,并且没有时间或资源在搜索引擎前面放置队列。在这种情况下,Elasticsearch 可以避免相当大量的并发。它有相当大的线程池来处理并发文档更新。如果这些线程池已饱和,它将拒绝响应并带有 HTTP 429 错误消息和关于超出队列深度的明确消息。这些可能会影响集群的稳定性,具体取决于可用资源和索引中的分片数量。但这些都是非常引人注目的问题。
底线:不,相对于 1 个包含 200 个文档的批量,20 个并发批量(每个包含 10 个文档)可能不会提高性能。如果您的批量操作很快,您应该增加它们的大小,直到它们运行一两秒钟,或者出现问题。使用保活。如果还有其他应用程序端开销,请将并发性提高到 2 倍或 3 倍并根据经验进行测量。如果索引是关键任务,请使用快速、持久的队列。
【讨论】:
这个问题没有直接的答案,因为它取决于很多因素。超过最佳批量请求大小,性能不再提高,甚至可能下降。然而,最佳尺寸并不是一个固定的数字。
这完全取决于您的硬件、文档大小和复杂性,以及您的索引和搜索负载。
尝试以越来越大的批量索引典型文档。当性能开始下降时,您的批量太大了。
由于您是以 200 个批次为单位进行的,因此很有可能它应该是最佳的索引方式。但同样取决于上述因素。
【讨论】: