女人荫蒂被添全过程13种图片,亚洲+欧美+在线,欧洲精品无码一区二区三区 ,在厨房拨开内裤进入毛片

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一步步解決長連接Netty服務內存泄漏

OSC開源社區 ? 來源:OSCHINA 社區 ? 2023-04-27 14:06 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

線上應用長連接 Netty 服務出現內存泄漏了!

應用介紹

說起支付業務的長連接服務,真是說來話長,我們這就長話短說: 隨著業務及系統架構的復雜化,一些場景,用戶操作無法同步得到結果。一般采用的短連接輪訓的策略,客戶端需要不停的發起請求,時效性較差還浪費服務器資源。 短輪訓痛點:

時效性差

耗費服務器性能

建立、關閉鏈接頻繁

相比于短連接輪訓策略,長連接服務可做到實時推送數據,并且在一個鏈接保持期間可進行多次數據推送。服務應用常見場景:PC 端掃碼支付,用戶打開掃碼支付頁面,手機掃碼完成支付,頁面實時展示支付成功信息,提供良好的用戶體驗。 長連服務優勢:

時效性高提升用戶體驗

減少鏈接建立次數

一次鏈接多次推送數據

提高系統吞吐量

dab1abd8-e4c0-11ed-ab56-dac502259ad0.png 這個長連接服務使用?Netty?框架,Netty?的高性能為這個應用帶來了無上的榮光,承接了眾多長連接使用場景的業務:

PC 收銀臺微信支付

聲波紅包

POS 線下掃碼支付

問題現象

回到線上問題,出現內存泄漏的是長連接前置服務,觀察線上服務,這個應用的內存泄漏的現象總伴隨著內存的增長,這個增長真是非常的緩慢,緩慢,緩慢,2、3 個月內從 30% 慢慢增長到 70%,極難發現:

dac11424-e4c0-11ed-ab56-dac502259ad0.png

每次發生內存泄漏,內存快耗盡時,總得重啟下,雖說重啟是最快解決的方法,但是程序員是天生懶惰的,要數著日子來重啟,那絕對不是一個優秀程序員的行為!問題必須徹底解決!

問題排查與復現

排查

遇到問題,毫無頭緒,首先還是需要去案發第一現場,排查 “死者 (應用實例)” 死亡現場,通過在發生 FullGC 的時間點,通過 Digger 查詢ERROR日志,沒想到還真找到破案的第一線索:

dac7f78a-e4c0-11ed-ab56-dac502259ad0.png

io.netty.util.ResourceLeakDetector [176] - LEAK: ByteBuf.release() was not called before it's garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option '-Dio.netty.leakDetection.level=advanced' or call ResourceLeakDetector.setLevel() See http://netty.io/wiki/reference-counted-objects.html for more information.

線上日志竟然有一個明顯的"LEAK"泄漏字樣,作為技術人的敏銳的技術嗅覺,和找 Bug 的直覺,可以確認,這就是事故案發第一現場。 我們憑借下大學四六級英文水平的,繼續翻譯下線索,原來是這吶!

ByteBuf.release() 在垃圾回收之前沒有被調用。啟用高級泄漏報告以找出泄漏發生的位置。要啟用高級泄漏報告,請指定 JVM 選項 “-Dio.netty.leakDetectionLevel=advanced” 或調用 ResourceLeakDetector.setLevel()

啊哈!這信息不就是說了嘛!ByteBuf.release()在垃圾回收前沒有調用,有ByteBuf對象沒有被釋放,ByteBuf可是分配在直接內存的,沒有被釋放,那就意味著堆外內存泄漏,所以內存一直是非常緩慢的增長,GC 都不能夠進行釋放。

提供了這個線索,那到底是我們應用中哪段代碼出現了ByteBuf對象的內存泄漏呢?
項目這么大,Netty 通信處理那么多,怎么找呢?自己從中搜索,那肯定是不靠譜,找到了又怎么釋放呢?

復現

面對這一連三問?別著急,Netty 的日志提示還是非常完善:啟用高級泄漏報告找出泄漏發生位置嘛,生產上不可能啟用,并且生產發生時間極長,時間上來不及,而且未經驗證,不能直接生產發布,那就本地代碼復現一下!找到具體代碼位置。

