您好,登錄后才能下訂單哦!
這篇“Es因scroll查詢引起的gc問題怎么解決”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Es因scroll查詢引起的gc問題怎么解決”文章吧。
問題:
某日下午正開心的逛著超市,突然收到線上es機器的fgc電話告警,隨之而來的是一波es reject execution,該es機器所處集群出現流量抖動。
排查:
回到家打開監控頁面,內存占用率有明顯的上升,通常服務端不會無端的爆內存,首先排查可能性最高的:讀寫流量變化。
通過監控頁發現入口流量并沒有明顯抖動,考慮到集群中的不同索引以及不同查詢類型,總的入口流量可能會掩蓋一些問題,所以繼續查看各索引的分操作流量監控,發現索引 A 的scroll流量在故障發生時存在明顯的波動,從正常的 10qps 以內漲到最高 100qps 左右,這對于普通查詢來說并不高,看來是 scroll 查詢有些異樣。
起因1:
先說結論:scroll 查詢相對普通查詢占用的內存開銷大很多,考慮到遍歷數據的場景,安全的量是控制在 10qps 左右。
相比于普通query,scroll 查詢需要后端保留遍歷請求的上下文,具體的就是當有init scroll請求到達時,當時的 index searcher 會持有全部索引段的句柄直至scroll請求結束,如果處理不當,比如段緩存等,容易在server端占用大量內存;另外, scroll 查詢還需要在server端保存請求上下文,比如翻頁深度、scroll context等,也會占用內存資源。
在后續的測試中,客戶端單線程使用scroll查詢遍歷百萬級別的索引數據,server端的CPU占用率高達70%左右,觀察進程的CPU占用,發現大部分的CPU時間都耗在gc上,這使得server沒有足夠的CPU時間調度其他任務,導致正常的讀寫請求不能被及時響應。
# 壓測機器配置:1c2g x 10# 索引配置:5 number_of_shards x 1 number_of_replica,共計約180萬數據
起因2:
繼續排查scroll執行的查詢內容,發現的主要有兩種類型。
其一:
{ "query": {"bool":{"must":[{"terms":[11,22,…2003]}]}}, "size":200}# terms子句中包含200個id
上面的示例query省略了其他一些過濾條件,白話一下這個查詢的含義:
從索引中查詢id字段值為數組所包含的200條記錄
可以看到的幾個特征是:
沒有filter子句,terms條件在must子句
這個查詢最多返回200條記錄,一次查詢就可以得到全部數據
其二:
{ "query": {"bool":{"must":[ {"range":{"create_time":{"gt":0, "lte":604800}}}, {"term":{"shop_id":1}} ]}}, "size":200}# range條件包含的數據大約為1000條# 全索引包含的數據大約1000萬條# create_time不固定,但是區間固定在1周
這里也省略了一些其他干擾條件,只保留最重要的,白話過來的含義:
從1000萬全量索引中查詢shop_id=1并且create_time在符合條件區間內的數據,條件區間每10秒變更一次,也就是每10秒查詢一次當前時刻之前1周的新數據.
可以得出的幾個結論:
size為200,要訪問全部數據至少需要5次查詢
create_time的變更很小,類似于 (0, 603800] => (5, 604805],所以每次查詢該子條件命中的記錄數變化也都不大,都有幾百萬條
沒有filter子句
并沒有發現filter或者must_not這樣在官方文檔中明確標明的filter context條件,但是實際上的filter cache在scroll發生期間單機從 500 MB 左右逐漸升高到 6 GB(配置的filter cache最大空間),理論上說不通,直接從代碼里找答案。
跟蹤query流程,發現bool子句中不論是must還是filter,最終被rewrite之后沒有本質上的區別,判斷是否可以進入filter cache的條件是:
段內最大文檔數是否在閾值范圍內(Es的filter緩存以段為單位)
查詢出現頻次是否超過閾值
而在出現頻次這個部分,Lucene緩存策略還會有isCostly這樣的判斷,目的是盡量將高消耗的查詢盡可能早的緩存起來,提高查詢性能,符合isCostly判斷的查詢包括 terms 和 range 等查詢,只要重復出現2次即會被緩存起來,結合起來分析:
terms查詢并不需要scroll查詢,使用普通查詢就能解決需求,使用scroll查詢增加了server負載
range查詢重復次數達到了isCostly閾值,也就是說每次遍歷數據都會往filter cache中丟入幾百萬的緩存value,而且命中率極低(下次scroll查詢的range起止條件有細微的變化),加大了server的gc負擔
解決:
通過上面的分析,我們可以看到有兩個因素的影響導致了server的拒絕響應:
大量的scroll并發
不當的range請求,具體又可以拆分為:
高頻次,每10秒一次
變化快,每次查詢的起止范圍都有10秒的后延
命中數大,百萬級別的命中數
針對上面的幾點各個擊破就是我們的解決方案:
scroll請求:
糾正不當使用的terms+scroll查詢,使用普通查詢;
推薦使用search_after替換scroll請求,雖然在效率上有所降低,但是有兩個優勢:
可以重試,scroll如果重試可能會丟失部分數據
資源占用低,在相同的測試環境下,CPU占用率只有10%左右
不當的range請求:
高頻次:降低請求頻率,限制到至少1分鐘一次,當然不是根本解決方案,推薦將類似的遍歷數據請求改到db或者hbase等介質
變化快:粗暴點的解決方案是限制時間單位到小時級別,優雅點的話:
將時間條件拆分為粗粒度和細粒度的組合,粗粒度以若干小時為單位,細粒度支撐到分鐘或者秒級
細粒度條件使用script方式執行,原理是filter cache的frequency是用LinkedHashMap作為key容器的,用來累積查詢次數,而key的hash計算,普通query是根據查詢的條件和值來作為hash輸入的,而script查詢是使用當前實例的引用,這樣就能避免查詢被累積(因為每次的hashcode都不一樣)
命中數大:通過粗細粒度劃分可以降低成本
以上就是關于“Es因scroll查詢引起的gc問題怎么解決”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。