Netty堆外内存泄露排查与总结

本文详细记录了使用Netty时遇到的堆外内存泄露问题的排查和解决过程。从最初怀疑log4j2,到发现Netty自身的内存统计,再到通过反射监控堆外内存,最终定位到编码过程中导致的NPE错误,修复了Bug。通过这个案例,总结了排查内存泄露问题的方法和经验。
摘要由CSDN通过智能技术生成

导读

Netty 是一个异步事件驱动的网络通信层框架,用于快速开发高可用高性能的服务端网络框架与客户端程序,它极大地简化了 TCP 和 UDP 套接字服务器等网络编程。

Netty 底层基于 JDK 的 NIO,我们为什么不直接基于 JDK 的 NIO 或者其他NIO框架:

使用 JDK 自带的 NIO 需要了解太多的概念,编程复杂。

Netty 底层 IO 模型随意切换,而这一切只需要做微小的改动。

Netty自带的拆包解包,异常检测等机制让我们从 NIO 的繁重细节中脱离出来,只需关心业务逻辑即可。

Netty解决了JDK 的很多包括空轮询在内的 Bug。

Netty底层对线程,Selector 做了很多细小的优化,精心设计的 Reactor 线程做到非常高效的并发处理。

自带各种协议栈,让我们处理任何一种通用协议都几乎不用亲自动手。

Netty社区活跃,遇到问题随时邮件列表或者 issue。

Netty已经历各大RPC框架(Dubbo),消息中间件(RocketMQ),大数据通信(Hadoop)框架的广泛的线上验证,健壮性无比强大。

背景

在做一个基于 WebSocket 的长连中间件,服务端使用实现了 Socket.IO 协议(基于WebSocket协议,提供长轮询降级能力) 的 netty-socketio 框架,该框架为 Netty 实现,鉴于本人对 Netty 比较熟,并且对比同样实现了 Socket.IO 协议的其他框架,Netty 的口碑都要更好一些,因此选择这个框架作为底层核心。

诚然,任何开源框架都避免不了 Bug 的存在,我们在使用这个开源框架时,就遇到一个堆外内存泄露的 Bug。美团的价值观一直都是“追求卓越”,所以我们就想挑战一下,找到那只臭虫(Bug),而本文就是遇到的问题以及排查的过程。当然,想看结论的同学可以直接跳到最后,阅读总结即可。

问题

某天早上,我们突然收到告警,Nginx 服务端出现大量5xx。

我们使用 Nginx 作为服务端 WebSocket 的七层负载,5xx的爆发通常表明服务端不可用。由于目前 Nginx 告警没有细分具体哪台机器不可用,接下来,我们就到 CAT(美团点评统一监控平台,目前已经开源)去检查一下整个集群的各项指标,就发现如下两个异常:

某台机器在同一时间点爆发 GC(垃圾回收),而且在同一时间,JVM 线程阻塞。

接下来,我们就开始了漫长的堆外内存泄露“排查之旅”。

排查过程

阶段1:怀疑是log4j2

因为线程被大量阻塞,我们首先想到的是定位哪些线程被阻塞,最后查出来是 log4j2 狂打日志导致 Netty 的 NIO 线程阻塞(由于没有及时保留现场,所以截图缺失)。NIO 线程阻塞之后,因我们的服务器无法处理客户端的请求,所以对Nginx来说就是5xx。

接下来,我们查看了 log4j2 的配置文件。

我们发现打印到控制台的这个 Appender 忘记注释掉了,所以初步猜测:因为这个项目打印的日志过多,而 log4j2 打印到控制台是同步阻塞打印的,所以就导致了这个问题。那么接下来,我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值