理想情况下,ElasticSearch应该独立运行在服务器上,并使用这个服务器上所有可用的资源。为了达到这个目的,你应该允许运行ElasticSearch的用户能够访问比默认更多的资源。
在进入生产环境前,下面的这些配置必须小心考虑到
- Configure system settings
- Disable swapping
- Increase file descriptors
- Ensure sufficient virtual memory
- Ensure sufficient threads
- JVM DNS cache settings
- Temporary directory not mounted withnoexec
- TCP retransmission timeout
开发模式和生产模式
默认情况下,ElasticSearch假设你在开发模式下。上述的配置如果没有被正确设置的话,将在log日志文件里产生一条Warning告警,但是ElasticSearch依然能够正常启动。
一旦你配置了网络配置例如network.host 配置项的话,ElasticSearch会假设你迁移到了生产环境,并将warning升级为Exception。这个Exception将会阻止ElasticSearch的启动。这是一个重要的安全措施,确保你不会因为不当的配置而丢失数据。
配置系统settings
配置系统的settings的位置取决于你安装ElasticSearch使用的包以及你的操作系统是什么。如果你使用的是zip包或者tar.gz包安装的话,你的配置位置在
- 临时的使用unlimit
- 永久的在<font style="color:rgb(33, 37, 41);"> </font>[/etc/security/limits.conf](https://www.elastic.co/guide/en/elasticsearch/reference/8.11/setting-system-settings.html#limits.conf)
如果使用的是 RPM or Debian包,大部分的配置可以使用system configuration file.系统设置文件。
然而,使用systemd的系统要求系统的 limits 在systemd configuration file中配置。
ulimit
在Linux操作系统中,ulimit 能够用来临时的改变系统资源限制.修改Limits通常需要从运行ElasticSearch的用户切换到root用户。 例如,设置打开文件句柄的数量限制 (ulimit -n) 到 65,535, 你可以像下面这样:
sudo su //切换到root用户
ulimit -n 65535 // 配置限制到65535
su elasticsearch //切回到ElasticSearch账户
新的配置仅仅在当前的会话里有效。
你可以使用ulimit -a 命令查询当前所有的配置。
/etc/security/limits.conf
在Linux系统上,可以通过编辑/etc/security/limits.conf文件为特定的用户设置持久的限制。为了设置ElasticSearch用户最大打开文件数,可以在limit.conf文件里增加下面一行:
elasticsearch - nofile 65535
这个改变只会在ElasticSearch用户只会在下次登录打开会话的时候才会生效。
Ubuntu and limits.conf
Ubuntu 会 在init.d启动的进程忽略 limits.conf 。为了启用 limits.conf 文件, 编辑 /etc/pam.d/su 以及删掉下面的注释:
# session required pam_limits.so
Sysconfig file
如果使用了RPM or Debian包的话,环境变量可以在下面的文件中配置:
| RPM | /etc/sysconfig/elasticsearch |
|---|---|
| Debian | /etc/default/elasticsearch |
但是, 系统 limits 需要 通过 systemd 来配置。
Systemd configuration
当使用 RPM or Debian包并且使用了 systemd的时候,系统 limits 需要通过systemd来配置。systemd服务配置 (/usr/lib/systemd/system/elasticsearch.service) 包含了所有的默认limits。
需要覆写他们的话,, 添加一个文件/etc/systemd/system/elasticsearch.service.d/override.conf (或者, 你可以运行 sudo systemctl edit elasticsearch 会自动的在你的编辑器里打开配置文件). 像下面一样设置配置这个文件:
[Service]
LimitMEMLOCK=infinity
一旦完成,运行下面的这个命令行reload配置文件:
sudo systemctl daemon-reload
禁用 swapping
大多数操作系统会尽可能多地使用内存作为文件系统缓存,并且会积极地将未使用的应用程序内存换出。这可能会导致JVM堆甚至其可执行页面的一部分被换出到磁盘上。
交换对性能和节点稳定性非常不利,应不惜一切代价避免。它可能导致垃圾回收持续几分钟而不是几毫秒,并且可能导致节点响应缓慢甚至从集群中断开连接。在一个有弹性的分布式系统中,让操作系统终止该节点更为有效。
有三种方法可以禁用交换。首选方案是完全禁用交换。如果这不可行,那么是否选择最小化交换倾向或锁定内存取决于您的环境。
Disable all swap files
通常情况下,Elasticsearch是唯一在一个服务器上运行的服务,其内存使用由JVM选项控制。因此,没有必要启用交换分区(swap)。
在Linux系统中,你可以通过运行以下命令临时禁用交换分区:
这条命令会立即停止所有活动的交换空间。如果你希望永久禁用交换分区,则需要编辑系统的配置文件,比如/etc/fstab,移除或注释掉与swap相关的行。
:::info sudo swapoff -a
:::
这不需要重启Elasticsearch。
要永久禁用它,您需要编辑 /etc/fstab 文件,并注释掉包含 swap 一词的所有行。
在 Windows 上,可以通过系统属性 → 高级 → 性能 → 高级 → 虚拟内存完全禁用分页文件来实现相同的效果。
配置 swappiness
在 Linux 系统上的另一个选项是确保 sysctl 值 vm.swappiness 设置为 1。这样可以减少内核交换的倾向,在正常情况下不会导致交换,但仍然允许整个系统在紧急情况下进行交换。
启用 bootstrap.memory_lock
另一个选项是在 Linux/Unix 系统上使用 mlockall,或在 Windows 上使用 VirtualLock,尝试将进程地址空间锁定到 RAM 中,防止任何 Elasticsearch 堆内存被交换出去。
某些平台在使用内存锁定时仍会交换非堆内存。要防止非堆内存交换,请完全禁用所有交换文件。
要启用内存锁定,请在 elasticsearch.yml 中将 bootstrap.memory_lock 设置为 true:
bootstrap.memory_lock: true
mlockall 可能会导致 JVM 或 shell 会话退出,如果它尝试分配的内存超过了可用内存!
在启动 Elasticsearch 后,您可以通过检查此请求输出中的 mlockall 值来查看该设置是否成功应用:
GET _nodes?filter_path=**.mlockall
如果您看到 mlockall 为 false,则意味着 mlockall 请求失败。您还将在日志中看到一条带有更多信息的行,其中包含“Unable to lock JVM Memory”(无法锁定 JVM 内存)的字样。
在 Linux/Unix 系统上,最可能的原因是运行 Elasticsearch 的用户没有锁定内存的权限。可以按照以下方式授予该权限:
- 对于 .zip 和 .tar.gz 安装包:
- 在启动 Elasticsearch 之前以 root 用户身份设置
ulimit -l unlimited。 - 或者,在
/etc/security/limits.conf文件中将 memlock 设置为 unlimited。
- 在启动 Elasticsearch 之前以 root 用户身份设置
# allow user 'elasticsearch' mlockall
elasticsearch soft memlock unlimited
elasticsearch hard memlock unlimited
RPM and Debian
将systemd配置中的LimitMEMLOCK设置为无限。
mlockall失败的另一个可能原因是JNA临时目录(通常是/tmp的一个子目录)被挂载时使用了noexec选项。可以通过使用ES_JAVA_OPTS环境变量指定一个新的临时目录给JNA来解决这个问题:
export ES_JAVA_OPTS="$ES_JAVA_OPTS -Djna.tmpdir=<path>"
./bin/elasticsearch
或者在jvm.options配置文件中设置此JVM标志。
文件描述符
:::info 这仅适用于Linux和macOS,如果在Windows上运行Elasticsearch则可以安全地忽略。在Windows上,JVM使用的API仅受限于可用资源。
:::
Elasticsearch会使用大量的文件描述符或文件句柄。耗尽文件描述符可能会导致灾难性后果,并极有可能导致数据丢失。请确保将运行Elasticsearch的用户的打开文件描述符数量限制增加到65,535或更高。
对于.zip和.tar.gz包,在启动Elasticsearch之前,以root身份设置ulimit -n 65535,或者在/etc/security/limits.conf中将nofile设置为65535。
在macOS上,你还必须向Elasticsearch传递JVM选项-XX:-MaxFDLimit,以便它能够利用更高的文件描述符限制。
RPM和Debian包已经默认将最大文件描述符数量设置为65535,不需要进一步配置。
你可以使用节点统计API来检查每个节点配置的最大文件描述符数,命令如下:
GET _nodes/stats/process?filter_path=**.max_file_descriptors
虚拟内存
Elasticsearch使用mmapfs目录来存储索引。操作系统的默认限制mmap的数量设置的太小,可能会导致OOM。在Linux操作系统上,你可以用root权限运行下面的命令:
sysctl -w vm.max_map_count=262144
如果要永久的设置这个值,你需要修改<font style="color:rgb(85, 85, 85);background-color:rgb(248, 248, 248);">/etc/sysctl.conf</font>文件里的vm.max_map_count,然后重启后使用sysctl vm.max_map_count命令来验证。
The RPM and Debian包已经默认配置好了,不需要更多的配置。
你可以使用下面的命令来查询,当前的ES运行的mmap的数量。把下面的$PID换成实际的ES的PID。
wc -l /proc/$PID/maps
线程数量
ES使用了大量的线程池用于不同的操作。能够在必要的时候创建线程对ES来说是非常重要的。确保ES能创建的线程数量至少有4096个。
在启动ES前使用root权限运行ulimit -u 4096 或者设置/etc/security/limits.conf.里的nproc为4096。以systemd服务的方式运行的发行包已经自动设置好了,因此不需要额外的修改配置。
DNS缓存设置
ES运行带着安全管理器,在安全管理器里JVM默认永久缓存正确的DNS解析结果,不正确的解析缓存10s。ES改写了这个配置,正确的是60s,错误的是10s。在大部分环境下,这个值应该被正确的配置,包括那些DNS解析动态变化的。你可以编辑这些配置来设置:
es.networkaddress.cache.ttl and es.networkaddress.cache.negative.ttl in the JVM options.
如果配置了上述的两个配置,那么java安全策略里的the values networkaddress.cache.ttl= and networkaddress.cache.negative.ttl=就会被忽略。
确保JNA的临时目录拥有执行权限
这个只与Linux操作系统相关
ES使用JNA和libffi库来执行平台依赖的Native代码。在Linux操作系统中,这些Native代码会在运行中(Runtime)被提取至临时目录并映射到ES的运行地址页面。这就需要这些底层文件所在的临时目录不是noexec权限。
默认情况下,ES会创建/tmp临时目录,但是在一些Linux操作系统中,/tmp目录是noexec权限。这会导致JNA或者libffi执行失败。在启动阶段JNA可能会报错
java.lang.UnsatisfiedLinkerError
或者类似于failed to map segment from shared object的报错。或者libffi会报错:failed to allocate closure。
注意不同的java版本可能报错不尽相同。
同时ES的组件如果依赖了JNA或者libffi执行的话,可能会报错:because JNA is not available 。
要解决这个问题,要么移除掉/tmp的noexec权限,要么通过 $ES_TMPDIR修改ES的临时目录路径。
例如,如果你是在shell环境下启动的ES,你可以运行如下命令:
export ES_TMPDIR=/usr/share/elasticsearch/tmp
通过RPM or DEB包安装的ES的情况,他的环境变量通过文件配置。Configuring system settings | Elasticsearch Guide [8.11] | Elastic
如果你是通过systemd来运行的ES,请在下面的文件里修改
Environment=ES_TMPDIR=/usr/share/elasticsearch/tmp
如果你想要更好的控制临时目录,你还可以通过java启动命令来设置/tmp路径,-Djna.tmpdir=以及使用环境变量LIBFFI_TMPDIR来设置libffi路径。将来的ES版本可能需要其他附加配置,所以推荐使用环境变量ES_TMPDIR来设置。
:::info ES不会自动的移除你的临时目录,所以在ES没有运行的时候需要移除tmp目录。推荐在重启的时候,自动移除。如果你运行的是Linux操作系统,你可以使用tmpfs文件系统。
:::
TCP重传超时
每一对ES的节点之间都是通过一系列的TCP连接来通信的,他们总是保持open状态知道节点关闭或者被底层的错误所中断。
TCP连接通过对通信应用隐藏间歇的网络中断来运行可靠的网络连接。在通知发送者问题之前,你的操作系统会进行一定数量的重传。ES必须在系统重传的时候进行等待直到放弃。用户就必须等待一系列的重传结束。
大部分的Linux操作系统设置15次的失败重传,这将耗费最多900s的等待时间。这意味着ES将等待数分钟来判断一个节点是否失败。Windows默认重传5次,每次13s。
Linux默认允许很长时间的丢包通信,但是这通常对ES这种高可用系统来说是致命的伤害。一个ES集群如果检测到一个节点失败,他会进行relocation丢失的分片,重新路由搜索请求,或者重新选举一个master节点。高可用的集群必须立刻马上感知到失败节点,通过减少tcp重传次数可以达到这个目的。连接到远程集群的情况下最好也能快速感知到节点失败而不是默认的系统失败时长。所以,Linux用户最好重新设置重传次数。
你可以通过下面这个命令,将重传次数修改为5,每一轮的时间是13s
sysctl -w net.ipv4.tcp_retries2=5
永久修改可以修改文件/etc/sysctl.conf.里的net.ipv4.tcp_retries2配置。重启系统后,通过sysctl net.ipv4.tcp_retries2.来进行验证。
这个配置会针对所有的连接生效,而不仅仅是ES集群。如果你运行在一个低质量的网络上,你需要提高你的net.ipv4.tcp_retries2配置,所以这就是ES没有把他改成默认配置的原因。
相关配置
Elasticsearch 也实现了自己内部的健康检查,其超时时间比 Linux 上的默认重传超时时间短得多。由于这些是应用级别的健康检查,它们的超时时间必须考虑到应用级别的影响,例如垃圾回收暂停。你不应该减少任何与这些应用级别的健康检查相关的超时时间。你需要确保你的网络架构不会干扰长链接,尽管这些连接看起来是空闲的。设备到一定age后会放弃连接,这是导致ES集群经常出问题的原因,应该尽量避免。