Easticsearch性能优化之硬件优化

  • 一、CPU配置
  • 二、内存配置
    • 1、内存配置总体方针
    • 2、内存实际分配
    • 3、禁止swap
    • 4、GC设置
  • 三、IO(磁盘)

对于性能优化,升级硬件设备配置一直都是提高服务能力最快速有效的手段。硬件优化主要可以从CPU内存存储设备(磁盘)、显卡、散热系统、主板、电源、外设设备等。
在系统层面能够影响应用性能的一般主要包括三个因素:CPU内存IO(磁盘)。可以从这三方面进行 Elasticsearch 的性能优化工作。

一、CPU配置

CPU(中央处理器)是计算机系统中最重要的组成部分之一,在CPU内可分为两个主要的单元,分别是:算数逻辑单元控制单元。 它负责执行计算机程序中的指令和控制计算机系统的操作。
我们都知道Elasticsearch 是一个多线程的应用程序,而多线程的上下文切换会导致CPU的繁忙,Elasticsearch 同时是一个很消耗内存的应用程序,特别是在进行排序、聚合时特别吃内存,这样会导致频繁的GC,也会导致CPU比较繁忙。所以合理的CPU的配置可以更好的提升Elasticsearch 的性能。
比如部署Elasticsearch 时应该选择具有多个内核的现代处理器,常见集群使用2到8核的机器(建议CPU8核,当然具体情况看具体使用)。也可选择高频CPU,来提供更快的计算速度,从而加快Elasticsearch 的处理速度。

注意:更快的 CPUs 和更多的核数之间选择,选择更多的核数更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。

二、内存配置

上面说过Elasticsearch 在排序和聚合时都很耗内存,如果有一种资源是最先被耗尽的,它可能是内存。所以有足够的堆空间来应付它们是很重要的。即使堆空间是比较小的时候,也能为操作系统文件缓存提供额外的内存。因为 Lucene 使用的许多数据结构是基于磁盘的格式,Elasticsearch 利用操作系统缓存能产生很大效果。这样显得内存的合理配置比具体配置多少个(CPU)重要的多得多。

1、内存配置总体方针

对于Elasticsearch 的堆内存分配建议将总内存的一半分配给堆内存,但不要超过机器的物理限制。对于数据节点最好不要超过32Gmaster节点可适当少点(数据节点一半即可)。所以64 GB 内存的机器是非常理想的,但是 32 GB 和 16 GB 机器也是很常见的。少于8 GB 会适得其反(你最终需要很多很多的小机器),大于 64 GB 的机器也会有问题(会有一定浪费,成本也会增加)。

为什么将总内存的一半分配给堆内存?

答:由于 ES 构建基于 lucene,而 lucene 设计强大之处在于 lucene 能够很好的利用操作系统内存来缓存索引数据,以提供快速的查询性能。lucene 的索引文件 segements 是存储在单文件中的,并且不可变,对于 OS 来说,能够很友好地将索引文件保持在 cache 中,以便快速访问;因此,我们很有必要将一半的物理内存留给 lucene;另一半的物理内存留给 ES(JVM heap)。

为什么数据节点最好不大于32G?

答:在 Elasticsearch 中,将堆内存设置为超过32GB 的主要原因是基于 Java 虚拟机(JVM)的限制。具体来说,这是由于 JVM 使用指针压缩技术所导致的。

  • 在 64 位 JVM 中,默认开启了指针压缩技术(Compressed Oops),它可以减少指针占用的内存空间。指针压缩适用于堆内存小于 32GB 的情况,能够显著降低内存消耗。然而,当堆内存超过32GB时,JVM 不再使用指针压缩,而是使用全指针模式,这会增加指针的大小和内存开销。
  • 因此,在 Elasticsearch 中,将堆内存设置为超过32GB 时,可能会导致更高的内存消耗,以及对垃圾回收(GC)和索引性能的不利影响。这是因为全指针模式增加 GC 操作的时间和频率
  • 此外,超过32GB 堆内存的配置也可能受到操作系统和硬件的限制。某些操作系统(32位和64位操作系统有不同限制)和硬件可能对单个进程的可用内存有限制,因此超过这些限制可能导致性能问题或运行时错误。

2、内存实际分配

