生产环境elasticsearch的配置建议

原创
2017/12/18 19:04
阅读数 7.2K

以下主要来自官方文档,主要分为几块:

 

 

硬件方面

内存

首先最重要的资源是内存,排序和聚合都可能导致内存匮乏,因此足够的堆空间来容纳这些是重要的。即使堆比较小,也要给操作系统高速缓存提供额外的内存,因为Lucene使用的许多数据结构是基于磁盘的格式,Elasticsearch利用操作系统缓存有很大的影响。 
64GB RAM的机器是最理想的,但32GB和16GB机器也很常见。少于8GB往往适得其反(你最终需要许多,许多小机器),大于64GB可能会有问题,我们将在讨论在堆:大小和交换。

CPU

大多数Elasticsearch部署往往对CPU要求很不大。因此,确切的处理器设置比其他资源更重要,应该选择具有多个内核的现代处理器。通用集群使用2到8核机器。 
如果需要在较快的CPU或更多核之间进行选择,请选择更多核。 多核提供的额外并发将远远超过稍快的时钟速度。

硬盘

磁盘对于所有集群都很重要,尤其是对于索引很重的集群(例如摄取日志数据的磁盘)。 磁盘是服务器中最慢的子系统,这意味着大量写入的群集可以轻松地饱和其磁盘,这反过来成为群集的瓶颈。

如果你能买得起SSD,他们远远优于任何旋转磁盘。 支持SSD的节点看到查询和索引性能方面的提升。 
如果使用旋转磁盘,请尝试获取尽可能最快的磁盘(高性能服务器磁盘,15k转速驱动器)。 
使用RAID 0是提高磁盘速度的有效方法,适用于旋转磁盘和SSD。 没有必要使用RAID的镜像或奇偶校验变体,因为高可用性是通过副本建立到Elasticsearch中。 
最后,避免网络连接存储(NAS)。 NAS通常较慢,显示较大的延迟,平均延迟的偏差较大,并且是单点故障。

检查IO调度程序
如果使用SSD,请确保正确配置您的OS I/O调度程序。 当将数据写入磁盘时,I/O调度程序将确定该数据何时实际发送到磁盘。 大多数调度的默认值是名为cfq(Completely Fair Queuing)。
此调度程序为每个进程分配时间片,然后优化这些不同队列到磁盘的传递。 他是针对旋转磁盘介质的优化:旋转盘的性质意味着根据物理布局将数据写入磁盘更高效。
然而,这对于SSD是低效的,因为SSD不涉及磁盘旋转。 相反,应该使用deadline或noop。 deadline调度根据写入已经等待的时间进行优化,noop只是一个简单的FIFO队列。
这种简单的变化可以产生巨大的影响 我们已经看到,通过使用正确的调度程序,写入吞吐量提高了500倍。cat /sys/block/sda/queue/scheduler命令查看,修改参照http://www.nuodb.com/techblog/tuning-linux-io-scheduler-ssds
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

网络

快速和可靠的网络对于分布式系统中的性能显然是重要的。低延迟有助于确保节点可以轻松地进行通信,而高带宽有助于分段移动和恢复。现代数据中心网络(1GbE,10GbE)对于绝大多数集群都是足够的。 
避免跨越多个数据中心的群集,即使数据中心位置非常接近。绝对避免跨越大地理距离的集群。 
Elasticsearch集群假定所有节点相等,而不是一半的节点距离另一个数据中心中有150ms。较大的延迟往往会加剧分布式系统中的问题,并使调试和解决更加困难。 
与NAS参数类似,每个人都声称数据中心之间的管道是稳健的和低延迟。(吹牛)。从我们的经验,管理跨数据中心集群的麻烦就是浪费成本。

其他

现在可以获得真正巨大的机器如数百GB的RAM和几十个CPU内核。 另外也可以在云平台(如EC2)中启动数千个小型虚拟机。 哪种方法最好? 
一般来说,最好选择中到大盒子。 避免使用小型机器,因为您不想管理具有一千个节点的集群,而简单运行Elasticsearch的开销在这种小型机器上更为明显。 
同时,避免真正巨大的机器。 它们通常导致资源使用不平衡(例如,所有内存正在使用,但没有CPU),并且如果您必须为每台机器运行多个节点,可能会增加后期的运维复杂性。

