ElasticSearch内存分配设置详解
1.内存
--
>i如果有一种资源是最先被好近的,那它可能是内存,排序和聚合都很消耗内存,所以有足够的堆空间来应付它们是很重要的,即使堆空间是比较小的时候,也能为操作系统文件缓存提供额外的内存,因为Lucene使用的许多数据结构是基于磁盘格式,Elasticsearch利用操作系统缓存能产生很大的效果。
>iElasticsearch默认安装后设置的内存是1GB,对于任何一个现实业务来说,这个设置都太小了。如果你正在使用这个个默认堆内存设置,你的集群配置可能很快发生问题。
>i这里有两种方式修改Elasticsearch的堆内存,最简单的一个方法就是指定环境变量(ES_HEAP_SIZE)服务器进程在启动的时候会读取这个变量,并相应的设置内存大小。
```
export ES_HEAP_SIZE=10g (OLD)
修改jvm.options文件中的
-Xms4g
-Xmx4g(NEW)
```
>i此外也可以通过命令行来给定内存大小。
```
./bin/elasticsearch -Xmx10g -Xms10g
```
>i一般来说,设置环境变量比直接内参数更好一点。
### 把一半的内存给Lucene
>i一个常见的问题是配置一个大内存,假设你有一个64G内存的机器,按照正常思维考虑,可能会认为把64G内存都给Elasticsearch比较好,但现实是这样吗?越大越好?
>i当然,内存对于Elasticsearch来说绝对是重要的,用于更多的内存数据提供更快的操作,而且还有一个内存消耗大户Lucene。
>iLucene的设计目的是把底层的OS里的数据缓存到内存中。Lucene的段(Lucene是分段存储的)是分别存储到单位文件中的,这些文件是不会变化的,所以很利于缓存,同事操作系统也会把这些文件缓存起来,以便更快的访问。
>d**Lucene的性能取决于和OS的交互,如果你把所有的内存都分给Elasticsearch,不留一点给Lucene那你的全文检索性能会很差。**
>i标准的建议是吧50%的内存给ElasticSearch,剩下的50%也不会没用处,Lucene会很快吞噬掉剩下的这部分内存用于文件缓存。
### 不要超过32G
>i这里有另一个原因不分配大内存给Elasticsearch,事实上JVM在内存小于32G的时候会采用一个内存对象指针压缩技术。
>i在JAVA中,所有的对象都分配在堆上,然后有一个指针引用它,指向这些对象的指针大小通常是在CPU字长的大小,不是32bit,就是64bit,这取决于你的处理器,指针指向了你的值的精确位置。
>i对于32位系统,你的内存最大可使用过4G,对于64位系统可以使用更大的内存,但是64位的指针意味着更大的浪费,因为你的指针本身太长了,浪费了内存不算,更糟糕的是,更大的指针在主内存和缓存器(例如LLC,L1等)之间移动数据的时候,会占用更多的宽带。
>iJAVA使用一个叫内存指针压缩技术的技术来解决这个问题,它的指针不再表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针可以引用40亿个对象,而不是40亿个字节,最终,也就是说堆内存长到32G的物理内存的时候,也可以用32bit的指针表示。
>i一旦你越过那个神奇的30-32bit边界,指针就会切回普通对象的指针,每个指针都边长了,就会使用更多的CPU内存宽带,也就是说你实际上是去了更多的内存,事实上当内存达到40-50G的时候,有效内存才相当于使用内存对象指针压缩技术时候的32G内存。
>i这段描述的意思就是说:即便你有足够的内存,也尽量不要超过32G,因为它浪费了内存,降低了CPU的性能,还要让GC应对大内存。
### 1TB内存的机器
>i32G是ES一个内存设置的限制,那如果你的机器有很大的内存怎么办呢?现在的机器内存普遍增长,你现在都可以看到有300-500G内存的机器。
>i首先,我们建议编码使用这样的大型机
>i其次,如果你已经有了这样的机器,你有两个选项
> i.你主要做全文检索吗?考虑给ES32G内存,剩下的交给Lucene用做操作系统的文件系统缓存,所有的segment都缓存起来,会加快全文检索。
> ii.你需要更多的排序和聚合?你希望更大的堆内存。你可以考虑一台机器上创建两个或者更多的ES节点,而不是部署一个32+G内存的节点。仍然要坚持50%原则,假设你有个机器有128G内存,你可以创建2个node,使用32G内存,也就是说64G内存给ES堆内存,剩下的64G给Lucene。
>d 如果你选择第二种,你需要配置 **cluster.routing.allocation.same_shard.host: true**.这样会防止同一个shard的主副本存在同一物理机上(如果存在一个机器上,副本的高可用性就没有了)。
### swapping是性能的坟墓
>i这是显而易见的,但是还是有必要说的更清楚一点,内存交换到磁盘对服务器的性能来说是只能的,想想看一个内存的操作必须是快速的。
>i如果内存交换到磁盘上,一个100微妙的操作可能变成10毫秒,再想想那么多10毫妙的操作延时累加起来,不难看出swapping对性能是有多么可怕。
>i最好的办法就是在你的操作系统中禁用swapping,这样可以暂时禁用:
```
swapoff -a
```
>i为了永久禁用它,你可能需要修改。/etc/fstab文件,这需要参考你的操作系统相关文档。
>w如果完全禁用swap,对你来说可能是不可行的,你可以降低swapping的值,这个值决定操作系统交换内存的频率,这可以预防正常情况下发生交换,但仍允许OS在紧急情况下发生交换。
>i对于大部分Linux操作系统,可以在sysctl中这样配置:
```
vm.swappiness = 1
```
>dPS:swappiness设置为1比设置为0要好,因为在一些内核版本,swappiness=0会引发OOM(内存溢出)
>i简单的说这个参数定义了系统对swap的使用形象,默认值为60,值越大表示越倾向使用swap,可以设置为0,这样做并不会禁止对swap的使用,只是最大限度的降低了使用swap的可能性。
>i通过systcl -q vm.swappiness 可以查看参数的当前设置。
>i修改参数方法是修改/etc/systcl.conf文件,加入vm.swappiness=xxx,并重启系统,这个操作相当于修改虚拟系统中的/proc/sys/vm/swappiness文件,将值改为xxx数值。
>i如果不想重启,可以通过,sysctl -p动态加载/etc/systcl.conf文件,但建议这样做之前先清空swap.
>i最后,如果上面的方法不能够做到,你需要打开配置文件中的mlockall开关,它的作用就是运行JVM锁住内存,禁止OS交换出去,在elasticsearch.yml配置,如下:
```
bootstrap.mlockall: true
```
2CPUs
--
>i大多数Elasticsearch部署往往对CPU要求不高,因此,相对其他资源,具体配置多少个(CPU)不是那么关键,你应该选择具有多个内核的现代处理器,常见的集群使用2-8核的机器。
>i如果你要在更快的CPUs和更多的核心之间选择,选择更多的核心更嗨皮。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。
3.硬盘
--
>i硬盘对所有的集群都很重要,对大量写入的集群更加倍重要(例如那些存储日志数据的)。硬盘是服务器上最慢的子系统,这意味着那些写入量很大的集群,很容易让硬盘饱和,使得它成为集群的瓶颈。
>i如果你负担的起SSD,它将远远超过任何旋转截止(注:机械硬盘,磁带等)基于SSD的节点,查询和索引性能都有提升,如果负担得起,SSD是一个好的选择。
>i如果你使用旋转介质,尝试获取尽可能快的以硬盘(高性能服务器硬盘,15K RPM 驱动器)。
>i使用RAID0是提高硬盘速度的有效途径。对机械硬盘和SSD来说都是如此,没有必要使用镜像或其他RAID变体,因为高可用是通过replicas内建在Elasticsearch中的。
>i最后,避免使用网络附加存储(NAS)。人们常声称他们的 NAS 解决方案比本地驱动器更快更可靠。除却这些声称, 我们从没看到 NAS 能配得上它的大肆宣传。NAS 常常很慢,显露出更大的延时和更宽的平均延时方差,而且它是单点故障的。
4.网络
--
>i快速可靠的网络显然对分布式系统的性能是很重要的。 低延时能帮助确保节点间能容易的通讯,大带宽能帮助分片移动和恢复。现代数据中心网络(1 GbE, 10 GbE)对绝大多数集群都是足够的。
>i即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。
>iElasticsearch 假定所有节点都是平等的—并不会因为有一半的节点在150ms 外的另一数据中心而有所不同。更大的延时会加重分布式系统中的问题而且使得调试和排错更困难。
>i和 NAS 的争论类似,每个人都声称他们的数据中心间的线路都是健壮和低延时的。这是真的—直到它不是时(网络失败终究是会发生的,你可以相信它)。 从我们的经验来看,处理跨数据中心集群的麻烦事是根本不值得的。