詳解SpringCloudGateway記憶體洩漏問題
SpringCloudGateway記憶體洩漏問題
專案完善差不多,在進入壓力測試階段期間,發現了gateway有記憶體洩漏問題,問題發現的起因是,當時啟動一臺gateway,一臺對應的下游應用服務,在壓力測試期間,發現特別不穩定,併發量時高時低,而且會有施壓機卡住的現象,然後找到容器對應的宿主機,並使用container stats命令觀察記憶體,經過觀察發現,壓力測試時記憶體會暴漲,並由於超過限制最大記憶體導致容器掛掉(這裡由於用的swarm所以會自動選擇節點重啟)最終發現由於之前測試伺服器配置低,所以限制了堆大小為1g,容器cpu 1,容器記憶體限制為了1g,經過調整後將記憶體改為4g且不限制容器資源的情況下,併發穩定,單機qps也不錯,但是多次壓力測試後依然會有卡住的問題,觀察了日誌之後確定為記憶體洩漏
io.netty.util.internal.OutOfDirectMemoryError:
failed to allocate 16777216 byte(s) of direct memory
(used: 4110417927,max: 4116185088)
- LEAK: ByteBuf.release() was not called before it's garbage-collected.
發現問題之後,我進入容器內dump了記憶體快照,並下載到本機由jvisualvm分析,分析過程中並沒有發現異常情況,由於gateway底層是netty,所以懷疑是堆外記憶體出了問題,這時候我從快照中查詢bytebuff,依然很小,後來直接使用arthas去線上分析,分析發現堆記憶體正常,gc也沒有問題
最後為了快速測試出異常,我調小了堆外記憶體大小,並配合nmt調查
-XX:NativeMemoryTracking=detail -XX:MaxDirectMemorySize=100M
在線上使用pmap去檢視記憶體,發現了很多的anon,並且每次併發都會增長
轉移到本地進行測試,發現記憶體遠超出分配的堆大小,最終確定為堆外記憶體出了問題
既然是堆外記憶體出的問題,我們就只關心是否申請了buff沒有釋放,通過對程式碼的檢查發現,只有兩個地方使用到了相關的內容
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes); return serverHttpResponse.writeWith(Flux.just(buffer));
對上面的程式碼進行大量壓測後發現並無問題,記憶體沒有異常增長不回收
ServerHttpRequest httpRequest = exchange.getRequest().mutate().headers(httpHeaders -> { httpHeaders.add(GatewayConstants.LOGIN_USER_KEY,JSON.toJSONString(s)); }).build(); return chain.filter(exchange.mutate().request(httpRequest).build());
還有一處就是修改請求頭這部分程式碼,當註釋掉這部分時,記憶體穩定沒有異常增長,當放開時,3000併發幾乎增加800M記憶體,幾次就懟到了5g+,由於gateway內建了一個請求頭工廠(AddRequestHeaderGatewayFilterFactory),我去檢視對應的原始碼,是怎麼實現的
如圖,除了多瞭解析配置之外和我寫的基本也一樣,那為何會記憶體異常呢?只能去github上找找問題看看有人遇到相同的事沒。
這個老哥遇到的問題也類似,他是修改請求體的內容時出現的
這個問題我也遇到了
看起來這個問題還是挺嚴重的,最後我也反手提了一個問題
沒有啥回答,最後還是參考了一些別人的寫法最後記憶體不會飆升了,但是不知其為何,還得繼續調查
到此這篇關於詳解SpringCloudGateway記憶體洩漏問題的文章就介紹到這了,更多相關SpringCloudGateway記憶體洩漏內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!