引言
-
JVM
参数设置
一、JVM参数调优
ElasticSearch
默认安装后设置的内存是1GB,对于任何一个现实业务来说,这个设置都太小了。如果你正在使用这个默认 堆内存 配置,你的集群配置可能会很快发生问题。
备注: 确保
Xmx
和Xms
的大小是相同的,其目的是为了能够在Java
垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源,可以减轻伸缩堆大小带来的压力。
把物理内存的一半给
Lucene
一个常见的问题是配置一个大内存,假设你有一个64G内存的机器,按照正常思维思考,你可能会认为把64G内存都给ElasticSearch
比较好,但现实是这样吗, 越大越好?
当然,内存对于ElasticSearch
来说绝对是重要的,用更多的内存对数据提供更快地操作,但还有一个内存消耗大户Lucene
。
Lucene
的设计目的是把底层OS
里的数据缓存到内存中。Lucene
的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。
Lucene
的性能取决于和OS
的交互,如果你把所有的内存都分配给ElasticSearch
,不留一点给Lucene
,那你的全文检索性能会很差的。
最后标准的建议是把50%的内存给ElasticSearch
,剩下的50%也不会没有用处的,Lucene
会很快吞噬剩下的这部分内存用于文件缓存。
不要超过32G
这里有另外一个原因不分配大内存给Elasticsearch
,事实上JVM
在内存小于32G的时候会采用一个内存对象指针压缩技术。
在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
应对大内存。
32GB是ES
的一个内存设置限制,那如果你的机器有很大的内存怎么办呢?现在的机器内存普遍增长,你现在都可以看到有300-500GB内存的机器。
首先,我们建议编码使用这样的大型机
-
其次,如果你已经有了这样的机器,你有两个可选项:
你主要做全文检索吗?考虑给
Elasticsearch
32G内存,剩下的交给Lucene
用作操作系统的文件系统缓存,所有的segment
都缓存起来,会加快全文检索。你需要更多的排序和聚合?你希望更大的堆内存。你可以考虑一台机器上创建两个或者更多
ES
节点,而不要部署一个使用32+GB内存的节点。仍然要 坚持50%原则,假设 你有个机器有128G内存,你可以创建两个node
,使用32G内存。也就是说64G内存给ES的堆内存,剩下的64G给Lucene
。
如果你选择第二种,你需要配置cluster.routing.allocation.same_shard.host:true
。这会防止同一个shard
的主副本存在同一个物理机上(因为如果存在一个机器上,副本的高可用性就没有了)。
1. swapping是性能的坟墓
这是显而易见的,但还是有必要说的更清楚一点,内存交换到磁盘对服务器性能来说是致命的。想想看一个内存的操作必须是快速的。
如果内存交换到磁盘上,一个100微秒的操作可能变成10毫秒,再想想那么多10微秒的操作时延累加起来。不难看出swapping
对于性能是多么可怕。
最好的办法就是在你的操作系统中完全禁用swapping
。这样可以暂时禁用:
swapoff -a
为了永久禁用它,你可能需要修改/etc/fstab
文件,这要参考你的操作系统相关文档。
如果完全禁用swap
,对你来说是不可行的。你可以降低swappiness
的值,这个值决定操作系统交换内存的频率。这可以预防正常情况下发生交换。但仍允许OS
在紧急情况下发生交换。
对于大部分Linux
操作系统,可以在sysctl
中这样配置:
vm.swappiness = 1
备注:
swappiness
设置为1
比设置为0
要好,因为在一些内核版本,swappness=0
会引发OOM
(内存溢出)
简单地说这个参数定义了系统对swap
的使用倾向,默认值为60,值越大表示越倾向于使用swap
。可以设为0
,这样做并不会禁止对swap
的使用,只是最大限度地降低了使用swap
的可能性。
通过sysctl -q vm.swappiness
可以查看参数的当前设置。
修改参数的方法是修改/etc/sysctl.conf
文件,加入vm.swappiness=xxx
,并重起系统。这个操作相当于是修改虚拟系统中的/proc/sys/vm/swappiness
文件,将值改为XXX
数值。
如果不想重起,可以通过sysctl -p
动态加载/etc/sysctl.conf
文件,但建议这样做之前先清空swap
。
# 查看内存使用情况
free -m
total used free shared buffers cached
Mem: 12010 9433 2577 0 4 24
-/+ buffers/cache: 9404 2606
Swap: 4094 838 3256
# swap清空
swapoff -a
swapon -a
#终于free -m看到swap为空了。
最后,如果上面的方法都不能做到,你需要打开配置文件中的mlockall
开关,它的作用就是运行JVM
锁住内存,禁止OS
交换出去。在elasticsearch.yml
配置如下:
bootstrap.mlockall: true
或
bootstrap.memmory_lock