操作系统

较大的文件描述符

Lucene使用了非常大量的文件。 并且Elasticsearch使用大量的套接字在节点和HTTP客户端之间进行通信。 所有这些都需要可用的文件描述符。 
可悲的是,许多现代的Linux发行版每个进程允许一个不允许的1024个文件描述符。 这对于一个小的Elasticsearch节点来说太低了,更不用说处理数百个索引的节点了。 
您应该将文件描述符计数增加到非常大的值,例如64,000。 这个过程是令人恼火的困难,高度依赖于你的特定操作系统和分布。 请查阅操作系统的文档以确定如何更改允许的文件描述符计数。 
可以使用http://ip:port/_nodes/stats接口process中的open_file_descriptors和max_file_descriptors进行查看。

设置MMap

Elasticsearch还针对各种文件使用NioFS和MMapFS的混合。 确保配置最大映射计数,以便有足够的虚拟内存可用于mmapped文件。 这可以临时设置

sysctl -w vm.max_map_count=655300

或者在/etc/sysctl.conf下永久设置vm.max_map_count。查看设置

cat /proc/sys/vm/max_map_count

管理工具

集群管理请使用集群管理工具(Puppet, Chef, Ansible)。配置管理工具通过自动化配置更改过程来帮助使您的集群一致,它可能需要一些时间来设置和学习,但随着时间的推移,会发现他是值得的。

JVM虚拟机

除非Elasticsearch网站上另有说明,否则应始终运行最新版本的Java虚拟机(JVM)。 Elasticsearch和Lucene都是比较苛刻的软件。 Lucene的单元和集成测试通常暴露JVM本身的错误。这些错误的范围可以从轻微的烦恼到严重的segfaults,所以最好是使用最新版本的JVM尽可能。 
Java8要好于Java7.Java6不再受支持。可以接受Oracle或OpenJDK。它们的性能和稳定性相当。 
如果您的应用程序是用Java编写的,并且正在使用传输客户端或节点客户端,请确保运行应用程序的JVM与服务器JVM相同。在Elasticsearch中的几个位置,使用Java的本机序列化(IP地址,异常等)。不幸的是,Oracle已知改变小版本之间的序列化格式,导致奇怪的错误。这种情况很少发生,但最佳做法是保持客户端和服务器之间的JVM版本相同。

请不要调整JVM设置

JVM暴露了几十个甚至数百个参数和配置。 它们允许您调整和调整JVM的几乎每个方面。但是建议不使用自定义JVM设置。 Elasticsearch是一个复杂的软件,目前的JVM设置已经调整了多年的实际使用。 
很容易调整参数,但是会产生难以测量的不透明效果,并最终使群集失去缓慢、不稳定,乃至混乱。 当调试集群时,第一步通常是删除所有自定义配置。 大约一半的时间,这个能恢复稳定性和性能。

请不要修改垃圾收集器

Elasticsearch的默认GC是并发标记和扫描(CMS)。此GC与应用程序的执行同时运行,以便它可以最小化暂停。但是,它有两个stop-world的阶段。它也是收集大堆的麻烦。 
尽管有这些缺点,它是目前最好的GC的低延迟服务器软件像Elasticsearch。官方建议是使用CMS。 
有一个更新的GC称为垃圾第一GC(G1GC)。这个较新的GC设计为最小化暂停甚至超过CMS,并在大堆上操作。它通过将堆分成区域并预测哪些区域包含最多的可回收空间来工作。通过首先收集这些区域(垃圾优先),它可以最小化停顿并在非常大的堆上操作。听起来不错,但不幸的是,G1GC仍然是新的,有很多新的bug。这些错误通常是segfault类型的,并将导致严重崩溃。 Lucene测试套件对GC算法是残酷的,看起来G1GC还没有解决这个问题。 
我们总有一天会推荐G1GC,但现在它不够稳定,不足以满足Elasticsearch和Lucene的需求。

给lucene留下一半的内存空间

