故障描述:
某天對(duì)Es做多次查詢(xún)請(qǐng)求,發(fā)現(xiàn)Es集群經(jīng)常掛掉衰粹,無(wú)法響應(yīng)锣光。
定位問(wèn)題:
我們的Es在之前較長(zhǎng)時(shí)間內(nèi)未出現(xiàn)故障,所以可認(rèn)為時(shí)近期內(nèi)的變更導(dǎo)致的铝耻。最近我們新運(yùn)行了一個(gè)bulk index程序生產(chǎn)Es數(shù)據(jù)誊爹。
1.index方面:首先我們懷疑可能是這個(gè)bulk index程序可能觸發(fā)Es某些問(wèn)題。但是關(guān)閉該程序并重啟Es集群,該故障仍然會(huì)發(fā)生频丘。
2.search方面:故障是發(fā)生在Es數(shù)據(jù)快速增長(zhǎng)之后箍铭,那么有很大的可能是數(shù)據(jù)量增長(zhǎng)之后,某個(gè)search請(qǐng)求觸發(fā)es問(wèn)題椎镣。因?yàn)槲覀兊南到y(tǒng)構(gòu)建于Es之上诈火,且較為復(fù)雜,無(wú)法很快的定位是哪次請(qǐng)求導(dǎo)致Es故障状答。很難從這里下手定位問(wèn)題冷守。但是query/filter,aggs幾類(lèi)請(qǐng)求中惊科,最可能的是不合理aggs請(qǐng)求導(dǎo)致的拍摇。
確認(rèn)問(wèn)題:
查看日志,在當(dāng)天的日志中馆截,發(fā)現(xiàn)出現(xiàn)故障時(shí)Es在頻繁的Full GC
甚至可能會(huì)OOM
Es本質(zhì)上是一個(gè)java程序充活,在進(jìn)行GC時(shí)整個(gè)程序無(wú)法響應(yīng)。長(zhǎng)時(shí)間GC時(shí)蜡娶,集群其它節(jié)點(diǎn)在無(wú)法獲得某個(gè)節(jié)點(diǎn)的心跳響應(yīng)時(shí)混卵,集群會(huì)認(rèn)為這個(gè)這個(gè)節(jié)點(diǎn)退出了集群〗颜牛可是從其它節(jié)點(diǎn)日志發(fā)現(xiàn)這一點(diǎn):
丟失整個(gè)節(jié)點(diǎn)的分片數(shù)據(jù)后幕随,由于Es高可用自平衡機(jī)制,集群開(kāi)始平衡分片等任務(wù)宿接。集群長(zhǎng)時(shí)間處于不健康狀態(tài)赘淮。
現(xiàn)在可以確定是某次查詢(xún)請(qǐng)求導(dǎo)致節(jié)點(diǎn)內(nèi)存被大量使用,觸發(fā)Full GC(Es默認(rèn)會(huì)在內(nèi)存使用75%時(shí)發(fā)生FullGc -XX:CMSInitiatingOccupancyFraction=75)睦霎,而該內(nèi)存又不能被GC回收掉梢卸,接著頻繁GC。甚至可能直接OOM副女。結(jié)果該節(jié)點(diǎn)長(zhǎng)時(shí)間無(wú)法響應(yīng)外部請(qǐng)求蛤高。
問(wèn)題請(qǐng)求:
經(jīng)過(guò)不斷排查,發(fā)現(xiàn)可疑請(qǐng)求search dsl為:
該聚合請(qǐng)求將數(shù)據(jù)按分鐘分桶肮塞,每個(gè)桶計(jì)算top 1的文檔襟齿,當(dāng)時(shí)間范圍橫跨較大時(shí),會(huì)相當(dāng)吃?xún)?nèi)存枕赵。 該請(qǐng)求橫跨一天的數(shù)據(jù)猜欺,數(shù)據(jù)量為0.75M,并且同時(shí)并發(fā)7次類(lèi)似請(qǐng)求拷窜,數(shù)據(jù)內(nèi)容不一致(_msearch)开皿。經(jīng)測(cè)試如果請(qǐng)求一個(gè)月數(shù)據(jù)必然復(fù)現(xiàn)故障問(wèn)題涧黄。
問(wèn)題原因:
ElasticSearch在收集文檔用于返回時(shí)非常的耗內(nèi)存,所以才有from+size<=10000的默認(rèn)設(shè)定赋荆。但是在bucket agg的子agg使用top_hits agg時(shí)笋妥,可以突破這個(gè)限制(ElasticSearch沒(méi)有這個(gè)限制)。所以當(dāng)bucket數(shù)量非常大時(shí)窄潭,非常容易導(dǎo)致OOM春宣。假設(shè)請(qǐng)求10天的數(shù)據(jù),每秒分桶嫉你,每個(gè)桶內(nèi)取top 10月帝,那么這個(gè)數(shù)量級(jí)為10*24*60*60*10=8640000,即你可以取到864萬(wàn)條數(shù)據(jù)幽污,再大的內(nèi)存也無(wú)法完成這個(gè)計(jì)算嚷辅。而且這只是一個(gè)分片shard的數(shù)據(jù),而協(xié)調(diào)節(jié)點(diǎn)(請(qǐng)求的那個(gè)節(jié)點(diǎn))需要將所有分片節(jié)點(diǎn)的數(shù)據(jù)集合到一起再做reduce距误,內(nèi)存使用是其它節(jié)點(diǎn)的倍數(shù)簸搞,更加容易OOM。我們這次故障就是發(fā)生在協(xié)調(diào)節(jié)點(diǎn)reduce數(shù)據(jù)時(shí)准潭。
解決問(wèn)題:
對(duì)于上面的請(qǐng)求趁俊,業(yè)務(wù)上實(shí)際沒(méi)有必要每個(gè)桶都取top1,所以完全可以將top1提升為父聚合的兄弟來(lái)避免這個(gè)問(wèn)題惋鹅。而對(duì)于無(wú)法改進(jìn)的dsl则酝,則應(yīng)該將所有數(shù)據(jù)切片,比如按時(shí)間分片闰集,多次請(qǐng)求來(lái)避免這個(gè)問(wèn)題。
思考:
1.對(duì)于分桶數(shù)量太大的聚合請(qǐng)求般卑,應(yīng)該將所有數(shù)據(jù)切片武鲁,比如按時(shí)間分片,多次請(qǐng)求來(lái)避免內(nèi)存OOM蝠检。
2.集群中應(yīng)該有獨(dú)立的協(xié)調(diào)節(jié)點(diǎn)沐鼠,專(zhuān)門(mén)用于數(shù)據(jù)請(qǐng)求(node.master=false node.data=false),并給它們?cè)O(shè)置足夠的內(nèi)存叹谁。通過(guò)數(shù)據(jù)節(jié)點(diǎn)與協(xié)調(diào)節(jié)點(diǎn)分離饲梭,可以避免節(jié)點(diǎn)掛掉之后,導(dǎo)致整個(gè)集群不可用焰檩,或者長(zhǎng)時(shí)間響應(yīng)遲鈍憔涉。
3.在探究Es的故障時(shí),能實(shí)時(shí)看Es各項(xiàng)指標(biāo)非常有用析苫。比如兜叨,對(duì)于本文中的這種故障穿扳,能看到j(luò)vm的內(nèi)存使用是非常有幫助的。所以最好能有一個(gè)對(duì)Es的專(zhuān)門(mén)的監(jiān)控系統(tǒng)国旷。如何監(jiān)控Elasticsearch?
4.使用docvalue是解決該類(lèi)問(wèn)題的王道矛物。es2.x版本,使用string類(lèi)型保存字符串跪但,string類(lèi)型默認(rèn)分詞analyzed履羞。分詞的string是無(wú)法利用docvalue的。那么問(wèn)題來(lái)了屡久,怎么即想分詞吧雹,又想利用docvalue呢:
PS:有人可能會(huì)說(shuō)CMS垃圾回收在大內(nèi)存情況下表現(xiàn)不如G1,但是Elasticsearch官方文檔不建議使用官方文檔