首页 > 解决方案 > 创建高吞吐量 Elasticsearch 集群

问题描述

我们正在将 Elasticsearch 作为我们组织中的搜索解决方案实施。对于 POC,我们实施了一个 3 节点集群(每个节点有 16 个 VCore 和 60 GB RAM 和 6 * 375GB SSD),所有节点都充当主节点、数据节点和协调节点。因为它是 POC 索引速度不是考虑因素,我们只是想看看它是否会工作。

注意:我们确实尝试在我们的 POC 集群上索引 2000 万个文档,这需要大约 23-24 小时才能完成,这促使我们花时间设计具有适当大小和设置的生产集群。

现在我们正在尝试实现一个生产集群(在谷歌云平台中),同时强调索引速度和搜索速度。

我们的用例如下:

  1. 我们将为每个索引批量索引700 万到 2000 万个文档(我们为每个客户端设置 1 个索引,并且只有一个集群)。这个批量索引是一个每周的过程,即我们将对所有数据进行一次索引,并在刷新之前查询它整周。We are aiming for a 0.5 million document per second indexing throughput.

当我们增加更多客户时,我们也在寻找一种横向扩展的策略。我在后续章节中提到了该策略。

  1. 我们的数据模型具有嵌套文档结构和嵌套文档的大量查询,据我所知,这些查询是 CPU、内存和 IO 密集型的。We are aiming for sub second query times for 95th percentile of queries.

我在这个论坛和其他博客上进行了大量阅读,其中公司拥有成功运行的高性能 Elasticsearch 集群。

以下是我的学习:

  1. 有专用的主节点(总是奇数以避免脑裂)。这些机器可以是中型的(16 个 vCore 和 60 Gigs ram)。

  2. 将 50% 的 RAM 分配给 ES Heap,但堆大小不得超过 31 GB 以避免 32 位指针。我们计划在每个节点上将其设置为 28GB。

  3. 数据节点是集群的主力,因此 CPU、RAM 和 IO 必须很高。我们计划拥有(64 个 VCore、240 Gb RAM 和 6 * 375 GB SSD)。

  4. 也有协调节点来处理批量索引和搜索请求。


现在我们计划从以下配置开始:

3 Masters - 16Vcores, 60GB RAM and 1 X 375 GB SSD
3 Cordinators - 64Vcores, 60GB RAM and 1 X 375 GB SSD (Compute Intensive machines)
6 Data Nodes - 64 VCores, 240 Gb RAM and 6 * 375 GB SSDs

我们计划为每个传入的客户端添加 1 个数据节点。

现在由于硬件不在窗口中,让我们专注于索引策略。

我整理的几个最佳实践如下:

  1. 在大多数情况下,每个节点的分片数量越少越好,但在负载平衡的情况下,在所有节点之间具有良好的数据分布。由于我们计划从 6 个数据节点开始,我倾向于为第一个客户端提供 6 个分片以充分利用集群。
  2. 有 1 个复制以在节点丢失中幸存。

接下来是批量索引过程。我们有一个完整的 spark 安装,并将使用elasticsearch-hadoop连接器将数据从 Spark 推送到我们的集群。

  1. 在索引期间,我们将 设置refresh_interval1m以确保刷新频率较低。

  2. 我们正在使用 100 个并行 Spark 任务,每个任务发送2MB数据以进行批量请求。因此,有时会有2 * 100 = 200 MB大量请求,我认为这些请求完全在 ES 可以处理的范围内。我们绝对可以根据反馈或反复试验来更改这些设置。

  3. 我已经阅读了有关设置缓存百分比、线程池大小和队列大小设置的更多信息,但我们计划在开始时将它们保持为智能默认值。

  4. 我们愿意同时使用这两种方法Concurrent CMSG1GC算法来进行 GC,但在这方面需要建议。我已经阅读了使用这两种方法的利弊,以及使用哪一种的困境。