一个常见的问题是配置一个太大的堆。你有一个64GB的机器,并且你想给Elasticsearch所有64GB的内存。更多更好?!堆对Elasticsearch绝对重要,它被许多内存数据结构使用以提供快速操作。但是还有另一个主要的内存用户是堆:Lucene。 
Lucene旨在利用底层操作系统来缓存内存中的数据结构。 Lucene段存储在单独的文件中,因为段是不可变的,所以这些文件从不改变。这使得它们非常易于缓存,并且底层操作系统将适合的保持segment驻留在内存中以便更快地访问。这些段包括反向索引(用于全文搜索)和docvalues(用于聚合)。Lucene的性能依赖于与操作系统的这种交互。但是如果你给Elasticsearch的堆提供所有可用的内存,Lucene就不会有任何剩余的内存。这会严重影响性能。 
标准建议是给Elasticsearch堆提供50%的可用内存,同时保留其他50%的空闲内存。它不会不使用; Lucene会愉快地吞噬剩下的任何东西。 
如果你不是聚合在分析的字符串字段(例如你不需要fielddata),你可以考虑降低堆更多。你可以做的堆越小,你可以期望从Elasticsearch(更快的GC)和Lucene(更多的内存缓存)更好的性能。

不要超过32G

事实证明,当堆大小小于32GB时,HotSpot JVM使用一个技巧来压缩对象指针。可以通过-XX:+PrintFlagsFinal来查看,在es2.2.0后不用设置,启动后会打印compressed ordinary object pointers [true] 
在Java中,所有对象都在堆上分配并由指针引用。Ordinary object pointers(OOP)指向这些对象,并且通常是CPU本地字的大小:32位或64位,取决于处理器。指针引用值的确切字节位置。 对于32位系统,这最大堆大小为4GB。对于64位系统,堆大小可以变得更大,但64位指针的开销意味着更多的浪费空间,因为指针更大。并且比浪费的空间更糟,当在主存储器和各种高速缓存(LLC,L1等)之间移动值时,较大的指针占用更多的带宽。 
Java使用一个名为compress oops的技巧来解决这个问题。指针不是指向存储器中的精确字节位置,而是引用对象偏移。这意味着32位指针可以引用四十亿个对象,而不是40亿字节。最终,这意味着堆可以增长到大约32 GB的物理大小,同时仍然使用32位指针。 
一旦你超越32GB边界,指针切换回Ordinary object pointers。每个指针的大小增加,使用更多的CPU内存带宽,并且您有效地丢失了内存。事实上,它需要直到大约40到50GB的分配的堆,你有一个堆的相同有效内存刚刚低于32GB使用压缩oops。所以即使你有内存,尽量避免跨越32 GB堆边界。它浪费内存,降低CPU性能,并使GC与大堆争夺。

避免过大的使用内存

32G这个临界值是相当重要的。但是如果你的机器有很多内存时,你改怎么?毕竟现在有512-768GB RAM的超级服务器变得越来越普遍。 
1、首先,我们建议避免使用这种大型机器(参见硬件)。但如果你已经有这种机器,则有两个实用的选择: 
你大部分是全文搜索吗?考虑给Elasticsearch提供4-32 GB,让Lucene通过操作系统文件系统缓存使用剩余的内存。所有的内存将缓存段,并导致令人惊异的快速全文搜索。你做了很多排序/聚合?大多数聚合是在数字,日期,geo_points和not_analyzed字符串?你很幸运!给Elasticsearch从4-32 GB的内存,并留下其余的操作系统缓存在内存中的文档值。 
2、你在分析的字符串上是否做了很多排序/聚合(例如word-tags 或者SigTerms等)?不幸的是,这意味着你需要fielddata,这意味着你需要堆空间。作为一个节点具有超过512GB的RAM的替换方案,请考虑在单个机器上运行两个或多个节点。仍然坚持50%的规则。因此,如果您的机器有128 GB的RAM,运行两个节点,每个节点只有32GB。这意味着少于64GB将用于堆内存,并且Lucene将剩余64GB以上。如果选择此选项,请在配置中设置

cluster.routing.allocation.same_shard.host:true

这将防止主分片和副本分片共同驻留到同一物理机器(因为这会移除副本高可用性的好处)。

swapping是性能的死穴

它应该是显而易见的,但它明确拼写出来:将主内存交换到磁盘会破坏服务器性能。 内存中操作是需要快速执行的操作。如果内存交换到磁盘,100微秒操作将花费10毫秒。 现在重复所有其他10us操作的延迟增加。 不难看出为什么交换对于性能来说是可怕的。 
1、最好的办法是在系统上完全禁用交换。 这可以临时完成:

