05-乾貨 | 吃透Elasticsearch 堆記憶體
1、什麼是堆記憶體?
Java 中的堆是 JVM 所管理的最大的一塊記憶體空間,主要用於存放各種類的例項物件。
在 Java 中,堆被劃分成兩個不同的區域:
新生代 ( Young )、
老年代 ( Old )。
新生代 ( Young ) 又被劃分為三個區域
:
Eden、
From Survivor、
To Survivor。
這樣劃分的目的是為了使 JVM 能夠更好的管理堆記憶體中的物件,包括記憶體的分配以及回收。
2、堆記憶體的作用是什麼?
在虛擬機器啟動時建立。
堆記憶體的唯一目的就是建立物件例項,所有的物件例項和陣列都要在堆上分配。
堆是由垃圾回收來負責的,因此也叫做“GC堆”,垃圾回收採用分代演算法,堆由此分為新生代和老年代。
堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,因為它是在執行時動態分配記憶體的,Java的垃圾收集器會自動收走這些不再使用的資料。
但缺點是,由於要在執行時動態分配記憶體,存取速度較慢。當堆記憶體因為滿了無法擴充套件時就會丟擲java.lang.OutOfMemoryError:Java heap space異常。出現這種情況的解決辦法具體參見java調優。
3、堆記憶體如何配置?
預設情況下,Elasticsearch JVM使用堆記憶體最小和最大大小為2 GB(5.X版本以上)。
早期版本預設1GB,官網指出:這明顯不夠。
在轉移到生產環境時,配置足夠容量的堆大小以確保Elasticsearch功能和效能是必要的。
Elasticsearch將通過Xms(最小堆大小)和Xmx(最大堆大小)設定來分配jvm.options中指定的整個堆。
舉例如下:
設定方式一:
在jvm.option配置檔案中設定堆記憶體。
-Xms2g
-Xmx2g
設定方式二:
通過環境變數設定。
這可以通過註釋掉jvm.options檔案中的Xms和Xmx設定並通過ES_JAVA_OPTS設定這些值來完成:
ES_JAVA_OPTS="-Xms2g -Xmx2g" ./bin/elasticsearch ES_JAVA_OPTS="-Xms4000m -Xmx4000m" ./bin/elasticsearch
4、堆記憶體的決定因素
堆記憶體的值取決於伺服器上可用的記憶體大小。
5、堆記憶體配置建議
將最小堆大小(Xms)和最大堆大小(Xmx)設定為彼此相等。
Elasticsearch可用的堆越多,可用於快取的記憶體就越多。但請注意,太多的堆記憶體可能會使您長時間垃圾收集暫停。
將Xmx設定為不超過實體記憶體的50%,以確保有足夠的實體記憶體留給核心檔案系統快取。
- 不要將Xmx設定為JVM超過32GB。
大小建議:
宿主機記憶體大小的一半和31GB,取最小值。
6、堆記憶體為什麼不能超過物理機記憶體的一半?
堆對於Elasticsearch絕對重要。
它被許多記憶體資料結構用來提供快速操作。但還有另外一個非常重要的記憶體使用者:Lucene。
Lucene旨在利用底層作業系統來快取記憶體中的資料結構。 Lucene段(segment)儲存在單個檔案中。因為段是一成不變的,所以這些檔案永遠不會改變。這使得它們非常容易快取,並且底層作業系統將愉快地將熱段(hot segments)保留在記憶體中以便更快地訪問。這些段包括倒排索引(用於全文搜尋)和文件值(用於聚合)。
Lucene的效能依賴於與作業系統的這種互動。但是如果你把所有可用的記憶體都給了Elasticsearch的堆,那麼Lucene就不會有任何剩餘的記憶體。這會嚴重影響效能。
標準建議是將可用記憶體的50%提供給Elasticsearch堆,而將其他50%空閒。它不會被閒置; Lucene會高興地吞噬掉剩下的東西。
如果您不字串欄位上做聚合操作(例如,您不需要fielddata),則可以考慮進一步降低堆。堆越小,您可以從Elasticsearch(更快的GC)和Lucene(更多記憶體快取)中獲得更好的效能。
7、堆記憶體為什麼不能超過32GB?
在Java中,所有物件都分配在堆上並由指標引用。普通的物件指標(OOP)指向這些物件,傳統上它們是CPU本地字的大小:32位或64位,取決於處理器。
對於32位系統,這意味著最大堆大小為4 GB。對於64位系統,堆大小可能會變得更大,但是64位指標的開銷意味著僅僅因為指標較大而存在更多的浪費空間。並且比浪費的空間更糟糕,當在主儲存器和各種快取(LLC,L1等等)之間移動值時,較大的指標消耗更多的頻寬。
Java使用稱為壓縮oops的技巧來解決這個問題。而不是指向記憶體中的確切位元組位置,指標引用物件偏移量。這意味著一個32位指標可以引用40億個物件,而不是40億個位元組。最終,這意味著堆可以增長到約32 GB的物理尺寸,同時仍然使用32位指標。
一旦你穿越了這個神奇的〜32 GB的邊界,指標就會切換回普通的物件指標。每個指標的大小增加,使用更多的CPU記憶體頻寬,並且實際上會丟失記憶體。實際上,在使用壓縮oops獲得32 GB以下堆的相同有效記憶體之前,需要大約40-50 GB的分配堆。
以上小結為:即使你有足夠的記憶體空間,儘量避免跨越32GB的堆邊界。
否則會導致浪費了記憶體,降低了CPU的效能,並使GC在大堆中掙扎。
8、我是記憶體土豪怎麼辦?
假設,我有一臺帶有1TB RAM的機器!
32 GB的基線相當重要。那麼當你的機器有很多記憶體時你怎麼做?當前具有512-768 GB RAM的超級伺服器變得越來越普遍。
首先,我們建議避免使用這種大型機器。
但是如果你已經有了這些機器,你有三種實用的選擇:
1. 你是否主要進行全文搜尋?
考慮給Elasticsearch提供4-32 GB,並讓Lucene通過作業系統檔案系統快取使用剩餘的記憶體。所有記憶體都會快取段,並導致快速全文搜尋。
2. 你在做很多排序/聚合?
大部分聚合數字,日期,地理位置和not_analyzed字串?你很幸運,你的聚合將在記憶體快取的文件值上完成!
從4-32 GB的記憶體中給Elasticsearch一個地方,剩下的讓作業系統在記憶體中快取doc值。
3. 你是否對分析過的字串進行了很多排序/聚合(例如對於字標記或SigTerms等)?
不幸的是,這意味著你需要fielddata,這意味著你需要堆空間。
考慮在一臺機器上執行兩個或多個節點,而不是一個節點數量巨大的RAM。
儘管如此,仍然堅持50%的規則。
To土豪記憶體小結:
因此,如果您的機器具有128 GB的RAM,請執行兩個節點,每個節點的容量低於32 GB。這意味著小於64 GB將用於堆,而Lucene將剩餘64 GB以上。
如果您選擇此選項,請在您的配置中設定cluster.routing.allocation.same_shard.host:true。這將阻止主副本分片共享同一臺物理機(因為這會消除副本高可用性的好處)。
9、堆記憶體優化建議
方式一:最好的辦法是在系統上完全禁用交。
這可以暫時完成:
sudo swapoff -a
如果完全禁用交換不是一種選擇,您可以嘗試降低swappiness。該值控制作業系統嘗試交換記憶體的積極性。這可以防止在正常情況下交換,但仍然允許作業系統在緊急記憶體情況下進行交換。
對於大多數Linux系統,這是使用sysctl值配置的:
vm.swappiness = 1
1的swappiness優於0,因為在某些核心版本上,swappiness為0可以呼叫OOM殺手。
方式三:mlockall允許JVM鎖定其記憶體並防止其被作業系統交換。
最後,如果兩種方法都不可行,則應啟用mlockall。檔案。這允許JVM鎖定其記憶體並防止其被作業系統交換。在你的elasticsearch.yml中,設定這個:
bootstrap.mlockall:true
10、注意
- 修改JVM相關配置很容易,但容易產生難以測量的不透明效果,並最終將您的群集解調為緩慢,不穩定的混亂
- 在除錯群集時,第一步通常是刪除所有自定義配置。大約一半的時間,僅靠這一點就恢復了穩定性和效能。
11、最新認知
事實上,給ES分配的記憶體有一個魔法上限值26GB,
這樣可以確保啟用zero based Compressed Oops,這樣效能才是最佳的
原文部落格 https://blog.csdn.net/laoyang360/article/details/79998974