Elasticsearch 性能优化详解

硬件配置优化升级硬件设备配置一直都是提高服务能力最快速有效的手段,在系统层面能够影响应用性能的一般包括三个因素:CPU、内存和 IO,可以从这三方面进行 ES 的性能优化工作 。
CPU 配置一般说来,CPU 繁忙的原因有以下几个:

  • 线程中有无限空循环、无阻塞、正则匹配或者单纯的计算;
  • 发生了频繁的 GC;
  • 多线程的上下文切换;
大多数 Elasticsearch 部署往往对 CPU 要求不高 。因此 , 相对其它资源,具体配置多少个(CPU)不是那么关键 。你应该选择具有多个内核的现代处理器,常见的集群使用 2 到 8 个核的机器 。如果你要在更快的 CPUs 和更多的核数之间选择,选择更多的核数更好 。多个内核提供的额外并发远胜过稍微快一点点的时钟频率 。
内存配置如果有一种资源是最先被耗尽的,它可能是内存 。排序和聚合都很耗内存,所以有足够的堆空间来应付它们是很重要的 。即使堆空间是比较小的时候,也能为操作系统文件缓存提供额外的内存 。因为 Lucene 使用的许多数据结构是基于磁盘的格式,Elasticsearch 利用操作系统缓存能产生很大效果 。
64 GB 内存的机器是非常理想的,但是 32 GB 和 16 GB 机器也是很常见的 。少于8 GB 会适得其反(你最终需要很多很多的小机器),大于 64 GB 的机器也会有问题 。
由于 ES 构建基于 lucene,而 lucene 设计强大之处在于 lucene 能够很好的利用操作系统内存来缓存索引数据,以提供快速的查询性能 。lucene 的索引文件 segements 是存储在单文件中的,并且不可变,对于 OS 来说,能够很友好地将索引文件保持在 cache 中,以便快速访问;因此,我们很有必要将一半的物理内存留给 lucene;另一半的物理内存留给 ES(JVM heap) 。
内存分配当机器内存小于 64G 时,遵循通用的原则,50% 给 ES,50% 留给 lucene 。
当机器内存大于 64G 时,遵循以下原则:
  • 如果主要的使用场景是全文检索,那么建议给 ES Heap 分配 4~32G 的内存即可;其它内存留给操作系统,供 lucene 使用(segments cache),以提供更快的查询性能 。
  • 如果主要的使用场景是聚合或排序,并且大多数是 numerics,dates,geo_points 以及 not_analyzed 的字符类型,建议分配给 ES Heap 分配 4~32G 的内存即可 , 其它内存留给操作系统 , 供 lucene 使用,提供快速的基于文档的聚类、排序性能 。
  • 如果使用场景是聚合或排序,并且都是基于 analyzed 字符数据,这时需要更多的 heap size,建议机器上运行多 ES 实例,每个实例保持不超过 50% 的 ES heap 设置(但不超过 32 G,堆内存设置 32 G 以下时,JVM 使用对象指标压缩技巧节省空间) , 50% 以上留给 lucene 。
禁止 swap禁止 swap,一旦允许内存与磁盘的交换,会引起致命的性能问题 。可以通过在 elasticsearch.yml 中 bootstrap.memory_lock: true,以保持 JVM 锁定内存,保证 ES 的性能 。
GC 设置老的版本中官方文档 中推荐默认设置为:Concurrent-Mark and Sweep(CMS),给的理由是当时G1 还有很多 BUG 。
原因是:已知JDK 8附带的HotSpot JVM的早期版本存在一些问题,当启用G1GC收集器时,这些问题可能导致索引损坏 。受影响的版本早于JDK 8u40随附的HotSpot版本 。来源于官方说明
实际上如果你使用的JDK8较高版本,或者JDK9+,我推荐你使用G1 GC;因为我们目前的项目使用的就是G1 GC , 运行效果良好,对Heap大对象优化尤为明显 。修改jvm.options文件 , 将下面几行:
-XX:+UseConcMarkSweepGC-XX:CMSInitiatingOccupancyFraction=75-XX:+UseCMSInitiatingOccupancyOnly更改为
-XX:+UseG1GC-XX:MaxGCPauseMillis=50其中 -XX:MaxGCPauseMillis是控制预期的最高GC时长 , 默认值为200ms,如果线上业务特性对于GC停顿非常敏感,可以适当设置低一些 。但是 这个值如果设置过小 , 可能会带来比较高的cpu消耗 。
G1对于集群正常运作的情况下减轻G1停顿对服务时延的影响还是很有效的 , 但是如果是你描述的GC导致集群卡死,那么很有可能换G1也无法根本上解决问题 。通常都是集群的数据模型或者Query需要优化 。
磁盘硬盘对所有的集群都很重要,对大量写入的集群更是加倍重要(例如那些存储日志数据的) 。硬盘是服务器上最慢的子系统 , 这意味着那些写入量很大的集群很容易让硬盘饱和,使得它成为集群的瓶颈 。


推荐阅读