Elasticsearch 集群优化篇

Elasticsearch 集群优化篇java

这篇文章的做者很认真,分析的很好。node

转载请注明出处@http://blog.csdn.net/gamer_gytgit

http://blog.csdn.net/gamer_gyt/article/details/62217053 github

转载请注明出处:http://blog.csdn.net/gamer_gyt 
博主微博:http://weibo.com/234654758 
Github:https://github.com/thinkgamer算法



写在前边的话

ES5.2.1 集群部署参考:http://blog.csdn.net/gamer_gyt/article/details/59077189api

对于集群的监控和优化是很重要的一部分,若是想持久维护集群,单单靠增长物理内存,cpu,硬盘是不够的,必须经过一些方法来进行优化。缓存


集群结点角色分配

在以前得文章中咱们介绍到es集群中得三个角色 master ,data,client安全

master结点:node.master: true node.data: false服务器

该node服务器只做为一个主节点,但不存储任何索引数据,该node服务器将使用自身空闲得资源,来协调各类建立索引请求或者查询请求,将这些请求合理分发到相关得node服务器上。数据结构

data结点:node.master: false node.data: true

该node服务器只做为一个数据节点,只用于存储索引数据。使该node服务器功能 单一,只用于数据存储和数据查询,下降其资源消耗率。

client结点(负载均衡结点):node.master: false node.data: false

该node服务器即不会被选做主节点,也不会存储任何索引数据。该服务器主要用 于查询负载均衡。在查询的时候,一般会涉及到从多个node服务器上查询数据,并请 求分发到多个指定的node服务器,并对各个node服务器返回的结果进行一个汇总处理, 最终返回给客户端。

1:关闭data结点得http功能

    针对ElasticSearch集群中的全部数据节点,不用开启http服务。将其中的配置 参数这样设置:http.enabled: false,同时也不要安装head, bigdesk, marvel等监控 插件,这样保证data节点服务器只需处理建立/更新/删除/查询索引数据等操做。

    http功能能够在非数据节点服务器上开启,上述相关的监控插件也安装到这些服 务器上,用于监控ElasticSearch集群状态等数据信息。这样作一来出于数据安全考虑,二来出于服务性能考虑。

2:一台服务器上最好只部署一个node

    一台物理服务器上能够启动多个Node服务器节点(经过设置不一样的启动port),但一台服务器上的CPU,内存,硬盘等资源毕竟有限,从服务器性能考虑,不建议一台服务器上启动多个node节点。

    在大规模局点,好比100个点,能够专门配备3个Master,可以使用3台具备内存的刀片便可,即参数配置为node.master: true,node.data: false;能够按比例配备数据汇聚节点,好比10个,即参数配置为node.master: false ,node.data: false;小规模节点,能够不用如此设置,固然若是依然有性能问题,也是一个优化的措施


集群得机器内存设置

    Elasticsearch 默认采用的是Lucene,至于为何es采用这个,缘由多是由于Lucene是一个成熟的、高性能的、可扩展的、轻量级的,并且功能强大的搜索引擎包。Lucene的核心jar包只有一个文件,并且不依赖任何第三方jar包。更重要的是,它提供的索引数据和检索数据的功能开箱即用。固然,Lucene也提供了多语言支持,具备拼写检查、高亮等功能。固然es使用Lucene做为分词搜索包,势必会形成很大程度上的内存消耗。

1:预留一半内存给Lucene使用

    一个常见的问题是配置堆太大。你有一个64 GB的机器,以为JVM内存越大越好,想给Elasticsearch全部64 GB的内存。

    固然,内存对于Elasticsearch来讲绝对是重要的,用于更多的内存数据提供更快的操做。并且还有一个内存消耗大户-Lucene

    Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,因此很利于缓存,同时操做系统也会把这些段文件缓存起来,以便更快的访问。

    Lucene的性能取决于和OS的交互,若是你把全部的内存都分配给Elasticsearch,不留一点给Lucene,那你的全文检索性能会不好的。

    最后标准的建议是把50%的内存给elasticsearch,剩下的50%也不会没有用处的,Lucene会很快吞噬剩下的这部份内存。

2:32GB限制

    在Java中,全部的对象都分配在堆上,而后有一个指针引用它。指向这些对象的指针大小一般是CPU的字长的大小,不是32bit就是64bit,这取决于你的处理器,指针指向了你的值的精确位置。

    对于32位系统,你的内存最大可以使用4G。对于64系统可使用更大的内存。可是64位的指针意味着更大的浪费,由于你的指针自己大了。浪费内存不算,更糟糕的是,更大的指针在主内存和缓存器(例如LLC, L1等)之间移动数据的时候,会占用更多的带宽。

    java 使用一个叫内存指针压缩的技术来解决这个问题。它的指针再也不表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针能够引用40亿个对象,而不是40亿个字节。最终,也就是说堆内存长到32G的物理内存,也能够用32bit的指针表示。

    一旦你越过那个神奇的30-32G的边界,指针就会切回普通对象的指针,每一个对象的指针都变长了,就会使用更多的CPU内存带宽,也就是说你实际上失去了更多的内存。事实上当内存到达40-50GB的时候,有效内存才至关于使用内存对象指针压缩技术时候的32G内存。

    这段描述的意思就是说:即使你有足够的内存,也尽可能不要超过32G,由于它浪费了内存,下降了CPU的性能,还要让GC应对大内存。

