吃透Elasticsearch堆內(nèi)存
1.什么是堆內(nèi)存虎敦?
Java 中的堆是 JVM 所管理的最大的一塊內(nèi)存空間,它是Java內(nèi)存管理的核心區(qū)域,用來(lái)存放Java對(duì)象實(shí)例驻仅,幾乎所有創(chuàng)建的Java對(duì)象實(shí)例都是被直接分配在堆上。堆被所有的線程共享登渣,在虛擬機(jī)啟動(dòng)時(shí)噪服,我們指定的“Xmx”之類(lèi)參數(shù)就是用來(lái)指定最大堆空間等指標(biāo)。
理所當(dāng)然胜茧,堆也是垃圾收集器重點(diǎn)照顧的區(qū)域粘优,所以堆內(nèi)空間還會(huì)被不同的垃圾收集器進(jìn)行進(jìn)一步的細(xì)分仇味,
在 Java 中,堆被劃分成兩個(gè)不同的區(qū)域:
新生代 ( Young )
老年代 ( Old )
新生代 ( Young ) 又被劃分為三個(gè)區(qū)域
Eden
From Survivor
To Survivor
這樣劃分的目的是為了使 JVM 能夠更好的管理堆內(nèi)存中的對(duì)象雹顺,包括內(nèi)存的分配以及回收丹墨。
2.堆內(nèi)存的作用是什么?
在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建嬉愧。
堆內(nèi)存的唯一目的就是創(chuàng)建對(duì)象實(shí)例贩挣,所有的對(duì)象實(shí)例和數(shù)組都要在堆上分配。
堆是由垃圾回收來(lái)負(fù)責(zé)的没酣,因此也叫做“GC堆”王财,垃圾回收采用分代算法,堆由此分為新生代和老年代裕便。
堆的優(yōu)勢(shì)是可以動(dòng)態(tài)地分配內(nèi)存大小绒净,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存的偿衰,Java的垃圾收集器會(huì)自動(dòng)收走這些不再使用的數(shù)據(jù)挂疆。
但缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存哎垦,存取速度較慢囱嫩。當(dāng)堆內(nèi)存因?yàn)闈M了無(wú)法擴(kuò)展時(shí)就會(huì)拋出java.lang.OutOfMemoryError:Java heap space異常。出現(xiàn)這種情況的解決辦法具體參見(jiàn)java調(diào)優(yōu)漏设。
3.堆內(nèi)存如何配置墨闲?
默認(rèn)情況下,Elasticsearch JVM使用堆內(nèi)存最小和最大大小為2 GB(5.X版本以上)郑口。
早期版本默認(rèn)1GB鸳碧,官網(wǎng)指出:這明顯不夠。
在轉(zhuǎn)移到生產(chǎn)環(huán)境時(shí)犬性,配置足夠容量的堆大小以確保Elasticsearch功能和性能是必要的瞻离。
Elasticsearch將通過(guò)Xms(最小堆大小)和Xmx(最大堆大衅柜伞)設(shè)置來(lái)分配jvm.options中指定的整個(gè)堆套利。
舉例如下:
設(shè)置方式一:
在jvm.options配置文件中設(shè)置堆內(nèi)存。
-Xms2g
-Xmx2g
設(shè)置方式二:
通過(guò)環(huán)境變量設(shè)置鹤耍。
這可以通過(guò)注釋掉jvm.options文件中的Xms和Xmx設(shè)置并通過(guò)ES_JAVA_OPTS設(shè)置這些值來(lái)完成:
ES_JAVA_OPTS="-Xms2g -Xmx2g" ./bin/elasticsearch
ES_JAVA_OPTS="-Xms4000m -Xmx4000m" ./bin/elasticsearch
4.堆內(nèi)存的決定因素
堆內(nèi)存的值取決于服務(wù)器上可用的內(nèi)存大小肉迫。
5.堆內(nèi)存配置建議
將最小堆大小(Xms)和最大堆大懈寤啤(Xmx)設(shè)置為彼此相等喊衫。
Elasticsearch可用的堆越多,可用于緩存的內(nèi)存就越多杆怕。但請(qǐng)注意族购,太多的堆內(nèi)存可能會(huì)使您長(zhǎng)時(shí)間垃圾收集暫停壳贪。
將Xmx設(shè)置為不超過(guò)物理內(nèi)存的50%,以確保有足夠的物理內(nèi)存留給內(nèi)核文件系統(tǒng)緩存寝杖。
不要將Xmx設(shè)置為JVM超過(guò)32GB违施。
大小建議:
宿主機(jī)內(nèi)存大小的一半和31GB,取最小值朝墩。
6.堆內(nèi)存為什么不能超過(guò)物理機(jī)內(nèi)存的一半醉拓?
堆對(duì)于Elasticsearch絕對(duì)重要。
它被許多內(nèi)存數(shù)據(jù)結(jié)構(gòu)用來(lái)提供快速操作收苏。但還有另外一個(gè)非常重要的內(nèi)存使用者:Lucene亿卤。
Lucene旨在利用底層操作系統(tǒng)來(lái)緩存內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)。 Lucene段(segment)存儲(chǔ)在單個(gè)文件中鹿霸。因?yàn)槎问且怀刹蛔兊呐盼猓赃@些文件永遠(yuǎn)不會(huì)改變。這使得它們非常容易緩存懦鼠,并且底層操作系統(tǒng)將愉快地將熱段(hot segments)保留在內(nèi)存中以便更快地訪問(wèn)钻哩。這些段包括倒排索引(用于全文搜索)和文檔值(用于聚合)。
Lucene的性能依賴于與操作系統(tǒng)的這種交互肛冶。但是如果你把所有可用的內(nèi)存都給了Elasticsearch的堆街氢,那么Lucene就不會(huì)有任何剩余的內(nèi)存。這會(huì)嚴(yán)重影響性能睦袖。
標(biāo)準(zhǔn)建議是將可用內(nèi)存的50%提供給Elasticsearch堆珊肃,而將其他50%空閑。它不會(huì)被閑置; Lucene會(huì)高興地吞噬掉剩下的東西馅笙。
如果您不字符串字段上做聚合操作(例如伦乔,您不需要fielddata),則可以考慮進(jìn)一步降低堆董习。堆越小烈和,您可以從Elasticsearch(更快的GC)和Lucene(更多內(nèi)存緩存)中獲得更好的性能。
7.堆內(nèi)存為什么不能超過(guò)32GB皿淋?
在Java中招刹,所有對(duì)象都分配在堆上并由指針引用。普通的對(duì)象指針(OOP)指向這些對(duì)象窝趣,傳統(tǒng)上它們是CPU本地字的大蟹枋睢:32位或64位,取決于處理器高帖。
對(duì)于32位系統(tǒng),這意味著最大堆大小為4 GB畦粮。對(duì)于64位系統(tǒng)散址,堆大小可能會(huì)變得更大乖阵,但是64位指針的開(kāi)銷(xiāo)意味著僅僅因?yàn)橹羔樰^大而存在更多的浪費(fèi)空間。并且比浪費(fèi)的空間更糟糕预麸,當(dāng)在主存儲(chǔ)器和各種緩存(LLC瞪浸,L1等等)之間移動(dòng)值時(shí),較大的指針消耗更多的帶寬吏祸。
Java使用稱為壓縮oops的技巧來(lái)解決這個(gè)問(wèn)題对蒲。而不是指向內(nèi)存中的確切字節(jié)位置,指針引用對(duì)象偏移量贡翘。這意味著一個(gè)32位指針可以引用40億個(gè)對(duì)象蹈矮,而不是40億個(gè)字節(jié)。最終鸣驱,這意味著堆可以增長(zhǎng)到約32 GB的物理尺寸泛鸟,同時(shí)仍然使用32位指針。
一旦你穿越了這個(gè)神奇的?32 GB的邊界踊东,指針就會(huì)切換回普通的對(duì)象指針北滥。每個(gè)指針的大小增加,使用更多的CPU內(nèi)存帶寬闸翅,并且實(shí)際上會(huì)丟失內(nèi)存再芋。實(shí)際上,在使用壓縮oops獲得32 GB以下堆的相同有效內(nèi)存之前坚冀,需要大約40-50 GB的分配堆济赎。
以上小結(jié)為:即使你有足夠的內(nèi)存空間,盡量避免跨越32GB的堆邊界遗菠。
否則會(huì)導(dǎo)致浪費(fèi)了內(nèi)存联喘,降低了CPU的性能,并使GC在大堆中掙扎辙纬。
8.我是內(nèi)存土豪怎么辦豁遭?
假設(shè),我有一臺(tái)帶有1TB RAM的機(jī)器贺拣!
32 GB的基線相當(dāng)重要蓖谢。那么當(dāng)你的機(jī)器有很多內(nèi)存時(shí)你怎么做?當(dāng)前具有512-768 GB RAM的超級(jí)服務(wù)器變得越來(lái)越普遍譬涡。
首先闪幽,我們建議避免使用這種大型機(jī)器。
但是如果你已經(jīng)有了這些機(jī)器涡匀,你有三種實(shí)用的選擇:
- 1.你是否主要進(jìn)行全文搜索盯腌?
考慮給Elasticsearch提供4-32 GB,并讓Lucene通過(guò)操作系統(tǒng)文件系統(tǒng)緩存使用剩余的內(nèi)存陨瘩。所有內(nèi)存都會(huì)緩存段腕够,并導(dǎo)致快速全文搜索级乍。
- 2.你在做很多排序/聚合?
大部分聚合數(shù)字帚湘,日期玫荣,地理位置和not_analyzed字符串?你很幸運(yùn)大诸,你的聚合將在內(nèi)存緩存的文檔值上完成捅厂!
從4-32 GB的內(nèi)存中給Elasticsearch一個(gè)地方,剩下的讓操作系統(tǒng)在內(nèi)存中緩存doc值资柔。
-
3.你是否對(duì)分析過(guò)的字符串進(jìn)行了很多排序/聚合(例如對(duì)于字標(biāo)記或SigTerms等)焙贷?
不幸的是,這意味著你需要fielddata建邓,這意味著你需要堆空間盈厘。
考慮在一臺(tái)機(jī)器上運(yùn)行兩個(gè)或多個(gè)節(jié)點(diǎn),而不是一個(gè)節(jié)點(diǎn)數(shù)量巨大的RAM官边。
盡管如此沸手,仍然堅(jiān)持50%的規(guī)則。
To土豪內(nèi)存小結(jié):
因此注簿,如果您的機(jī)器具有128 GB的RAM契吉,請(qǐng)運(yùn)行兩個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)的容量低于32 GB诡渴。這意味著小于64 GB將用于堆捐晶,而Lucene將剩余64 GB以上。
如果您選擇此選項(xiàng)妄辩,請(qǐng)?jiān)谀呐渲弥性O(shè)置cluster.routing.allocation.same_shard.host:true惑灵。這將阻止主副本分片共享同一臺(tái)物理機(jī)(因?yàn)檫@會(huì)消除副本高可用性的好處)。
9.堆內(nèi)存優(yōu)化建議
- 方式一:最好的辦法是在系統(tǒng)上完全禁用交眼耀。
這可以暫時(shí)完成:
sudo swapoff -a
要永久禁用它英支,你可能需要編輯你的/ etc / fstab。
- 方式二:控制操作系統(tǒng)嘗試交換內(nèi)存的積極性哮伟。
如果完全禁用交換不是一種選擇干花,您可以嘗試降低swappiness。該值控制操作系統(tǒng)嘗試交換內(nèi)存的積極性楞黄。這可以防止在正常情況下交換池凄,但仍然允許操作系統(tǒng)在緊急內(nèi)存情況下進(jìn)行交換。
對(duì)于大多數(shù)Linux系統(tǒng)鬼廓,這是使用sysctl值配置的:
vm.swappiness = 1
1的swappiness優(yōu)于0肿仑,因?yàn)樵谀承﹥?nèi)核版本上,swappiness為0可以調(diào)用OOM殺手。
- 方式三:mlockall允許JVM鎖定其內(nèi)存并防止其被操作系統(tǒng)交換尤慰。
最后勾邦,如果兩種方法都不可行,則應(yīng)啟用mlockall割择。文件。這允許JVM鎖定其內(nèi)存并防止其被操作系統(tǒng)交換萎河。在你的elasticsearch.yml中荔泳,設(shè)置這個(gè):
bootstrap.mlockall:true
10.注意
修改JVM相關(guān)配置很容易,但容易產(chǎn)生難以測(cè)量的不透明效果虐杯,并最終將您的群集解調(diào)為緩慢玛歌,不穩(wěn)定的混亂
在調(diào)試群集時(shí),第一步通常是刪除所有自定義配置擎椰。大約一半的時(shí)間支子,僅靠這一點(diǎn)就恢復(fù)了穩(wěn)定性和性能。
11.最新認(rèn)知
wood@Ctrip
事實(shí)上达舒,給ES分配的內(nèi)存有一個(gè)魔法上限值26GB值朋,
這樣可以確保啟用zero based Compressed Oops,這樣性能才是最佳的巩搏。
參考:
https://elasticsearch.cn/question/3995
https://www.elastic.co/blog/a-heap-of-trouble
12.小結(jié)
這是一篇官網(wǎng)文檔&原理的整合文章昨登,主要目的是梳理認(rèn)知。
切記:宿主機(jī)內(nèi)存大小的一半和31GB贯底,取最小值丰辣。
參考:
基礎(chǔ):http://t.cn/RH4DDYu
設(shè)置:http://t.cn/RmKbO1i