一次netty 堆外内存泄露排查

背景

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

任何开源框架都避免不了 bug 的存在,我们在使用这个开源框架的时候,就遇到一个堆外内存泄露的 bug,鉴于对 netty 比较熟,于是接下来便想挑战一下,找出那只臭虫(bug),接下来便是现象和排查过程,想看结论的同学可以直接拉到最后总结。

正文

现象

某天早上突然收到告警,nginx 服务端大量5xx

image.png

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

image.png

某台机器在同一时间点爆发 gc,同一时间,jvm 线程阻塞

image.png

接下来,便开始漫长的 堆外内存泄露排查之旅行。

排查过程

阶段1: 怀疑是log4j2

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

接下来,查看 log4j2 的配置文件

image.png

发现打印到控制台的这个 appender 忘记注释掉了,所以我初步猜测是因为这个项目打印的日志过多,而 log4j2 打印到控制台是同步阻塞打印的,接下来,把线上所有机器的这行注释掉,以为大功告成,没想到,过不了几天,5xx告警又来敲门了,看来,这个问题没那么简单。

阶段2:可疑日志浮现

接下来,只能硬着头皮去查日志,查看故障发生点前后的日志,发现了一处可疑的地方

image.png

在极短的时间内,狂打 failed to allocate64(bytes)of direct memory(…)日志(瞬间十几个日志文件,每个日志文件几百M),日志里抛出一个 netty 自己封装的 OutOfDirectMemoryError,说白了,就是堆外内存不够用了,netty 一直在喊冤。

堆外内存泄露,我去,听到这个名词就有点沮丧,因为这个问题的排查就像 c 语言内存泄露一样难以排查,首先想到的是,在 OOM 爆发之前,查看有无异常,然后

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值