ES 內存管理分析
命令 GET _cat/nodes?help 列出所有node, 并展示node所在機器的運行狀態信息,help可顯示幫助信息
1
|
GET _cat/nodes?h=name,hp,hm,rp,rm,qcm,rcm,fm,sm&v
|
解析下上面參數的意義
信息如下:
以紅框里的node為例, 內存占用 = (8.6 gb)qcm + (1gb) rcm + (0.35gb) fm + (2.2 gb)sm,大約12 gb。
內存占用有2種,一種是ES可以管理的 on-heap 內存,另一種是由Lucene管理的 off-heap 內存。
On Heap
根據緩存占用的作用,可以分為以下五種緩存:節點查詢緩存、分片請求緩存、Fielddata Cache、Segments FST Cache、Indexing Buffer(無參數可看占用的大小)。
節點查詢緩存
Node Query Cache (node 級別的 filter 過濾器結果緩存), 每個節點有一個,被所有 shard 共享,filter query 結果要么是 yes 要么是no,不涉及 scores 的計算。使用LRU淘汰策略,內存無法被GC。
集群中每個節點都要配置,indices.queries.cache.size: 10%,默認為 10%。index.queries.cache.enabled 用來控制具體索引是否啟用緩存,默認是開啟的。屬于 index 級別配置,只用在索引創建時候或者關閉的索引上設置。
分片請求緩存
Shard Request Cache (shard 級別的 query result 緩存)每個 shard 一個,默認情況下該緩存只緩存 request 的結果 size 為0的查詢。所以該緩存不會緩存hits,但卻會緩存 hits.total, aggregations 和 suggestions,默認值:indices.requests.cache.size: 1%
Fielddata Cache
Field Data Cache (OLAP場景,用于排序、聚合使用的字段的緩存)。對于Text類型的字段,如果要對其進行聚合和排序,則需要打開字段的Fileddata屬性。Fielddata 是延遲加載。如果你從來沒有聚合一個分析字符串,就不會加載 fielddata 到內存中。如果沒有足夠的內存保存 fielddata 時,Elastisearch會不斷地從磁盤加載數據到內存,并剔除掉舊的內存數據。剔除操作會造成嚴重的磁盤I/O,并且引發大量的GC,會嚴重影響Elastisearch的性能。
通過參數 indices.fielddata.cache.size: 30% 配置,默認情況下Fielddata會不斷占用內存,無上限,直到它觸發了 fielddata circuit breaker。
fielddata circuit breaker會根據查詢條件評估這次查詢會使用多少內存,從而計算加載這部分內存之后,Field Data Cache所占用的內存是否會超過 indices.breaker.fielddata.limit。如果超過這個值,就會觸發fielddata circuit breaker,abort這次查詢并且拋出異常,防止OOM。
indices.breaker.fielddata.limit: 60% (默認heap的60%) ,如果設置了indices.fielddata.cache.size,當達到size時,cache會剔除舊的fielddata。注意,indices.breaker.fielddata.limit 必須大于 indices.fielddata.cache.size,否則只會觸發fielddata circuit breaker,而不會剔除舊的fielddata。
Segments FST Cache
Segments Cache(segments FST數據的緩存),為了加速查詢,FST 永駐堆內內存,無法被 GC 回收。該部分內存無法設置大小,減少data node上的segment memory占用,有三種方法:
- 刪除不用的索引。
- 關閉索引(文件仍然存在于磁盤,只是釋放掉內存),需要的時候可重新打開。
- 定期對不再更新的索引做force merge
解釋下FST
ES 底層存儲采用 Lucene(搜索引擎),寫入時會根據原始數據的內容,分詞,然后生成倒排索引。查詢時先通過查詢倒排索引找到數據地址(DocID),再讀取原始數據(行存數據、列存數據)。但由于 Lucene 會為原始數據中的每個詞都生成倒排索引,數據量較大。所以倒排索引對應的倒排表被存放在磁盤上。這樣如果每次查詢都直接讀取磁盤上的倒排表,再查詢目標關鍵詞,會有很多次磁盤 IO,嚴重影響查詢性能。為了解磁盤 IO 問題,Lucene 引入排索引的二級索引 FST [Finite State Transducer] 。原理上可以理解為前綴樹,加速查詢。
Indexing Buffer
Indexing Buffer 索引寫入緩沖區,用于存儲新寫入的文檔,當其被填滿時,緩沖區中的文檔被寫入磁盤中的 segments 中。節點上所有 shard 共享。這部分空間是可以被GC的,緩沖區默認大小 10%。
Off-heap
上面的提到的內存都是JVM管理的,ES能控制,即On-heap內存,ES還有Off-heap內存,由Lucene管理,負責緩存倒排索引(Segment Memory)。Lucene 中的倒排索引 segments 存儲在文件中,為提高訪問速度,都會把它加載到內存中,從而提高 Lucene 性能。
總結
緩存的清除
清除全部的緩存:
1
|
POST /_cache/clear
|
清除特定索引的緩存:
1
|
POST /my_index/_cache/clear
|
通過設置fielddata, query, request參數為true來清除特定類型的緩存清除特定類型緩存:
1
|
POST /my-index/_cache/clear?fielddata=true
|
通過上面分析,ES內存管理主要是謹慎對待unbounded的內存。unbounded內存是不可控的,會占用大量的 heap (Field Data Cache)或者 off heap(segments會長期占用內存,其初衷就是利用OS的cache提升性能。只有在Merge之后,才會釋放掉標記為Delete的segments,釋放部分內存),從而會導致Elasticsearch OOM。
查看Cache對應的類
一個小技巧,測試環境對ES jmap下,之后MAT分析,選擇dominator_tree,之后group by class,然后模糊匹配 Cache 關鍵字,之后可以看到一些關鍵類,比如IndicesRequestCache和IndicesFieldDataCache,而 FST Cache我還沒有找到對應的類,還需要繼續熟悉下代碼。

浙公網安備 33010602011771號