ElasticSearch 內存分配

Lucene 被設計爲可以利用操作系統底層機制來緩存內存數據結構。 Lucene 的段是分別存儲到單個文件中的。因爲段是不可變的,這些文件也都不會變化,這是對緩存友好的,同時操作系統也會把這些段文件緩存起來,以便更快的訪問。

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

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

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

給ES分配的內存有一個魔法上限值26GB,這樣可以確保啓用zero based Compressed Oops,這個值因不同OS可能有差異,可以通過 zero based Compressed Oops 這個輸出來確定最大值,這樣性能纔是最佳的。參考:
https://www.elastic.co/blog/a-heap-of-trouble
https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#zeroBasedCompressedOop

Zero-Based Compressed Ordinary Object Pointers (oops)
When using compressed oops in a 64-bit Java Virtual Machine process, the JVM software asks the operating system to reserve memory for the Java heap starting at virtual address zero. If the operating system supports such a request and can reserve memory for the Java heap at virtual address zero, then zero-based compressed oops are used.

Use of zero-based compressed oops means that a 64-bit pointer can be decoded from a 32-bit object offset without adding in the Java heap base address. For heap sizes less than 4 gigabytes, the JVM software can use a byte offset instead of an object offset and thus also avoid scaling the offset by 8. Encoding a 64-bit address into a 32-bit offset is correspondingly efficient.

For Java heap sizes up around 26 gigabytes, any of Solaris, Linux, and Windows operating systems will typically be able to allocate the Java heap at virtual address zero.

1、將Java Heap Size設置的大於32G會對性能有什麼影響?
開門見山的說,結果有幾點(這幾點其實也是內部關聯):

觸發JVM的臨界值,優化策略Compressed OOPS失效(之前Heap Size在[4G~32G]區間內採用此優化)

由於優化策略失效,同時堆內存>32G,所以JVM被迫使用8字節(64位)來對Java對象尋址(之前4字節(32位)就夠了)

通常64位JVM消耗的內存會比32位的大1.5倍,這是因爲對象指針在64位架構下,長度會翻倍(事實上當內存到達40-50GB的時候,有效內存才相當於使用Compressed OOPS技術時候的32G內存)

更大的指針在主內存和緩存器(例如LLC, L1等)之間移動數據的時候,會佔用更多的帶寬

讓JVM的GC面臨更大壓力的指針對象(在實際應用中構建大於12-16G的堆時,若無很好的性能調優與測評,你很容易就會引起一個耗時數分鐘的完全GC)

1.1 JVM的OOPS
OOP = “ordinary object pointer” 普通對象指針

啓用CompressOops後,會壓縮的對象:

每個class的屬性指針(靜態成員變量)

每個對象的屬性指針

普通對象數組的每個元素指針

1.2 JVM的優化策略Compressed OOPS
從JDK 1.6 update14開始,64 bit JVM正式支持了 -XX:+UseCompressedOops ,這個可以壓縮指針,起到節約內存佔用的新參數。

Compressed OOPS,即大霧的對象壓縮技術,壓縮引用到32位,以降低堆的佔用空間。其僞代碼原理就不貼了,

在堆大小在[4G~32G]的時候,這項技術會被觸發,在JVM執行時加入編/解碼指令,即

JVM在將對象存入堆時編碼,在堆中讀取對象時解碼

內存地址確定公式類似於

1

swap(交換區)是性能終結者

**
這應該顯而易見了,但仍然需要明確的寫出來:把內存換成硬盤將毀掉服務器的性能,想象一下:涉及內存的操作是需要快速執行的。如果介質從內存變爲了硬盤,一個10微秒的操作變成需要10毫秒。而且這種延遲發生在所有本該只花費10微秒的操作上,就不難理解爲什麼交換區對於性能來說是噩夢。

最好的選擇是禁用掉操作系統的交換區。可以用以下命令:

sudo swapoff -a

來禁用,你可能還需要編輯/etc/fstab文件。細節可以參考你的操作系統文檔。

如果實際環境不允許禁用掉swap,你可以嘗試降低swappiness。此值控制操作系統使用交換區的積極性。這可以防止在正常情況下使用交換區,但仍允許操作系統在緊急情況下將內存裏的東西放到交換區。

對於大多數Linux系統來說,這可以用sysctl值來配置:

vm.swappiness = 1

  • 將此值配置爲1會比0好,在kernal內核的某些版本中,0可能會引起OOM異常。
    最後,如果兩種方法都不可用,你應該在ElasticSearch的配置中啓用mlockall.file。這允許JVM鎖定其使用的內存,而避免被放入操作系統交換區。

在elasticsearch.yml中,做如下設置:

bootstrap.mlockall: true

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章