以下分別解讀幾個我知道的內(nèi)存消耗大戶:
Segment Memory
Segment不是file嗎?segment memory又是什么壹瘟?前面提到過,一個segment是一個完備的lucene倒排索引,而倒排索引是通過詞典(Term Dictionary)到文檔列表(Postings List)的映射關(guān)系,快速做查詢的盈蛮。由于詞典的size會很大,全部裝載到heap里不現(xiàn)實技矮,因此Lucene為詞典做了一層前綴索引(Term Index)抖誉,這個索引在Lucene4.0以后采用的數(shù)據(jù)結(jié)構(gòu)是FST (Finite State
Transducer)。這種數(shù)據(jù)結(jié)構(gòu)占用空間很小衰倦,Lucene打開索引的時候?qū)⑵淙垦b載到內(nèi)存中袒炉,加快磁盤上詞典查詢速度的同時減少隨機磁盤訪問次數(shù)。
下面是詞典索引和詞典主存儲之間的一個對應(yīng)關(guān)系圖:
說了這么多樊零,要傳達的一個意思就是我磁,ES的data node存儲數(shù)據(jù)并非只是耗費磁盤空間的,為了加速數(shù)據(jù)的訪問驻襟,每個segment都有會一些索引數(shù)據(jù)駐留在heap里夺艰。因此segment越多,瓜分掉的heap也越多沉衣,并且這部分heap是無法被GC掉的郁副! 理解這點對于監(jiān)控和管理集群容量很重要,當一個node的segment memory占用過多的時候厢蒜,就需要考慮刪除霞势、歸檔數(shù)據(jù)烹植,或者擴容了。
怎么知道segment memory占用情況呢? CAT API可以給出答案愕贡。
- 查看一個索引所有segment的memory占用情況:
- 查看一個node上所有segment占用的memory總和:
那么有哪些途徑減少data node上的segment memory占用呢草雕?總結(jié)起來有三種方法:
刪除不用的索引。
關(guān)閉索引(文件仍然存在于磁盤固以,只是釋放掉內(nèi)存)墩虹。需要的時候可以重新打開。
定期對不再更新的索引做optimize (ES2.0以后更改為force merge api)憨琳。這Optimze的實質(zhì)是對segment file強制做合并诫钓,可以節(jié)省大量的segment memory。
Filter Cache
Filter cache是用來緩存使用過的filter的結(jié)果集的篙螟,需要注意的是這個緩存也是常駐heap菌湃,無法GC的。默認的10% heap size設(shè)置工作得夠好了遍略,如果實際使用中heap沒什么壓力的情況下惧所,才考慮加大這個設(shè)置。
Field Data cache
對搜索結(jié)果做排序或者聚合操作绪杏,需要將倒排索引里的數(shù)據(jù)進行解析下愈,然后進行一次倒排。在有大量排序蕾久、數(shù)據(jù)聚合的應(yīng)用場景势似,可以說field data cache是性能和穩(wěn)定性的殺手。這個過程非常耗費時間僧著,因此ES
2.0以前的版本主要依賴這個cache緩存已經(jīng)計算過的數(shù)據(jù)履因,提升性能。但是由于heap空間有限盹愚,當遇到用戶對海量數(shù)據(jù)做計算的時候搓逾,就很容易導致heap吃緊,集群頻繁GC杯拐,根本無法完成計算過程。ES2.0以后世蔗,正式默認啟用Doc Values特性(1.x需要手動更改mapping開啟)端逼,將field data在indexing time構(gòu)建在磁盤上,經(jīng)過一系列優(yōu)化污淋,可以達到比之前采用field data cache機制更好的性能顶滩。因此需要限制對field data cache的使用,最好是完全不用寸爆,可以極大釋放heap壓力礁鲁。這里需要注意的是盐欺,排序、聚合字段必須為not analyzed仅醇。設(shè)想如果有一個字段是analyzed過的冗美,排序的實際對象其實是詞典,在數(shù)據(jù)量很大情況下這種情況非常致命析二。
Bulk Queue
Bulk Queue是做什么用的粉洼?當所有的bulk thread都在忙,無法響應(yīng)新的bulk request的時候叶摄,將request在內(nèi)存里排列起來属韧,然后慢慢清掉。一般來說蛤吓,Bulk queue不會消耗很多的heap宵喂,但是見過一些用戶為了提高bulk的速度,客戶端設(shè)置了很大的并發(fā)量会傲,并且將bulk Queue設(shè)置到不可思議的大锅棕,比如好幾千。這在應(yīng)對短暫的請求爆發(fā)的時候有用唆铐,但是如果集群本身索引速度一直跟不上哲戚,設(shè)置的好幾千的queue都滿了會是什么狀況呢? 取決于一個bulk的數(shù)據(jù)量大小艾岂,乘上queue的大小顺少,heap很有可能就不夠用,內(nèi)存溢出了王浴。一般來說官方默認的thread
pool設(shè)置已經(jīng)能很好的工作了脆炎,建議不要隨意去“調(diào)優(yōu)”相關(guān)的設(shè)置,很多時候都是適得其反的效果氓辣。
Indexing Buffer
Indexing Buffer是用來緩存新數(shù)據(jù)秒裕,當其滿了或者refresh/flush interval到了,就會以segment file的形式寫入到磁盤钞啸。這個參數(shù)的默認值是10% heap size几蜻。根據(jù)經(jīng)驗,這個默認值也能夠很好的工作体斩,應(yīng)對很大的索引吞吐量梭稚。但有些用戶認為這個buffer越大吞吐量越高,因此見過有用戶將其設(shè)置為40%的絮吵。到了極端的情況弧烤,寫入速度很高的時候,40%都被占用蹬敲,導致OOM暇昂。
Cluster State Buffer
ES被設(shè)計成每個Node都可以響應(yīng)用戶的api請求莺戒,因此每個Node的內(nèi)存里都包含有一份集群狀態(tài)的拷貝。這個Cluster state包含諸如集群有多少個Node急波,多少個index从铲,每個index的mapping是什么?有少shard幔崖,每個shard的分配情況等等(ES有各類stats api獲取這類數(shù)據(jù))食店。在一個規(guī)模很大的集群,這個狀態(tài)信息可能會非常大的赏寇,耗用的內(nèi)存空間就不可忽視了吉嫩。并且在ES2.0之前的版本,state的更新是由Master Node做完以后全量散播到其他結(jié)點的嗅定。頻繁的狀態(tài)更新都有可能給heap帶來壓力自娩。在超大規(guī)模集群的情況下,可以考慮分集群并通過tribe node連接做到對用戶api的透明渠退,這樣可以保證每個集群里的state信息不會膨脹得過大忙迁。
超大搜索聚合結(jié)果集的fetch
ES是分布式搜索引擎,搜索和聚合計算除了在各個data node并行計算以外碎乃,還需要將結(jié)果返回給匯總節(jié)點進行匯總和排序后再返回姊扔。無論是搜索,還是聚合梅誓,如果返回結(jié)果的size設(shè)置過大恰梢,都會給heap造成很大的壓力,特別是數(shù)據(jù)匯聚節(jié)點梗掰。
未完待續(xù)