问题导读:
1. 如何优化集群节点的配置?
2. 机器内存为什么需要预留一半给Lucene用?
3. 给ES内存配置是不是越大越好呢?
4. Swapping为什么会是性能的瓶颈?
集群节点规划
节点职责单一,各司其职
elasticSearch的配置文件中有2个参数:node.master和node.data。这两个参数搭配使用时,能够帮助提供服务器性能。
[mw_shl_code=applescript,true]数据节点node.master: false node.data: true[/mw_shl_code] 该node服务器只作为一个数据节点,只用于存储索引数据。使该node服务器功能单一,只用于数据存储和数据查询,降低其资源消耗率。
[mw_shl_code=applescript,true]master节点node.master: true node.data: false[/mw_shl_code] 该node服务器只作为一个主节点,但不存储任何索引数据。该node服务器将使用自身空闲的资源,来协调各种创建索引请求或者查询请求,讲这些请求合理分发到相关的node服务器上。
[mw_shl_code=applescript,true]负载均衡节点 node.master: false node.data: false[/mw_shl_code] 该node服务器即不会被选作主节点,也不会存储任何索引数据。该服务器主要用于查询负载均衡。在查询的时候,通常会涉及到从多个node服务器上查询数据,并请 求分发到多个指定的node服务器,并对各个node服务器返回的结果进行一个汇总处理,最终返回给客户端。
关闭data节点服务器中的http功能
针对ElasticSearch集群中的所有数据节点,不用开启http服务。将其中的配置参数这样设置:http.enabled: false,同时也不要安装head, bigdesk, marvel等监控 插件,这样保证data节点服务器只需处理创建/更新/删除/查询索引数据等操作。
http功能可以在非数据节点服务器上开启,上述相关的监控插件也安装到这些服务器上,用于监控ElasticSearch集群状态等数据信息。
这样做一来出于数据安全考虑,二来出于服务性能考虑。
一台服务器上最好只部署一个Node
一台物理服务器上可以启动多个Node服务器节点(通过设置不同的启动port),但一台服务器上的CPU,内存,硬盘等资源毕竟有限,从服务器性能考虑,不建议一台服务器上启动多个node节点。
在大规模局点,比如100个点,可以专门配备3个Master,可使用3台具有内存的刀片即可,即参数配置为node.master: true,node.data: false;可以按比例配备数据汇聚节点,比如10个,即参数配置为node.master: false ,node.data: false;小规模节点,可以不用如此设置,当然如果依然有性能问题,也是一个优化的措施。
机器设置(内存)
预留一半内存给Lucene使用
一个常见的问题是配置堆太大。你有一个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才采用内存对象指针压缩技术,不然对象指针需要占用很大的内存。
使用如下命令测试最大边界值:
[mw_shl_code=applescript,true]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[/mw_shl_code]
在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。这样可以暂时禁用:
[mw_shl_code=applescript,true]sudo swapoff -a[/mw_shl_code]
为了永久禁用它,你可能需要修改/etc/fstab文件,这要参考你的操作系统相关文档。
如果完全禁用swap,对你来说是不可行的。你可以降低swappiness 的值,这个值决定操作系统交换内存的频率。这可以预防正常情况下发生交换。但仍允许os在紧急情况下发生交换。对于大部分Linux操作系统,可以在sysctl 中这样配置:
[mw_shl_code=applescript,true]vm.swappiness = 1[/mw_shl_code]
备注:swappiness设置为1比设置为0要好,因为在一些内核版本,swappness=0会引发OOM(内存溢出)
最后,如果上面的方法都不能做到,你需要打开配置文件中的mlockall开关,它的作用就是运行JVM锁住内存,禁止OS交换出去。在elasticsearch.yml配置如下:
[mw_shl_code=applescript,true]bootstrap.mlockall: true[/mw_shl_code]
来源:简书
作者:jacksu在简书
|
|