1. 程式人生 > >elasticsearch JVM優化配置-官網

elasticsearch JVM優化配置-官網

        Elasticsearch 預設安裝後設置的堆記憶體是 1 GB。 對於任何一個業務部署來說, 這個設定都太小了。如果你正在使用這些預設堆記憶體配置,您的叢集可能會出現問題。

        這裡有兩種方式修改 Elasticsearch 的堆記憶體。最簡單的一個方法就是指定 ES_HEAP_SIZE 環境變數。服務程序在啟動時候會讀取這個變數,並相應的設定堆的大小。 比如,你可以用下面的命令設定它:

export ES_HEAP_SIZE=10g

       此外,你也可以通過命令列引數的形式,在程式啟動的時候把記憶體大小傳遞給它,如果你覺得這樣更簡單的話:

./bin/elasticsearch -Xmx10g -Xms10g 

確保堆記憶體最小值( Xms )與最大值( Xmx )的大小是相同的,防止程式在執行時改變堆記憶體大小, 這是一個很耗系統資源的過程。

        通常來說,設定 ES_HEAP_SIZE 環境變數,比直接寫 -Xmx -Xms 更好一點。

把你的記憶體的(少於)一半給 Lucene編輯

        一個常見的問題是給 Elasticsearch 分配的記憶體 

 大了。 假設你有一個 64 GB 記憶體的機器, 天啊,我要把 64 GB 記憶體全都給 Elasticsearch。因為越多越好啊!

       當然,記憶體對於 Elasticsearch 來說絕對是重要的,它可以被許多記憶體資料結構使用來提供更快的操作。但是說到這裡, 還有另外一個記憶體消耗大戶 非堆記憶體 (off-heap):Lucene。

       Lucene 被設計為可以利用作業系統底層機制來快取記憶體資料結構。 Lucene 的段是分別儲存到單個檔案中的。因為段是不可變的,這些檔案也都不會變化,這是對快取友好的,同時作業系統也會把這些段檔案快取起來,以便更快的訪問。

     Lucene 的效能取決於和作業系統的相互作用。如果你把所有的記憶體都分配給 Elasticsearch 的堆記憶體,那將不會有剩餘的記憶體交給 Lucene。 這將嚴重地影響全文檢索的效能。

      標準的建議是把 50% 的可用記憶體作為 Elasticsearch 的堆記憶體,保留剩下的 50%。當然它也不會被浪費,Lucene 會很樂意利用起餘下的記憶體。

      如果你不需要對分詞字串做聚合計算(例如,不需要 fielddata )可以考慮降低堆記憶體。堆記憶體越小,Elasticsearch(更快的 GC)和 Lucene(更多的記憶體用於快取)的效能越好。

不要超過 32 GB!編輯

        這裡有另外一個原因不分配大記憶體給 Elasticsearch。事實上 , JVM 在記憶體小於 32 GB 的時候會採用一個記憶體物件指標壓縮技術。

        在 Java 中,所有的物件都分配在堆上,並通過一個指標進行引用。 普通物件指標(OOP)指向這些物件,通常為 CPU 字長 的大小:32 位或 64 位,取決於你的處理器。指標引用的就是這個 OOP 值的位元組位置。

        對於 32 位的系統,意味著堆記憶體大小最大為 4 GB。對於 64 位的系統, 可以使用更大的記憶體,但是 64 位的指標意味著更大的浪費,因為你的指標本身大了。更糟糕的是, 更大的指標在主記憶體和各級快取(例如 LLC,L1 等)之間移動資料的時候,會佔用更多的頻寬。

       Java 使用一個叫作 記憶體指標壓縮(compressed oops)的技術來解決這個問題。 它的指標不再表示物件在記憶體中的精確位置,而是表示 偏移量 。這意味著 32 位的指標可以引用 40 億個 物件 , 而不是 40 億個位元組。最終, 也就是說堆記憶體增長到 32 GB 的實體記憶體,也可以用 32 位的指標表示。

        一旦你越過那個神奇的 ~32 GB 的邊界,指標就會切回普通物件的指標。 每個物件的指標都變長了,就會使用更多的 CPU 記憶體頻寬,也就是說你實際上失去了更多的記憶體。事實上,當記憶體到達 40–50 GB 的時候,有效記憶體才相當於使用記憶體物件指標壓縮技術時候的 32 GB 記憶體。

       這段描述的意思就是說:即便你有足夠的記憶體,也儘量不要 超過 32 GB。因為它浪費了記憶體,降低了 CPU 的效能,還要讓 GC 應對大記憶體。

