ES內存持續增長問題分析

環境介紹

es版本:5.6.4
-Xms31g -Xmx31g
-XX:MaxDirectMemorySize=10g

問題說明

用top命令觀察ES使用的物理內存不斷增加到54.6G
在這裏插入圖片描述
已知堆內存31G,堆外內存MaxDirectMemorySize 10G,那麼內存使用最高應該不超過41G纔對。現在內存使用了54.6G明顯超過了預估,那麼除了已知的41G外,還有哪些我們不知道的地方在佔用內存呢?

問題分析

爲了弄清楚54.6g內存有哪些部分組成,我打開了內存映射文件 /proc/ES進程號/smaps

在這裏插入圖片描述
首先我們截取文件中的一段來介紹怎麼看這個文件:

  • 7e1cde88b000-7e1ce4acf000 是該虛擬內存段的開始和結束位置
  • r–s內存段的權限,最後一位p代表私有,s代表共享
  • 00000000 該虛擬內存段在對應的映射文件中的偏移量
  • 08:20 文件的主設備和次設備號
  • 21365069 被映射到虛擬內存的文件的索引節點號
  • /mnt/ssd1/data/cluster001/SERVICE-ELASTICSEARCH-retro/nodes/0/indices/iB4FRrDrQNSxIp8-VAegbw/3/index/_841x.cfs
    被映射到虛擬內存的文件名稱。後面帶(deleted)的是內存數據,可以被銷燬。
  • size 是進程使用內存空間,並不一定實際分配了內存(VSS)
  • Rss是實際分配的內存(不需要缺頁中斷就可以使用的)
  • Pss是平攤計算後的使用內存(有些內存會和其他進程共享,例如mmap進來的)
  • Shared_Clean 和其他進程共享的未改寫頁面
  • Shared_Dirty 和其他進程共享的已改寫頁面
  • Private_Clean 未改寫的私有頁面頁面
  • Private_Dirty 已改寫的私有頁面頁面
  • Referenced 標記爲訪問和使用的內存大小
  • Anonymous 不來自於文件的內存大小
  • Swap 存在於交換分區的數據大小(如果物理內存有限,可能存在一部分在主存一部分在交換分區)
  • KernelPageSize 內核頁大小
  • MMUPageSize MMU頁大小,基本和Kernel頁大小相同

由介紹可以知道top命令中的RES表示進程實際佔有的內存大小,它通過把smaps文件中所有的Rss累計得到的。可以通過以下命令計算:

grep Rss smaps |awk 'BEGIN {sum = 0;} {sum += $2} END{print sum}'

在文件中我找到了31G堆內存的映射:
在這裏插入圖片描述
其中的Rss剛好等於31G。
而剩下內存的大部分被lucene文件佔用,我把lucene文件目錄部分的過濾出來,統計的Rss和有22G之多。
過濾和統計lucene文件佔用RSS的命令如下:

grep -A 5  'SERVICE-ELASTICSEARCH' smaps > lucene_smaps
grep Rss lucene_smaps |awk 'BEGIN {sum = 0;} {sum += $2} END{print sum}'

現在基本可以確定內存超出控制的元兇就是lucene文件的加載。而lucene文件所佔用的內存即不屬於JVM的堆內存,也不屬於MaxDirectMemorySize 控制的堆外內存。因此這塊內存是不受ES進程控制的。那麼爲什麼會加載這些Lucene文件呢?

這不得不讓我想到了ES的文件存儲類型。
5.6.4版本的ES支持simplefs,niofs,mmapfs這3中文件存儲類型,配置配置項index.store.type進行配置。可參考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/index-modules-store.html
我的環境默認使用的是mmapfs。這種存儲類型會將lucene索引文件用mmap的方式映射到內存中,這樣進程就能夠直接從內存中讀取lucene數據了。對mmap不瞭解可以參考:https://www.jianshu.com/p/da998d55ea36

由於使用了內存映射,es進程讀取lucene文件的時候讀取到的數據就會佔用了堆外內存的空間,數據讀取完畢後這塊內存空間會自動釋放。用於我的es環境在壓測,因此高併發,不間斷的查詢使得越來越多的數據被讀入堆外內存空間,導致ES進程的總體內存不斷上升。

問題解決

雖然es進程佔用的內存因爲加載lucene文件而升高,但這並不會成爲一個問題,因爲mmapfs佔用的內存是緩存類型的,當其他進程使用到這塊內存區域的時候,它將會釋放。

如果還是不放心,不希望看到RES指標持續增長的現象,可以將mmapfs模式修改爲niofs。這樣es就不會使用內存映射的方式了,堆外內存空間也不會上升,RES指標也就穩定了。不過官方還是推薦64位的linux系統使用mmapfs模式。

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