当前位置: 首页 > 科技观察

在生产环境中运行Elasticsearch的深度指南

时间:2023-03-22 01:49:16 科技观察

在这篇文章中,我并不是要告诉您Elasticsearch强大、快速并且几乎可以工作。在这篇文章中,我还要告诉您,Elasticsearch可能无缘无故地不透明、令人困惑和崩溃。在本文中,我想分享有关如何正确配置Elasticsearch并避免常见陷阱的经验和技巧。我写文章也不是为了赚钱,所以我打算把整篇文章放在一篇文章里,而不是分成一系列。不感兴趣的章节可以跳过。基础知识:集群、节点、索引和分片如果您是Elasticsearch(ES)的新手,我想先解释一些基本概念。本节根本不涉及最佳实践,主要侧重于解释术语。大部分人可以直接跳过这一段。Elasticsearch是一个用于运行ApacheLucene(基于Java的搜索引擎)的分布式管理框架。Lucene是数据实际保存、索引和搜索的地方。ES位于其之上,允许您并行运行数千个Lucene实例。ES的最高层单元是集群。集群是ES节点和索引的集合。节点(Node)是ES的一个实例。可以是单台服务器,也可以是服务器上运行的ES进程。服务器不同于节点。一个VM或者物理服务器可以包含很多个ES进程,每个ES进程就是一个节点。节点只能加入一个集群。有不同类型的节点,最值得注意的两种类型是数据节点和符合主节点条件的节点。一个节点可以同时有多种类型。数据节点运行所有数据操作,即存储、索引和检索数据。master候选节点有投票master的权限,用于管理集群和索引。索引(Index)是数据的高级抽象。索引本身不保存数据,它们只是实际存储数据的另一种抽象。任何对数据进行的插入、删除、索引、查找等操作都会对索引产生影响。一个索引可以完全属于一个集群,由分片组成。分片是ApacheLucene的实例。一个分片可以容纳很多文件。分片是存储、索引和搜索数据的实际对象。一个分片只属于一个节点和索引。有两种类型的分片:主分片和副本分片,它们基本相同,具有相同的数据,并且在所有分片中并行运行搜索。在所有具有相同数据的分片中,其中一个属于主分片。这是唯一可以接受索引请求的分片。如果节点中的主分片死亡,副本将接管并成为主分片。然后ES将创建一个新的副本并复制数据。综上所述,我们整理了下图:深入了解Elasticsearch如果你要跑一个系统,我相信你需要了解这个系统。在本节中,我将解释Elasticsearch的各个部分,我认为如果您想在生产环境中对其进行管理,您需要了解这些部分。本节也不涉及具体的推荐,后面会介绍。该程序仅旨在提供必要的背景知识。Quorum必须了解Elasticsearch是一个(有缺陷的)选举系统。节点投票决定谁应该管理它们,即主节点。主节点运行着大量的集群管理进程,在很多事情上拥有最终的决策权。ES选举存在缺陷,因为只有一小部分节点(符合主节点资格的节点)具有投票权。通过如下配置启用master候选节点:node.master:true当集群启动或master节点离开集群时,所有满足master选举条件的节点将开始选举新的master节点。为此,你需要有2n+1名硕士候选人。否则可能会出现脑裂情况,比如两个节点同时获得50%的选票,这会导致两个分区之一的所有数据丢失。为了不让这种情况发生。你需要2n+1个有资格成为master候选者的节点。节点如何加入集群当ES节点启动时,它单独存在于广阔的世界中。它怎么知道它属于哪个集群?有不同的方法可以做到这一点,现在主要使用种子宿主方法。基本上,Elasticsearch节点不断地谈论他们看到的所有其他节点。所以一个节点最初只需要了解其他几个节点就可以了解整个集群。让我们看一个三节点集群的例子:初始状态最初,节点A和C只知道B。B是种子主机。种子主机要么以配置文件的形式提供给ES,要么直接放在elasticsearch.yml中。节点A与B连接并交换信息一旦节点A连接到B,B就知道A存在。对于A,没有任何变化。节点C与B连接并共享信息现在,C已连接。一旦发生这种情况,B就告诉CA存在。C和B现在知道集群中的所有节点。一旦A重新连接到B,它也会知道C的存在。分段和分段合并我在上面说过数据存储是分片的,这只是部分正确。最终数据以文件的形式存储在文件系统中。在Lucene和Elasticsearch中,这些文件称为段。一个分片将有一个到数千个片段。同样,段是实际的真实文件,您可以在Elasticsearch安装的数据目录中查看这些文件。这意味着使用段会产生开销。如果你想看到一个段,你必须找到文件并打开它。这意味着需要打开很多文件,会有很多开销。Lucene中的段是不可变的,这是一个问题。它们只能写入一次,然后不能更改。反过来,这意味着您放入ES的每个文档都将创建一个仅包含该文档的段。显然,一个有十亿个文档的集群有十亿个段,这意味着文件系统上确实有十亿个文件,对吧?没有。在幕后,Lucene进行连续的段合并,它不能更改段,但它可以使用两个较小段的数据合并来创建新的段。通过这种方式,lucene不断尝试保持段数(文件数,即开销)较小。您也可以使用强制合并。消息路由在Elasticsearch中,您可以在集群中的任何节点上运行任何命令,结果都是相同的。有趣的是,文档最终只会存在于一个主分片及其副本中,而ES不知道它在哪里。没有文档在哪个分片的映射。当执行搜索时,收到请求的ES节点将它广播到索引中的所有分片。即主分片和所有副本。然后在包含文档的所有段中查找这些碎片。执行插入时,ES节点将随机选择一个主分片并??将文档放置在那里。然后将其写入该主分片及其所有副本。如何在生产环境运行Elasticsearch?这部分是实践部分。前面说了,我管理ES的主要目的是为了记录日志。本文将尽量避免这种倾向的影响,但可能会失败。尺码需要提出并自行回答的第一个问题是关于尺码。您需要多大的ES集群?内存我首先谈论RAM,因为RAM会限制所有其他资源。HeapES是Java写的,Java使用堆,你可以认为是Java保留内存。列出堆的所有重要因素将使本文档的大小增加三倍,因此我将介绍最重要的部分,即堆大小。尽可能多的使用内存,但是堆大小不要超过30G。堆有一个很多人不知道的秘密:堆中的每一个对象都需要一个唯一的地址,也就是对象指针。这个地址的长度是固定的,也就是说可以寻址的对象数量是有限的。一种简单的描述方式是,超出一定范围,Java将开始使用压缩对象指针,而不是未压缩对象指针。这意味着每次内存访问都将涉及额外的步骤,这会严重降低速度。所以你100%不需要设置超过这个阈值(大约32G)。我曾经在一个黑暗的房间里度过了整整一周,除了使用esrally在文件系统、堆大小、文件和BIOS设置的不同组合上对Elasticsearch进行基准测试。长话短说,堆大小的设置方式如下:添加索引延迟,越低越好命名约定为fs_heapsize_biosflags。如您所见,从32G的堆大小开始,性能突然开始下降。吞吐量也是如此:indexappendmedian吞吐量。越高越好。长话短说:如果你想幸运的话,获得29G或30G的RAM,使用XFS,并在可能的情况下启用hardwareprefetch和llc-prefetch。文件缓存大多数人在Linux上运行Elasticsearch,它使用内存作为文件系统缓存。一个普遍的建议是ES服务器使用64G内存,想法是一半用于缓存,一半用于堆。我还没有测试文件缓存。但是不难看出,大型ES集群(例如用于日志记录)可以从配置大型文件缓存中受益匪浅。如果您的所有索引都适合内存堆,那么好处就不多了。CPU这取决于在集群上执行的操作。如果你正在做大量的索引工作,你将需要比仅仅做日志记录更多更快的CPU。对于日志记录,我发现8个CPU内核绰绰有余,但发现很多人使用更大的配置,但这对他的用例没有好处。磁盘并没有想象中的那么简单。首先,如果索引适合RAM,则磁盘仅在节点冷启动时才重要。其次,可以存储的实际数据量取决于索引布局。每个分片都是一个Lucene实例,它们都有内存需求。这意味着堆中可以容纳的最大分片数量是有限制的。我在索引布局部分对此进行了更详细的讨论。通常,您可以将所有数据盘都放入RAID0。您需要在Elasticsearch级别进行复制,因此丢失一个节点并不重要。不要将LVM与多个磁盘一起使用,因为LVM一次只能写入一个磁盘,根本没有提供多个磁盘的好处。关于文件系统和RAID设置,我整理了以下内容:调度器:cfq和deadline优于noop。如果你有nvme,Kyber可能没问题,但我没有测试它QueueDepth:尽可能高提前阅读:请打开Raidchunksize:对FS没有影响Chunksize:对FS没有影响Type:XFS>ext4indexlayout这在很大程度上取决于您的用例。我只能从日志记录场景(尤其是使用Graylog)来讨论这个问题。ShardingLite:对于写重的工作负载,主分片=节点数对于读重的工作负载,主分片*副本数=节点数更多的副本=更高的搜索性能可以通过以下公式给出最大写入性能:node_throughput*number_of_primary_shardsnodethroughput*numberofprimaryshards节点吞吐量*numberofprimaryshards原因很简单:如果只有一个primaryshards,写入速度只和单节点差不多,因为一个shard只能在一个节点上.如果真的要优化写入性能,应该保证每个节点上只有一个分片(主分片或副本分片),因为在这种情况下从分片可以获得与主分片相同的写入速度,写入很大程度上取决于磁盘IO。注意:如果索引很多,那么上述策略可能会出现问题,性能瓶颈可能是其他原因。如果要优化搜索性能,可以通过以下公式给出:)对于搜索来说,primaryShards和replicas基本是一样的。因此,如果要提高搜索性能,只需增加副本数即可。大小我已经多次讨论过索引大小。以下是我的经验:30Gofheap=140shardsmaximumpernode30G堆内存=一个节点最多可以启动140个分片。如果您使用超过140个分片,Elasticsearch进程将崩溃并出现内存不足的错误。这是因为每个分片都是一个Lucene实例,每个实例都需要一定的内存。这意味着每个节点可以拥有的分片数量是有限制的。如果你有大量的节点、分片和索引大小,可以容纳多少个索引可以通过以下公式计算:number_of_indices=(140*number_of_nodes)/(number_of_primary_shards*replication_factor)indexnumber=(140*nodenumber)/(primaryscoreNumberNumberofslice*replicationfactor)根据磁盘的大小,很容易计算出索引的大小:index_size=(number_of_nodes*disk_size)/number_of_indicesIndexsize=(nodesnumber*disksize)/Number索引但是,索引越大,搜索越慢。对于日志记录来说,慢一点是可以的,但是对于真正需要大量搜索的应用程序,索引大小应该根据RAM大小来调整。段合并每个段都是文件系统中的一个实际文件,段越多意味着读取开销越大。基本上,对于每个搜索查询,它会转到索引中的所有分片,然后转到分片中的所有段。多个段会大大增加集群读取IOPS,直到它变得不可用。因此,有必要尽可能地减少段数。force_mergeAPI允许您将段合并到一定数量,比如1。如果您执行索引翻转(例如,使用Elasticsearch进行日志记录),建议在集群未使用时执行常规强制合并。强制合并是资源密集型的,会显着降低集群的速度。所以最好不要让Graylog帮你做,而是选择自己做,集群时间少。如果您有很多索引,则必须定期执行段合并。否则,集群将运行非常缓慢并最终死亡。集群布局对于除最小设置之外的所有设置,最好使用专门的主候选。主要是为了保证总有2n+1个候选主节点来保证法定人数。但是有了数据节点,可以随时添加新的节点,不用担心这个需求。此外,我们不希望数据节点上的高负载影响主节点。最后,主节点是种子节点的理想候选者。请记住,种子节点是在Elasticsearch中进行节点发现的最简单方法。由于主节点很少更改,因此它是最佳选择,因为它很可能已经知道集群中的所有其他节点。主节点可以很小。一个CPU内核和4GRAM足以满足大多数集群的需求。当然,你也需要注意实际的使用情况,并做出相应的调整。MonitoringES为你提供了大量的metrics,所有的metrics都以JSON的形式提供,这样可以非常方便的传递给监控工具。下面是一些有用的监控指标:段数HeapusageHeapGCTimeaveragesearch,index,mergetimeIOPSDiskutilization结论这篇文章花了我大约5个小时,包含了我对ES的所有了解,希望你能遇到它Lessofa一提到问题就头疼。资源https://www.elastic.co/guide/zh-CN/elasticsearch/reference/current/modules-node.htmlhttps://www.elastic.co/guide/en/elasticsearch/reference/master/modules-discovery-quorums.htmlhttps://github.com/elastic/rallyhttps://tech.ebayinc.com/engineering/elasticsearch-performance-tuning-practice-at-ebay/