创建高吞吐量的Elasticsearch集群

时间:2019-03-08 09:21:33

标签: elasticsearch

我们正在将Elasticsearch作为我们组织中的搜索解决方案实施。对于POC,我们实现了一个3节点集群(每个节点具有16个VCore和60 GB RAM和6 * 375GB SSD),所有节点均充当主节点,数据节点和协调节点。由于这是POC索引速度,因此我们不打算考虑它是否可以工作。

  

注意:我们确实尝试在POC集群上索引2000万个文档,而这样做花了大约23-24小时,这迫使我们花费时间并使用适当的大小和设置来设计生产集群。

现在,我们正在尝试实现一个生产集群(在Google Cloud Platform中),同时强调索引速度和搜索速度。

我们的用例如下:

  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堆,但不超过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_interval设置为1m,以确保刷新频率较低。

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

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

  4. 我们愿意在GC中使用Concurrent CMSG1GC算法,但需要对此提供建议。我已经读过在同时使用和在使用中都会遇到的利弊。


现在是我的实际问题:

  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

1 个答案:

答案 0 :(得分:1)

  

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

令人惊讶的是,它几乎不到250 docs / s。我认为我的8GB RAM笔记本电脑可以在2小时内插入1300万份文档。您的文档非常复杂,设置不正确,或者瓶颈在摄取侧。

关于您的节点:我认为您可以通过减少主节点上的内存来轻松摆脱困境(例如32GB应该足够)。数据节点上的内存也很高。我通常希望堆相对于内存的其余部分为1:1或许多“热”数据可能为1:3。不确定会从1:7.5的比例中获得最大收益。

CMS vs 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个,然后等待其完成-尽管我以此为基准进行测试,如果这样做对整体有所帮助,并且值得增加复杂性。