標籤:

ElasticSearch優化系列二:機器設置(內存)

歡迎關注我們的微信公眾號「人工智慧LeadAI」(ID:atleadai)

預留一半內存給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 nbool UseCompressedOops = false {lp64_product} njava -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops n bool UseCompressedOops = true {lp64_product} n$ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops nbool UseCompressedOops := truen $ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32767m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOopsnbool UseCompressedOops = falsen

在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

未完待續


推薦閱讀:

Elasticsearch到底能玩多大的數據量?
Elastic Stack 5.0升級踩坑記
elasticsearch,我用ik分詞,搜索"寶馬2012",怎樣只查出即包含「寶馬」又包含「2012」的文章?
使用ElasticSearch搭建日誌系統

TAG:Elasticsearch |