為了本地復現Netty泄漏,定位詳細的內存泄漏代碼,我們需要做這幾步:

1、配置足夠小的本地 JVM 內存,以便快速模擬堆外內存泄漏。

如圖,我們設置設置 PermSize=30M, MaxPermSize=43M

dad006aa-e4c0-11ed-ab56-dac502259ad0.png

2、模擬足夠多的長連接請求,我們使用 Postman 定時批量發請求,以達到服務的堆外內存泄漏。

啟動項目,通過JProfilerJVM 監控工具,我們觀察到內存緩慢的增長,最終觸發了本地Netty的堆外內存泄漏,本地復現成功:

dadcaae0-e4c0-11ed-ab56-dac502259ad0.jpg

dae86272-e4c0-11ed-ab56-dac502259ad0.png

_那問題具體出現在代碼中哪塊呢?_我們最重要的是定位具體代碼,在開啟了Netty的高級內存泄漏級別為高級,來定位下:

3、開啟Netty的高級內存泄漏檢測級別,JVM 參數如下:

-Dio.netty.leakDetectionLevel=advanced

daf2393c-e4c0-11ed-ab56-dac502259ad0.png

再啟動項目,模擬請求,達到本地應用 JVM 內存泄漏,Netty 輸出如下具體日志信息,可以看到,具體的日志信息比之前的信息更加完善:

2020-09-24 2059.078 [nioEventLoopGroup-3-1] INFO  io.netty.handler.logging.LoggingHandler [101] - [id: 0x2a5e5026, L:/00008883] READ: [id: 0x926e140c, L:/127.0.0.1:8883 - R:/127.0.0.1:58920]
2020-09-24 2059.078 [nioEventLoopGroup-3-1] INFO  io.netty.handler.logging.LoggingHandler [101] - [id: 0x2a5e5026, L:/00008883] READ COMPLETE
2020-09-24 2059.079 [nioEventLoopGroup-2-8] ERROR io.netty.util.ResourceLeakDetector [171] - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
WARNING: 1 leak records were discarded because the leak record count is limited to 4. Use system property io.netty.leakDetection.maxRecords to increase the limit.
Recent access records: 5
#5:
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.readBytes(AdvancedLeakAwareCompositeByteBuf.java:476)
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.readBytes(AdvancedLeakAwareCompositeByteBuf.java:36)
com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.getClientMassageInfo(LongRotationServerHandler.java:169)
com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.handleHttpFrame(LongRotationServerHandler.java:121)
com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.channelRead(LongRotationServerHandler.java:80)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
......
#4:
Hint: 'LongRotationServerHandler#0' will handle the message from this point.
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
......
#3:
Hint: 'HttpServerExpectContinueHandler#0' will handle the message from this point.
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
#2:
Hint: 'HttpHeartbeatHandler#0' will handle the message from this point.
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
#1:
Hint: 'IdleStateHandler#0' will handle the message from this point.
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
Created at:
io.netty.util.ResourceLeakDetector.track(ResourceLeakDetector.java:237)
io.netty.buffer.AbstractByteBufAllocator.compositeDirectBuffer(AbstractByteBufAllocator.java:217)
io.netty.buffer.AbstractByteBufAllocator.compositeBuffer(AbstractByteBufAllocator.java:195)
io.netty.handler.codec.MessageAggregator.decode(MessageAggregator.java:255)
  ......

開啟高級的泄漏檢測級別后,通過上面異常日志,我們可以看到內存泄漏的具體地方:com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.getClientMassageInfo(LongRotationServerHandler.java:169)

dafa8b00-e4c0-11ed-ab56-dac502259ad0.jpg

不得不說Netty內存泄漏排查這點是真香!真香好評!

問題解決

找到問題了,那我么就需要解決,如何釋放ByteBuf內存呢?

如何回收泄漏的 ByteBuf

其實Netty官方也針對這個問題做了專門的討論,一般的經驗法則是,最后訪問引用計數對象的一方負責銷毀該引用計數對象,具體來說:

