- Gateway2.0基本介紹
- 使用reactor-netty作爲網絡模型。
- 全程爲reactor 編程方式。
- 問題報錯信息
- 問題現象
- 服務上線不久隔斷時間就會無法訪問,假死。
- 初期解決方案:定時重啓服務。
- 原因:業務需求壓力過大,無精力深入排查該問題。且問題發生不嚴重。
- 內存快照
- 問題復現
- 拿到代碼,構建一個docker鏡像,部署測試。
- 設置 JVM最大內存爲 256M
- Jmeter 壓測
- 復現結果
- 壓測1.5個小時後,開始報錯。 報錯內容於 線上運行時異常一致。
- 問題分析
- 內存快照分析
- 明明已經使用到內存溢出了,但是內存快照才33M大小。
- 出現最多的爲循環嵌套對象finalizer。
- 參考:
- 網絡資料排查過程中,可以通過內存快照對象直接定位到哪裏使用的這個對象,直接定位到問題點。
- 實際情況:
- 無限循環嵌套。無法定位到到底是哪裏使用的這個對象。
- 代碼檢查
- 發現的問題
- 使用了rides
- 在網關中提供了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 只做網關自己的事情!