sudo swapoff -a。

要永久禁用则需要编辑/etc/fstab。请查阅操作系统的文档。 
2、如果完全禁用交换不是一个选项,您可以尝试

sysctl vm.swappiness = 1(查看cat /proc/sys/vm/swappiness)

这个设置控制操作系统如何积极地尝试交换内存。 以防止在正常情况下交换,但仍然允许操作系统在紧急情况下交换。swappiness值1比0好,因为在一些内核版本上,swappiness为0可以调用OOM-killer。 
3、最后,如果两种方法都不可能,就应该启用mlockall。 这允许JVM锁定其内存,并防止它被操作系统交换。 可以在elasticsearch.yml中设置:

bootstrap.mlockall: true

ES参数配置

禁止调整线程池

每个人都喜欢调整线程池。无论什么原因,似乎人们不能抵抗增加线程数。索引很多?更多主题!很多搜索?更多主题!节点空闲95%的时间?更多主题! 
Elasticsearch中的默认线程池设置非常明智。对于所有线程池(除了搜索),threadcount设置为CPU核心数。如果你有八个内核,你只能同时运行八个线程。对任何特定的线程池只分配8个线程是有意义的。 
搜索获得更大的线程池,并配置为int((#of cores * 3)/ 2)+ 1。

1\你可能会认为某些线程可能阻塞(例如在磁盘I/O操作上),这就是为什么你需要更多线程。这不是Elasticsearch中的问题:大多数磁盘I/O由Lucene管理的线程处理,而不是Elasticsearch。 
2\此外,线程池通过在彼此之间传递工作来协作。你不需要担心网络线程阻塞,因为它正在等待磁盘写入。网络线程将很久以前将该工作单元交给另一个线程池,并返回到网络。 
3\最后,你的过程的计算能力是有限的。拥有更多的线程只是迫使处理器切换线程上下文。处理器每次只能运行一个线程,因此,当它需要切换到不同的线程时,它会存储当前状态(寄存器等)并加载另一个线程。如果你幸运,交换机将发生在同一个核心。如果你不幸运,交换机可能迁移到不同的核心,并且需要在核间通信总线上传输。这种上下文切换通过执行管理内务处理来完成周期;估计可以在现代CPU上高达30μs。因此,除非线程将被阻塞超过30μs,很可能这个时间将更好地用于只是处理和完成提前。 
人们通常将线程池设置为愚蠢的值。在8核机器上,我们运行的配置与60,100或甚至1000线程。这些设置将简单地破坏CPU比实际工作完成。 
所以下次你想调整一个线程池,请拒绝。如果你绝对不能抗拒,请记住你的核心数量,可以设置计数加倍。

设置集群和节点名称

Elasticseach默认情况下启动名为elasticsearch的集群。 明智的做法是将生产集群重命名为其名称,只是为了防止有人的笔记本电脑加入群集导致事故。 一个简单的名称更改可以省却大量烦恼。 
在elasticsearch.yml文件中更改

cluster.name: elasticsearch_production_name

同样的修改节点名称也是明智的选择,不需要es自动给你分配某些奇怪的名字,更加便于记忆;更重要的是避免重启之后又随机生成一个其他的名字,这会导致更多的不必要的问题。 
在elasticsearch.yml文件中更改

node.name: elasticsearch_005_data

设置路径

默认情况下,Elasticsearch会将插件、日志和最重要的数据放在安装目录中。 这可能会导致不幸的事故,由此安装目录会被新安装的Elasticsearch意外覆盖!!! 
最好的办法是将数据目录重定位到安装位置之外,当然也包括插件和日志目录。

path.data: /path/to/data1,/path/to/data2 #可以通过逗号指定多个目录存放 
path.logs: /path/to/logs 
path.plugins: /path/to/plugins

数据可以保存到多个目录,如果每个目录安装在不同的硬盘驱动器上,这就类似于软件方式实现了RAID0. Elasticsearch将自动在不同目录之间分条数据,提高性能。

设置minimum_master_nodes

minimum_master_nodes设置对群集的稳定性非常重要,这个设置有助于防止split brains(脑裂,在单个集群中存在两个主节点) 
一旦发生裂脑,集群就很可能会丢失数据。 因为master被认为是群集的最高统治者,所以它决定什么时候可以创建新的索引,如何移动碎片,等等。 如果你有两个master,数据完整性变得危险,因为这两个节点认为他们自己是负责人。 
这个设置是意思是告诉Elasticsearch不选择主节点,除非有足够的主节点可用节点。 只有这样,才会举行选举。

此设置应始终配置采用quorum原理,一般是(能够成为master的节点数/ 2)+ 1.这里有一些示例: 
1、如果你有10个常规节点(可以保存数据,可以成为主机),quorum为6。 
2、如果您有3个专用主节点和一百个数据节点,则quorum为2,因为您只需要统计只有符合主节点的节点。 
3、如果你有两个常规节点,你是在一个难题。 quorum将为2,但这意味着一个节点的丢失将使您的集群不可操作。 设置为1将允许您的群集运行,但不能防止裂脑。 在这种情况下最好有至少三个节点。 
此设置可以在elasticsearch.yml文件中配置:discovery.zen.minimum_master_nodes: 2 (每个节点都需要配置并且一致) 
当然也可以通过动态API调用进行配置。 您可以在群集联机时更改设置:

PUT /_cluster/settings
{
    "persistent" : {
        "discovery.zen.minimum_master_nodes" : 2
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

设置recover settings

先了解没有设置的情况下es是怎么工作的。 
假设您有十个节点,每个节点在5个主/1副本索引中保存单个分片(主分片或副本)。当您重新启动集群时,由于某种原因,你只有五个节点在线。这五个节点将彼此通信,选择一个master并形成一个集群。他们注意到数据不再均匀分布,因为集群中缺少五个节点,并且立即开始在彼此之间复制新的碎片。一段时间之后,其他五个节点打开并加入群集。这些节点看到它们的数据被复制到其他节点,因此它们删除它们的本地数据(因为它现在是冗余的,并且可能已过时)。然后集群开始重新平衡,因为集群大小刚刚从五到十。在整个过程中,您的节点正在颠簸磁盘和网络,移动数据。对于具有TB级数据的大型集群,这种无用的数据混洗可能需要很长时间。如果所有节点只是等待集群联机,所有数据都将是本地的,则不需要移动。 
现在我们有一些设置, 
1、首先设置gateway.recover_after_nodes: 8 ,这将阻止Elasticsearch在至少存在8个(数据或主节点)节点之前开始恢复,这意味着集群少于8个节点时不可操作。 
2、其次我们告诉Elasticsearch集群中应该有多少个节点gateway.expected_nodes: 10,以及我们要等待所有这些节点多长时间gateway.recover_after_time: 5m。 
这些设置之后,这意味着Elasticsearch将执行以下操作: 
1、等待8个节点启动 
2、5分钟后或十个节点加入群集后开始恢复,两者策略满足其一即可。 
这三个设置允许您避免在群集重新启动时可能发生的过多分片交换。 它可以字面上使恢复需要几秒钟而不是几个小时。

比起multicast更倾向于unicast

Elasticsearch默认使用unicast discovery,以防止节点意外加入集群。 
虽然multicast仍然作为插件提供,但不应在生产中使用。 最后一件事是让节点偶然加入您的生产网络,只是因为他们收到了错误的组播ping。 multicast本身没有什么问题,但是会导致愚蠢的问题,并可能有点脆弱(例如,网络工程师在瞎搞网络并且没有告诉你,可能会突然导致多有的节点不能再找到彼此)。 
要使用单播,请向Elasticsearch提供应尝试联系的节点的列表。 当节点联系单播列表的成员时,它接收列出集群中所有节点的完整集群状态。 然后它联系主机并加入群集。 
这意味着您的单播列表不需要包括集群中的所有节点。 它只需要足够的节点,一个新的节点可以找到有人谈话。 
如果你使用专用的主人,只需列出你的3个专用的master。 设置如下:

discovery.zen.ping.unicast.hosts: [“host1”, “host2:port”]

展开阅读全文
加载中

作者的其它热门文章

打赏
0
3 收藏
分享
打赏
0 评论
3 收藏
0
分享
返回顶部
顶部