如果一個 [發送] 組件將一個引用計數的對象傳遞給另一個 [接收] 組件,則發送組件通常不需要銷毀它,而是由接收組件進行銷毀。

如果一個組件使用了一個引用計數的對象,并且知道沒有其他對象將再訪問它(即,不會將引用傳遞給另一個組件),則該組件應該銷毀它。

總結起來主要三個方式:

方式一:手動釋放,哪里使用了,使用完就手動釋放。

方式二:升級ChannelHandler為SimpleChannelHandler, 在SimpleChannelHandler中,Netty對收到的所有消息都調用了ReferenceCountUtil.release(msg)。

方式三:如果處理過程中不確定ByteBuf是否應該被釋放,那交給 Netty 的ReferenceCountUtil.release(msg)來釋放,這個方法會判斷上下文是否可以釋放。 考慮到長連接前置應用使用的是ChannelHandler,如果升級SimpleChannelHandler對現有 API 接口變動比較大,同時如果手動釋放,不確定是否應該釋放風險也大,因此使用方式三,如下:

db039efc-e4c0-11ed-ab56-dac502259ad0.jpg

線上實例內存正常

問題修復后,線上服務正常,內存使用率也沒有再出現因泄漏而增長,從線上我們增加的日志中看出,FullHttpRequest中ByteBuf內存釋放成功。從此長連接前置內存泄漏的問題徹底解決。

db0d8390-e4c0-11ed-ab56-dac502259ad0.png

總結

一、Netty 的內存泄漏排查其實并不難,Netty 提供了比較完整的排查內存泄漏工具 JVM 選項-Dio.netty.leakDetection.level 目前有 4 個泄漏檢測級別的:

DISABLED - 完全禁用泄漏檢測。不推薦。

SIMPLE - 抽樣 1% 的緩沖區是否有泄漏。默認。

ADVANCED - 抽樣 1% 的緩沖區是否泄漏,以及能定位到緩沖區泄漏的代碼位置。

PARANOID - 與 ADVANCED 相同,只是它適用于每個緩沖區,適用于自動化測試階段。如果生成輸出包含 “LEAK:”,則可能會使生成失敗。

本次內存泄漏問題,我們通過本地設置泄漏檢測級別為高級,即:-Dio.netty.leakDetectionLevel=advanced定位到了具體內存泄漏的代碼。 同時 Netty 也給出了避免泄漏的最佳實踐:

在 PARANOID 泄漏檢測級別以及 SIMPLE 級別運行單元測試和集成測試。

在 SIMPLE 級別向整個集群推出應用程序之前,請先在相當長的時間內查看是否存在泄漏。

如果有泄漏,灰度發布中使用 ADVANCED 級別,以獲得有關泄漏來源的一些提示。

不要將泄漏的應用程序部署到整個群集。

二、解決 Netty 內存泄漏,Netty 也提供了指導方案,主要有三種方式 方式一:手動釋放,哪里使用了,使用完就手動釋放,這個對使用方要求比較高了。

方式二:如果處理過程中不確定ByteBuf是否應該被釋放,那交給Netty的ReferenceCountUtil.release(msg)來釋放,這個方法會判斷上下文中是否可以釋放,簡單方便。

方式三:升級ChannelHandler為SimpleChannelHandler, 在 SimpleChannelHandler 中,Netty 對收到的所有消息都調用了ReferenceCountUtil.release(msg),升級接口,可能對現有 API 改動會比較大。





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JVM
    JVM
    +關注

    關注

    0

    文章

    160

    瀏覽量

    12553
  • 內存泄漏
    +關注

    關注

    0

    文章

    40

    瀏覽量

    9370