1)当机器内存小于 64G 时,遵循通用的原则,50% 给 ES,50% 留给 lucene。
2) 当机器内存大于 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。

3、禁止swap

禁止 swap,一旦允许内存与磁盘的交换,会引起致命的性能问题。可以通过在 elasticsearch.yml 中 bootstrap.memory_lock: true,以保持 JVM 锁定内存,保证 ES 的性能。

4、GC设置

1)GC 默认设置为:Concurrent-Mark and Sweep(CMS),如果数据量较大建议改为G1。常用JVM配置如下:

-XX:+UseG1GC → 使用G1 gc-XX:+ExplicitGCInvokesConcurrent → 提升gc效率,调用并发gc,减少gc的STW时间-XX:+UseGCOverheadLimit→ 增加gc开销限制-XX:MaxGCPauseMillis=200→ 每次GC最大停顿毫秒数-XX:InitiatingHeapOccupancyPercent=30→老年代占比达到30%,触发并发标记-XX:ParallelGCThreads=43→ gc并行线程数,只有在 STW阶段才有效,不和用户线程并发执行。一般用于初始标记、重新标记、清理阶段。一般数值算法是:8+(N-8)*5/8-XX:ConcGCThreads=8→并发标记线程数,并发标记阶段,和用户线程并发执行,如果太大,会影响用户线程,造成不稳定,一般是ParallelGCThreads的1/4-XX:G1HeapRegionSize=32m→ 每个Region(独立区域)的大小,一般是堆内存 除以 2048-XX:+UnlockExperimentalVMOptions→解锁实验参数-XX:G1NewSizePercent=10→年轻代最小占比-XX:G1MaxNewSizePercent=20→年轻代最大占比-XX:G1ReservePercent=25→年老代预留空间占比

2)保持线程池的现有设置,目前 ES 的线程池有了较多优化设置,保持现状即可;默认线程池大小等于 CPU 核心数。如果一定要改,按公式 ( ( CPU 核心数 * 3 ) / 2 ) + 1 设置;不能超过 CPU 核心数的 2 倍; 但是不建议修改默认配置,否则会对 CPU 造成硬伤。

三、IO(磁盘)

硬盘对所有的集群都很重要,对大量写入的集群更是加倍重要(例如那些存储日志数据的)。硬盘是服务器上最慢的子系统,这意味着那些写入量很大的集群很容易让硬盘饱和,使得它成为集群的瓶颈。
在经济压力能承受的范围下,尽量使用固态硬盘(SSD) 固态硬盘相比于任何旋转介质(机械硬盘,磁带等),无论随机写还是顺序写,都会对 IO 有较大的提升。

如果你正在使用 SSDs,确保你的系统 I/O 调度程序是配置正确的。当你向硬盘写数据,I/O 调度程序决定何时把数据实际发送到硬盘。大多数默认 *nix 发行版下的调度程序都叫做 cfq(完全公平队列)。调度程序分配时间片到每个进程。并且优化这些到硬盘的众多队列的传递。但它是为旋转介质优化的:机械硬盘的固有特性意味着它写入数据到基于物理布局的硬盘会更高效。这对 SSD 来说是低效的,尽管这里没有涉及到机械硬盘。但是,deadline 或者 noop 应该被使用。deadline 调度程序基于写入等待时间进行优化,noop 只是一个简单的 FIFO 队列。这个简单的更改可以带来显著的影响。仅仅是使用正确的调度程序,我们看到了 500 倍的写入能力提升

如果你使用旋转介质(如机械硬盘),尝试获取尽可能快的硬盘(高性能服务器硬盘,15k RPM 驱动器)。
使用 RAID0 是提高硬盘速度的有效途径,对机械硬盘和 SSD 来说都是如此。 没有必要使用镜像或其它 RAID 变体,因为 Elasticsearch 在自身层面通过副本,已经提供了备份的功能,所以不需要利用磁盘的备份功能,同时如果使用磁盘备份功能的话,对写入速度有较大的影响。
最后,避免使用网络附加存储(NAS)。 人们常声称他们的 NAS 解决方案比本地驱动器更快更可靠。除却这些声称,我们从没看到 NAS 能配得上它的大肆宣传。NAS 常常很慢,显露出更大的延时和更宽的平均延时方差,而且它是单点故障的。