1. 程式人生 > >Elasticsearch 合理記憶體分配

Elasticsearch 合理記憶體分配

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

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

export ES_HEAP_SIZE=10g

此外,你也可以通過命令列引數的形式,在程式啟動的時候把記憶體大小傳遞給它:

./bin/elasticsearch -Xmx10g -Xms10g

備註:確保Xmx和Xms的大小是相同的,防止程式在執行時改變大小,這個是很廢的。

一般來說設定ES_HEAP_SIZE環境變數,比直接寫-Xmx10g -Xms10g更好一點。

把你的記憶體的一半給Lucene

一個常見的問題是配置一個大記憶體,假設你有一個64G記憶體的機器,我的天,你想把64G記憶體給Elasticsearch嗎? 越大越好!

當然,記憶體對於Elasticsearch來說絕對是重要的,用於更多的記憶體資料提供更快的操作。而且還有一個記憶體消耗大戶-Lucene

Lucene的設計目的是把底層OS裡的資料快取到記憶體中。Lucene的段是分別儲存到單個檔案中的,這些檔案都是不會變化的,所以很利於快取,同時作業系統也會把這些段檔案快取起來,以便更快的訪問。

Lucene的效能取決於和OS的互動,如果你把所有的記憶體都分配給Elasticsearch,不留一點給Lucene,那你的全文檢索效能會很差的。

最後標準的建議是把50%的記憶體給elasticsearch,剩下的50%也不會沒有用處的,Lucene會很快吞噬剩下的這部分記憶體。

不要超過32G

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

在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應對大記憶體。

*我有一個1TB記憶體的機器
這個32GB的線是很很重要的,那如果你的機器有很大的記憶體怎麼辦呢?現在的機器記憶體普遍增長,你現在都可以看到有300-500GB記憶體的機器。
首先,我們建議編碼使用這樣的大型機
其次,如果你已經有了這樣的機器,你有兩個可選項:
>你主要做全文檢索嗎?考慮給Elasticsearch 32G記憶體,剩下的交給Lucene用作作業系統的檔案系統快取,所有的segment都快取起來,會加快全文檢索。
>你需要更多的排序和聚合?你希望更大的堆記憶體。你可以考慮一臺機器上建立兩個或者更多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

參考地址:https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html.