到底需要低於 32 GB多少,來設定我的 JVM?編輯

        遺憾的是,這需要看情況。確切的劃分要根據 JVMs 和作業系統而定。 如果你想保證其安全可靠,設定堆記憶體為 31 GB 是一個安全的選擇。 另外,你可以在你的 JVM 設定裡新增 -XX:+PrintFlagsFinal 用來驗證 JVM 的臨界值, 並且檢查 UseCompressedOops 的值是否為 true。對於你自己使用的 JVM 和作業系統,這將找到最合適的堆記憶體臨界值。

        例如,我們在一臺安裝 Java 1.7 的 MacOSX 上測試,可以看到指標壓縮在被禁用之前,最大堆記憶體大約是在 32600 mb(~31.83 gb):

$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32600m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   := true
$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   = false

        相比之下,同一臺機器安裝 Java 1.8,可以看到指標壓縮在被禁用之前,最大堆記憶體大約是在 32766 mb(~31.99 gb):

$ 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

        這個例子告訴我們,影響記憶體指標壓縮使用的臨界值, 是會根據 JVM 的不同而變化的。 所以從其他地方獲取的例子,需要謹慎使用,要確認檢查作業系統配置和 JVM。

       如果使用的是 Elasticsearch v2.2.0,啟動日誌其實會告訴你 JVM 是否正在使用記憶體指標壓縮。 你會看到像這樣的日誌訊息:

[2015-12-16 13:53:33,417][INFO ][env] [Illyana Rasputin] heap size [989.8mb], compressed ordinary object pointers [true]

       這表明記憶體指標壓縮正在被使用。如果沒有,日誌訊息會顯示 [false] 。

我有一個 1 TB 記憶體的機器!

       這個 32 GB 的分割線是很重要的。那如果你的機器有很大的記憶體怎麼辦呢? 一臺有著 512–768 GB記憶體的伺服器愈發常見。

      首先,我們建議避免使用這樣的高配機器(參考 硬體)。

      但是如果你已經有了這樣的機器,你有三個可選項:

  • 你主要做全文檢索嗎?考慮給 Elasticsearch 4 - 32 GB 的記憶體, 讓 Lucene 通過作業系統檔案快取來利用餘下的記憶體。那些記憶體都會用來快取 segments,帶來極速的全文檢索。
  • 你需要更多的排序和聚合?而且大部分的聚合計算是在數字、日期、地理點和 非分詞 字串上?你很幸運,你的聚合計算將在記憶體友好的 doc values 上完成! 給 Elasticsearch 4 到 32 GB 的記憶體,其餘部分為作業系統快取記憶體中的 doc values。
  • 你在對分詞字串做大量的排序和聚合(例如,標籤或者 SigTerms,等等)不幸的是,這意味著你需要 fielddata,意味著你需要堆空間。考慮在單個機器上執行兩個或多個節點,而不是擁有大量 RAM 的一個節點。仍然要堅持 50% 原則。

       假設你有個機器有 128 GB 的記憶體,你可以建立兩個節點,每個節點記憶體分配不超過 32 GB。 也就是說不超過 64 GB 記憶體給 ES 的堆記憶體,剩下的超過 64 GB 的記憶體給 Lucene。

       如果你選擇這一種,你需要配置 cluster.routing.allocation.same_shard.host: true 。 這會防止同一個分片(shard)的主副本存在同一個物理機上(因為如果存在一個機器上,副本的高可用性就沒有了)。

Swapping 是效能的墳墓編輯

       這是顯而易見的, 但是還是有必要說的更清楚一點:記憶體交換 到磁碟對伺服器效能來說是 致命 的。想想看:一個記憶體操作必須能夠被快速執行。

      如果記憶體交換到磁碟上,一個 100 微秒的操作可能變成 10 毫秒。 再想想那麼多 10 微秒的操作時延累加起來。 不難看出 swapping 對於效能是多麼可怕。

     最好的辦法就是在你的作業系統中完全禁用 swap。這樣可以暫時禁用:

sudo swapoff -a

     如果需要永久禁用,你可能需要修改 /etc/fstab 檔案,這要參考你的作業系統相關文件。

     如果你並不打算完全禁用 swap,也可以選擇降低 swappiness 的值。 這個值決定作業系統交換記憶體的頻率。 這可以預防正常情況下發生交換,但仍允許作業系統在緊急情況下發生交換。

     對於大部分Linux作業系統,可以在 sysctl 中這樣配置:

vm.swappiness = 1 

swappiness 設定為 1 比設定為 0 要好,因為在一些核心版本 swappiness 設定為 0 會觸發系統 OOM-killer(注:Linux 核心的 Out of Memory(OOM)killer 機制)。

      最後,如果上面的方法都不合適,你需要開啟配置檔案中的 mlockall 開關。 它的作用就是允許 JVM 鎖住記憶體,禁止作業系統交換出去。在你的 elasticsearch.yml 檔案中,設定如下:

bootstrap.mlockall: true