ElasticSearch优化系列二:机器设置(内存)

预留一半内存给Lucence使用

一个常见的问题是配置堆太大。你有一个64 GB的机器,觉得JVM内存越大越好,想给Elasticsearch所有64 GB的内存。

当然,内存对于Elasticsearch来说绝对是重要的,用于更多的内存数据提供更快的操作。而且还有一个内存消耗大户-Lucene Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。

Lucene的性能取决于和OS的交互,如果你把所有的内存都分配给Elasticsearch,不留一点给Lucene,那你的全文检索性能会很差的。

最后标准的建议是把50%的内存给elasticsearch,剩下的50%也不会没有用处的,Lucene会很快吞噬剩下的这部分内存。

32GB限制

给ES的内存配置不是越大越好,建议不能超过32GB,不同jdk版本最大边界值是不同的,对于32位小于32G JVM才采用内存对象指针压缩技术,不然对象指针需要占用很大的内存。

使用如下命令测试最大边界值:

java -Xmx32767m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops      
bool UseCompressedOops       = false         {lp64_product}     
java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops     
 bool UseCompressedOops       = true          {lp64_product}    
$ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops      
bool UseCompressedOops   := true
 $ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32767m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
 bool UseCompressedOops   = false

在ES启动日志中最好能够看到压缩对象指针为真。

heap size [15.8gb], compressed ordinary object pointers [true] 在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应对大内存。

机器内存大于64GB

你可以考虑一台机器上创建两个或者更多ES节点,而不要部署一个使用32+GB内存的节点。仍然要 坚持50%原则,假设 你有个机器有128G内存,你可以创建两个node,使用32G内存。也就是说64G内存给ES的堆内存,剩下的64G给Lucene。

如果你选择第二种,你需要配置cluster.routing.allocation.same_shard.host:true。这会防止同一个shard的主副本存在同一个物理机上(因为如果存在一个机器上,副本的高可用性就没有了)

swapping是性能的坟墓

这是显而易见的,但是还是有必要说的更清楚一点,内存交换到磁盘对服务器性能来说是致命的。想想看一个内存的操作必须是快速的。

如果内存交换到磁盘上,一个100微秒的操作可能变成10毫秒,再想想那么多10微秒的操作时延累加起来。不难看出swapping对于性能是多么可怕。

最好的办法就是在你的操作系统中完全禁用swapping。这样可以暂时禁用:

sudo swapoff -a

为了永久禁用它,你可能需要修改/etc/fstab文件,这要参考你的操作系统相关文档。

如果完全禁用swap,对你来说是不可行的。你可以降低swappiness 的值,这个值决定操作系统交换内存的频率。这可以预防正常情况下发生交换。但仍允许os在紧急情况下发生交换。对于大部分Linux操作系统,可以在sysctl 中这样配置:

vm.swappiness = 1

备注:swappiness设置为1比设置为0要好,因为在一些内核版本,swappness=0会引发OOM(内存溢出)

最后,如果上面的方法都不能做到,你需要打开配置文件中的mlockall开关,它的作用就是运行JVM锁住内存,禁止OS交换出去。在elasticsearch.yml配置如下:

bootstrap.mlockall: true

原文发布于微信公众号 - 人工智能LeadAI(atleadai)

原文发表时间:2017-11-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码洞

Lettuce快速入门

最近在开发一个使用Redis协议包装HBase的Proxy服务器,一路写的很顺,客户端使用redis-py提供的execute_command方法也轻松搞定。但...

1981
来自专栏一枝花算不算浪漫

页面静态化技术Freemarker技术的介绍及使用实例.

3636
来自专栏Java帮帮-微信公众号-技术文章全总结

Java并发学习2【面试+工作】

  关键字synchronized的作用是实现进程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性(即同步块每...

1002
来自专栏CDA数据分析师

深入解读Python解析XML的几种方式

本文将介绍深入解读利用Python语言解析XML文件的几种方式,并以笔者推荐使用的ElementTree模块为例,演示具体使用方法和场景。文中所使用的Pytho...

2577
来自专栏黑泽君的专栏

day58_BOS项目_10

之前的请假流程,是没有实际意义的,我们要使得我们流程变得有意义(有实际意义),需要在流程向下推进的过程中带着数据推进才有意义。如下图所示:

884
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

19010
来自专栏云计算教程系列

如何在Debian 9上使用Python 3设置Jupyter笔记本

Jupyter Notebook为交互式计算提供了一个命令shell作为Web应用程序。该工具可以与多种语言一起使用,包括Python,Julia,R,Hask...

1863
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

21110
来自专栏Danny的专栏

System.AccessViolationException”类型的未经处理的异常在 System.Data.dll 中发生。其他信息:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

1122
来自专栏向治洪

Java的依赖注入(控制反转)

两个主角“依赖注入”和“控制反转”: 1、二都说的都是同一件事,只是叫法不同。是一个重要的面向对象编程的法则,也是一种设计模式; 2、英文原称:依赖注入,...

22210

扫码关注云+社区