3:机器内存大于64GB

    你能够考虑一台机器上建立两个或者更多ES节点,而不要部署一个使用32+GB内存的节点。仍然要 坚持50%原则,假设 你有个机器有128G内存,你能够建立两个node,使用32G内存。也就是说64G内存给ES的堆内存,剩下的64G给Lucene。 
    若是你选择第二种,你须要配置

cluster.routing.allocation.same_shard.host:true

这会防止同一个shard的主副本存在同一个物理机上(由于若是存在一个机器上,副本的高可用性就没有了)

4:ES集群的heap参数优化

    所谓的heap即数据缓存的内存大小,ES集群中消耗内存的有如下几个:

1):segment Memory

    Lucene 把每次生成的倒排索引,叫作一个段(segment)。而后另外使用一个 commit 文件,记录索引内全部的 segment。而生成 segment 的数据来源,则是内存中的 buffer。因为词典的size会很大,所有装载到heap里不现实,所以Lucene为词典作了一层前缀索引(Term Index),这个索引在Lucene4.0之后采用的数据结构是FST (Finite State Transducer)。这种数据结构占用空间很小,Lucene打开索引的时候将其全量装载到内存中,加快磁盘上词典查询速度的同时减小随机磁盘访问次数。因此ES的data node存储数据并不是只是耗费磁盘空间的,为了加速数据的访问,每一个segment都有会一些索引数据驻留在heap里。所以segment越多,瓜分掉的heap也越多,而且这部分heap是没法被GC掉的! 理解这点对于监控和管理集群容量很重要,当一个node的segment memory占用过多的时候,就须要考虑删除、归档数据,或者扩容了。

2):Filter Cache

    Filter cache是用来缓存使用过的filter的结果集的,须要注意的是这个缓存也是常驻heap,没法GC的。默认的10% heap size设置工做得够好了,若是实际使用中heap没什么压力的状况下,才考虑加大这个设置。

3):Field Data cache

    对搜索结果作排序或者聚合操做,须要将倒排索引里的数据进行解析,而后进行一次倒排。在有大量排序、数据聚合的应用场景,能够说field data cache是性能和稳定性的杀手。这个过程很是耗费时间,所以ES2.0之前的版本主要依赖这个cache缓存已经计算过的数据,提高性能。可是因为heap空间有限,当遇到用户对海量数据作计算的时候,就很容易致使heap吃紧,集群频繁GC,根本没法完成计算过程。ES2.0之后,正式默认启用Doc Values特性(1.x须要手动更改mapping开启),将field data在indexing time构建在磁盘上,通过一系列优化,能够达到比以前采用field data cache机制更好的性能。所以须要限制对field data cache的使用,最好是彻底不用,能够极大释放heap压力。这里须要注意的是,排序、聚合字段必须为not analyzed。设想若是有一个字段是analyzed过的,排序的实际对象实际上是词典,在数据量很大状况下这种状况很是致命。

4):Bulk Queue

    Bulk Queue是作什么用的?当全部的bulk thread都在忙,没法响应新的bulk request的时候,将request在内存里排列起来,而后慢慢清掉。通常来讲,Bulk queue不会消耗不少的heap,可是见过一些用户为了提升bulk的速度,客户端设置了很大的并发量,而且将bulk Queue设置到难以想象的大,好比好几千。这在应对短暂的请求爆发的时候有用,可是若是集群自己索引速度一直跟不上,设置的好几千的queue都满了会是什么情况呢? 取决于一个bulk的数据量大小,乘上queue的大小,heap颇有可能就不够用,内存溢出了。通常来讲官方默认的thread pool设置已经能很好的工做了,建议不要随意去“调优”相关的设置,不少时候都是拔苗助长的效果。

5):Indexing Buffer

    Indexing Buffer是用来缓存新数据,当其满了或者refresh/flush interval到了,就会以segment file的形式写入到磁盘。这个参数的默认值是10% heap size。根据经验,这个默认值也可以很好的工做,应对很大的索引吞吐量。但有些用户认为这个buffer越大吞吐量越高,所以见过有用户将其设置为40%的。到了极端的状况,写入速度很高的时候,40%都被占用,致使OOM。

6):Cluster State Buffer

    ES被设计成每一个Node均可以响应用户的api请求,所以每一个Node的内存里都包含有一份集群状态的拷贝。这个Cluster state包含诸如集群有多少个Node,多少个index,每一个index的mapping是什么?有少shard,每一个shard的分配状况等等(ES有各种stats api获取这类数据)。在一个规模很大的集群,这个状态信息可能会很是大的,耗用的内存空间就不可忽视了。而且在ES2.0以前的版本,state的更新是由Master Node作完之后全量散播到其余结点的。频繁的状态更新都有可能给heap带来压力。在超大规模集群的状况下,能够考虑分集群并经过tribe node链接作到对用户api的透明,这样能够保证每一个集群里的state信息不会膨胀得过大。

