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
要永久禁用它,你可能需要編輯你的/ etc / fstab。
方式二:控制作業系統嘗試交換記憶體的積極性。
如果完全禁用交換不是一種選擇,您可以嘗試降低swappiness。該值控制作業系統嘗試交換記憶體的積極性。這可以防止在正常情況下交換,但仍然允許作業系統在緊急記憶體情況下進行交換。
對于大多數Linux系統,這是使用sysctl值配置的:
vm.swappiness = 1
1的swappiness優于0,因為在某些核心版本上,swappiness為0可以調用OOM殺手。
方式三:mlockall允許JVM鎖定其記憶體并防止其被作業系統交換。
最後,如果兩種方法都不可行,則應啟用mlockall。檔案。這允許JVM鎖定其記憶體并防止其被作業系統交換。在你的elasticsearch.yml中,設定這個:
bootstrap.mlockall:true
10、注意
- 修改JVM相關配置很容易,但容易産生難以測量的不透明效果,并最終将您的群集解調為緩慢,不穩定的混亂
- 在調試群集時,第一步通常是删除所有自定義配置。大約一半的時間,僅靠這一點就恢複了穩定性和性能。
11、最新認知
wood@Ctrip
事實上,給ES配置設定的記憶體有一個魔法上限值26GB,
這樣可以確定啟用zero based Compressed Oops,這樣性能才是最佳的。
參考:
https://elasticsearch.cn/question/3995 https://www.elastic.co/blog/a-heap-of-trouble12、小結
這是一篇官網文檔&原理的整合文章,主要目的是梳理認知。
13、參考
基礎:
http://t.cn/RH4DDYu設定:
http://t.cn/RmKbO1i建議:
http://t.cn/RmKbjsF注意:
http://t.cn/RmKbHp5堆:
http://t.cn/RmKbRji作者:銘毅天下
原文:
https://blog.csdn.net/laoyang360/article/details/79998974