现在到我的实际问题:

  1. 将批量索引请求发送到协调节点是一个好的设计选择,还是我们应该将其直接发送到数据节点?

  2. 我们将通过协调节点发送查询请求。现在我的问题是,假设因为我的数据节点有 64 个内核,每个节点的线程池大小为 64,队列大小为 200。让我们假设在搜索数据节点线程池和队列大小完全耗尽期间,协调节点是否会继续接受和缓冲搜索请求,直到他们的队列也填满?或者每个查询请求也会阻止协调器上的 1 个线程?

假设一个搜索请求到达协调器节点,它在那里阻塞 1 个线程并将请求发送到数据节点,数据节点又根据查询数据所在的位置阻塞数据节点上的线程。这个假设正确吗?

  1. 当批量索引正在进行时(假设我们没有为所有客户端并行运行索引并安排它们是顺序的)如何进行最佳设计以确保在此批量索引期间查询时间不会受到太大影响。

参考

  1. https://thoughts.t37.net/designing-the-perfect-elasticsearch-cluster-the-almost-definitive-guide-e614eabc1a87

  2. https://thoughts.t37.net/how-we-reindexed-36-billions-documents-in-5-days-within-the-same-elasticsearch-cluster-cd9c054d1db8

  3. https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

标签: elasticsearch

解决方案


我们确实尝试在我们的 POC 集群上索引 2000 万个文档,并且花费了大约 23-24 小时

这是惊人的小——比如不到 250 文档/秒。我认为我的 8GB RAM 笔记本电脑可以在 2 小时内插入 1300 万份文档。要么你有非常复杂的文档、一些错误的设置,要么你的瓶颈在摄取方面。

关于你的节点:我认为你可以轻松地在主节点上使用更少的内存(比如 32GB 应该足够了)。数据节点上的内存也很高;我通常希望堆与内存的其余部分相关为 1:1,或者对于许多“热”数据可能为 1:3。不确定您能否充分利用 1:7.5 的比例。

CMS 与 G1GC:如果您有当前的 Elasticsearch 和 Java 版本,两者都是一个选项,否则 CMS。您通常会用吞吐量换取 (GC) 延迟,因此如果您进行基准测试,请确保有足够长的时间范围来正确达到 GC 阶段并尽可能地并行运行接近生产查询。

将批量索引请求发送到协调节点是一个好的设计选择,还是我们应该将其直接发送到数据节点?

我会说协调员很好。除非您使用自定义路由键并且批量仅包含该特定数据节点的数据,否则无论如何都需要将 5/6 的文档转发到其他数据节点(如果您有 6 个数据节点)。您可以将批量处理和协调处理卸载到非数据节点。但是,总体而言,拥有 3 个额外的数据节点并跳过专用的协调节点可能更有意义。尽管这是您只能通过对特定场景进行基准测试来确定的内容。

现在我的问题是,假设因为我的数据节点有 64 个内核,每个节点的线程池大小为 64,队列大小为 200。假设在搜索数据节点线程池和队列大小完全耗尽期间,协调节点是否会继续接受和缓冲搜索请求,直到他们的队列也填满?或者每个查询请求也会阻止协调器上的 1 个线程?

我不确定我是否理解这个问题。但是您是否查看过https://www.elastic.co/blog/why-am-i-seeing-bulk-rejections-in-my-elasticsearch-cluster,这可能会对这个主题有所了解?

当批量索引正在进行时(假设我们没有为所有客户端并行运行索引并安排它们是顺序的)如何进行最佳设计以确保在此批量索引期间查询时间不会受到太大影响。

虽然对于不同的查询操作有不同的队列,但没有明确的任务分离(例如“仅使用 20% 的资源用于索引)。可能对并行批量请求更加保守,以避免节点过载。

如果您在索引时没有从索引中读取(理想情况下,一旦完成就翻转别名):您可能希望完全禁用刷新率并让 Elasticsearch 根据需要创建段,但执行强制刷新并在完成后更改设置. 您也可以尝试在索引时使用 0 个副本运行,完成后将副本更改为 1,然后等待它完成 - 尽管我会进行基准测试,这是否有助于整体以及是否值得增加复杂性。


推荐阅读