7):超大搜索聚合结果集的fetch

    ES是分布式搜索引擎,搜索和聚合计算除了在各个data node并行计算之外,还须要将结果返回给汇总节点进行汇总和排序后再返回。不管是搜索,仍是聚合,若是返回结果的size设置过大,都会给heap形成很大的压力,特别是数据汇聚节点。

5:优化建议:

通常分配主机1/4-1/2的内存 
编辑:elasticsearch/bin/ elasticsearch 
加上(10g换成你本身设置的内存数):

ES_MIN_MEM=10g 
ES_MAX_MEM=10g 
ES_HEAP_NEWSIZE=1g


集群的硬盘和CPU设置

1:硬盘选型:

    硬盘对集群很是重要,特别是建索引多的状况。磁盘是一个服务器最慢的系统,对于写比较重的集群,磁盘很容易成为集群的瓶颈。若是能够承担的器SSD盘,最好使用SSD盘。若是使用SSD,最好调整I/O调度算法。RAID0是加快速度的不错方法。

2:自动调整存储带宽

    在2.0.0以前,elasticsearch会限制合并速度(merges),默认为20MB/sec。可是这个速率常常是显得过小,致使合并速度落后于索引速度,进而限制了索引速度。

    如今Elasticsearch2.0.0以后,使用了自动调整合并IO速度方式:若是合并落于索引速度,合并IO速度会逐渐增大,而且随着合并的持续进行会减少。在索引吞吐量小的时候,即便忽然来了一个大的合并任务,这种状况也不会吞噬整个节点可用的IO,极小化的下降对正在进行的查询和索引的影响。 
可是对索引请求大的状况下,容许的合并速度会自动调整到跟上索引的速度。有了2.0.0这个特性,意味着咱们不须要管任何的限制值了,只要用默认的就行了。

3:多个path.data 路径

    若是磁盘空间和IO性能是Elasticsearch的瓶颈的话,使用多个IO设备(经过设置多个path.data路径)存储shards,可以增长总的存储空间和提高IO性能。

    在Elasticsearch2.0以前的版本,也是配置多个path.data路径,可是其至关于RAID 0,每一个shards的数据会分布在全部的磁盘上。当一个节点上有一块盘坏了的状况下,该节点上全部的shards都会损坏了。须要恢复该节点上的全部shards。

    在2.0.0版本,把这个实现改为了:每一个shards全部的数据只会在一块磁盘上面。这样即便一个节点的一块磁盘损坏了,也只是损失了该磁盘上的shards,其它磁盘上的shards安然无事。只须要恢复该块盘上的shards便可。

    升级到2.0.0版本时,旧版本一个shard分布到全部磁盘上的数据,会拷贝到一块盘上。

    对应这个改变,在设计shards时,若是一个节点有10块磁盘,共3个节点,则shards至少30个,才能分布在30块盘上(即最大限度使用磁盘空间)。


集群的分片和副本配置

分片(Shard)

一个索引会分红多个分片存储,分片数量在索引创建后不可更改 
分片数是与检索速度很是相关的的指标,若是分片数过少或过多都会致使检索比较慢。分片数过多会致使检索时打开比较多的文件别外也会致使多台服务器之间通信。而分片数过少会致使单个分片索引过大,因此检索速度慢。基于索引分片数=数据总量/单分片数的计算公式,在肯定分片数以前须要进行单服务单索引单分片的测试,目前咱们测试的结果单个分片的内容为10G。

副本(replicas)

每一个索引的数据备份数量。 
ElasticSearch在建立索引数据时,最好指定相关的shards数量和replicas, 不然会使用服务器中的默认配置参数shards=5,replicas=1。

由于这两个属性的设置直接影响集群中索引和搜索操做的执行。假设你有足够的机器来持有碎片和副本,那么能够按以下规则设置这两个值:

  • 1) 拥有更多的碎片能够提高索引执行能力,并容许经过机器分发一个大型的索引;

  • 2) 拥有更多的副本可以提高搜索执行能力以及集群能力。

对于一个索引来讲,number_of_shards只能设置一次,而number_of_replicas可使用索引更新设置API在任什么时候候被增长或者减小。

这两个配置参数在配置文件的配置以下:

index.number_of_shards: 5 
number_of_replicas: 1

Elastic官方文档建议:一个Node中一个索引最好不要多于三个shards.配置total_shards_per_node参数,限制每一个index每一个节点最多分配多少个发片.


集群的优化总结

1:Java jdk版本尽可能高一点,不然容易出现bug 2:es集群结点规划好,master,client,data node 分开,关闭data node 的http功能 3:合理利用内存 4:根据机器数,磁盘数,索引大小等硬件环境,根据测试结果,设置最优的分片数和备份数,单个分片最好不超过10GB,按期删除不用的索引,作好冷数据的迁移。 5:保守配置内存限制参数,尽可能使用doc value存储以减小内存消耗,查询时限制size、from参数。 6:结合实际场景,作好集群监控

相关文章
相关标签/搜索