原文標題:一步步解決長連接 Netty 服務內存泄漏

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    虛擬現實正一步步向我們走來

    顯然,虛擬現實大發展的春天正在到來,虛擬現實正一步步走向消費者。那么,虛擬現實究竟涉及哪些重點技術領域?又將對整個產業帶來怎樣的影響?未來的“抓手”又有哪些?
    發表于 10-26 16:38 ?966次閱讀

    【迅為電子】一步步教你完成iTOP-RK3568 EDP屏幕適配

    【迅為電子】一步步教你完成iTOP-RK3568 EDP屏幕適配
    的頭像 發表于 04-23 15:08 ?901次閱讀
    【迅為電子】<b class='flag-5'>一步步</b>教你完成iTOP-RK3568 EDP屏幕適配

    外國牛人教你一步步快速打造首臺機器人(超詳細)

    外國牛人教你一步步快速打造首臺機器人(超詳細)
    發表于 08-15 19:30

    一步步寫嵌入式操作系統—ARM編程的方法與實踐ch02

    一步步寫嵌入式操作系統—ARM編程的方法與實踐ch02
    發表于 08-20 20:54

    CC2530一步步演示程序燒寫

    CC2530一步步演示程序燒寫第一步——先安裝IAR開發環境第二歩——安裝CC2530燒寫工具第三歩——CC2530串口配置軟件使用具體完整步驟看下面文檔
    發表于 03-03 14:33

    一步步建立_STM32_UCOS_模板

    一步步建立_STM32_UCOS_模板
    發表于 09-29 11:46

    菜鳥一步步入門SAM4S-XPLAINED--IAR開發環境

    菜鳥一步步入門SAM4S-XPLAINED--IAR開發環境
    發表于 01-25 10:55

    一步步進行調試GPRS模塊

    背景:在不知道硬件是否正確情況下,一步步進行調試,最終完成調試。以下是自己調試步驟。1、從gprs模塊TX ,RX 單獨焊接兩個線出來,通過上位機發送AT指令,是否能正常工作。
    發表于 01-25 07:33

    stm32是如何一步步實現設置地址匹配接收喚醒中斷功能的

    為什么要設置地址匹配接收喚醒中斷呢?stm32是如何一步步實現設置地址匹配接收喚醒中斷功能的?
    發表于 02-28 08:07

    手把手教內存條超頻 一步步爬上DDR600

    手把手教內存條超頻 一步步爬上DDR600  隨著電腦配件的價格逐漸走低,很多玩家開始不僅為了省錢而攢機,而越來越趨向于國外
    發表于 01-12 09:35 ?3799次閱讀

    一步步寫嵌入式操作系統

    一步步寫嵌入式操作系統_ARM編程的方法與實踐
    發表于 07-14 11:32 ?0次下載

    看電工技術是如何一步步淪為勤雜工的

    相信很多的電工老師傅也都聽說過這種話,那電工究竟是不是勤雜工?電工技術工種是如何一步步的淪為勤雜工的,我們今天就重點來看看。
    的頭像 發表于 02-18 15:47 ?4377次閱讀

    ROM與RAM 單片機上電后如何一步步執行?資料下載

    電子發燒友網為你提供ROM與RAM 單片機上電后如何一步步執行?資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發表于 04-21 08:53 ?12次下載
    ROM與RAM 單片機上電后如何<b class='flag-5'>一步步</b>執行?資料下載

    一步步重新演繹汽車駕駛體驗

    一步步重新演繹汽車駕駛體驗
    發表于 11-04 09:52 ?0次下載
    <b class='flag-5'>一步步</b>重新演繹汽車駕駛體驗

    基于一步步蒸餾(Distilling step-by-step)機制

    為優化LLM為“小模型/少數據/好效果”,提供了種新思路:”一步步蒸餾”(Distilling step-by-step)
    的頭像 發表于 05-16 10:24 ?1642次閱讀
    基于<b class='flag-5'>一步步</b>蒸餾(Distilling step-by-step)機制
    主站蜘蛛池模板: 项城市| 涞水县| 三台县| 从化市| 文成县| 绥德县| 绥芬河市| 恩施市| 本溪市| 上思县| 乌恰县| 永泰县| 新昌县| 东台市| 阿鲁科尔沁旗| 黄浦区| 武强县| 孟村| 吐鲁番市| 五家渠市| 乐至县| 饶平县| 通许县| 遂宁市| 湖口县| 克东县| 柳林县| 彭阳县| 蓬溪县| 宿迁市| 沧州市| 汉阴县| 额敏县| 玛纳斯县| 米脂县| 安阳县| 华池县| 大冶市| 景谷| 广丰县| 米易县|