-
Gateway2.0基本介紹
- 使用reactor-netty作為網絡模型。
- 全程為reactor 編程方式。
-
問題報錯信息
-
問題現象
-
服務上線不久隔斷時間就會無法訪問,假死。
-
初期解決方案:定時重啟服務。
- 原因:業務需求壓力過大,無精力深入排查該問題。且問題發生不嚴重。
-
-
-
內存快照
-
問題復現
-
拿到代碼,構建一個docker鏡像,部署測試。
- 設置 JVM最大內存為 256M
- Jmeter 壓測
-
-
復現結果
- 壓測1.5個小時后,開始報錯。 報錯內容於 線上運行時異常一致。
問題分析
-
內存快照分析
- 明明已經使用到內存溢出了,但是內存快照才33M大小。
- 出現最多的為循環嵌套對象finalizer。
-
參考:
- 網絡資料排查過程中,可以通過內存快照對象直接定位到哪里使用的這個對象,直接定位到問題點。
-
實際情況:
- 無限循環嵌套。無法定位到到底是哪里使用的這個對象。
-
代碼檢查
-
發現的問題
- 使用了redis
- 在網關中提供了API接口
- 在引入gateway的同時還引入了zuul
- 同時還引入了 spring-boot-starter-web
-
深入排查
- 在壓測中第一個報錯的信息為
-
問題分析
- ResourceLeakDetector 為 netty 內存泄漏檢測機制 ,默認為1%的抽樣檢查。
- 可以得到信息,netty 發送了內存泄露。
- 但是,這只能說明是內存泄露了,但是定位不到泄露點。
- 問題開始變為定位泄露點。
-
繼續壓測后得到線上錯誤日志
- [網關異常處理]請求路徑:/stars/cust/api/communicate/queryRecordByItemCode,異常信息:io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 16777216 byte(s) of direct
- memory (used: 1895825415, max: 1908932608)
- 當前日志同樣定位不到泄露點
-
代碼位置
- 把堆棧信息吃掉了!吃掉了!
-
信息分析
-
得到已知信息
- 確認為netty 內存泄露照成的服務不可用
- netty 使用的內存為 堆外內存(直接內存)
-
-
繼續調整壓測
- 修改 jvm 啟動參數 -XX:MaxDirectMemorySize=50M 縮減固定堆外內存大小
-
新的問題出現
- 加入堆棧異常輸入后 日志報錯為 netty rides 內存溢出!
- 並未保留日志與截圖,就不提供了。
-
新問題排查
- 百度得到的信息是 spring-boot-starter-data-redis 組件使用了netty為通訊模塊,排查掉netty后 ,使用jedis,不在報錯。
-
繼續壓測
- 問題並未解決,還是netty內存溢出。
-
逐行百度相關信息
- 網絡上有報相同錯誤的,但是都說Netty 特定版本有問題,我們使用相關依賴並非該版本
-
繼續壓測
-
調整內容
- 只壓測 getaway本身,將相關依賴全部去掉,排查是否 為getaway本身問題。
-
壓測結果
- Getaway 本身無問題,不報錯。
-
-
信息分析
- 既然getaway 本身沒有問題,必然是相關依賴出現了問題。照成了 響應結果沒釋放引起的內存溢出。
-
繼續排查
-
發現矛盾點
- 在內存快照中, netty 與 tomcat相關對象都有被創建。
- 初步還以為引入的 spring-boot-starter-web 的tomcat 照成的問題。
-
-
繼續壓測
-
調整內容
- 排除 spring-boot-starter-web 的 tomcat 相關依賴引用
-
-
結果
- 不在報錯!!!!
-
排查結果
- getaway 2.0 使用的是 netty 做為容器, 在引入 spring-boot-starter-web 組件的時候會引入 tomcat 容器。
- tomcat 內對象也被創建了,在響應的時候,照成了netty 與 tomcat 類相關使用的問題。
-
從內存快照中其實也可以看到的,當時並未特別注意。
-
解決方案
-
排除 spring-boot-starter-web 的 tomcat 相關依賴引用
-
-
問題延時
- 打異常的時候,能打堆棧信息,就一定要打出來!要不真的不好排除定位問題!
- 在不是特別了解的情況下,那就勁量做到模塊單一原則。讓getaway 只做網關自己的事情!