spring boot netty socket服务端_记录一次netty堆外内存溢出问题

导读

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

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

  1. 使用 JDK 自带的 NIO 需要了解太多的概念,编程复杂。
  2. Netty 底层 IO 模型随意切换,而这一切只需要做微小的改动。
  3. Netty自带的拆包解包,异常检测等机制让我们从 NIO 的繁重细节中脱离出来,只需关心业务逻辑即可。
  4. Netty解决了JDK 的很多包括空轮训在内的 Bug。
  5. Netty底层对线程,Selector 做了很多细小的优化,精心设计的 Reactor 线程做到非常高效的并发处理。
  6. 自带各种协议栈,让我们处理任何一种通用协议都几乎不用亲自动手。
  7. Netty社区活跃,遇到问题随时邮件列表或者 issue。
  8. Netty已经历各大RPC框架(Dubbo),消息中间件(RocketMQ),大数据通信(Hadoop)框架的广泛的线上验证,健壮性无比强大。(以上优点摘自美团技术博客)

背景

最近在做一个基于异步事件驱动的基础框架,服务端使用实现 Vert.x框架,该框架底层网络通信基于 Netty 实现。基于对反应式编程的兴趣与研究,打算把Spring WebFlux与Vert.x结合在一起使用。

理想目标是创建一个纯异步的、反应式编程框架。

在完成初步目标(完成了Spring WebFlux与Vert.x整合使用)之后,进行初步的demo测试。在这个时候一切都没有问题,都按照理想中的步骤运行。基于对底层框架的负责以及展示区别于传统编程性能的提升。于是决定用Jmeter对这个demo进行压力测试。在压测一段时间后出现了netty堆外内存溢出的问题。此篇用来记录遇到问题以及排查解决问题的过程。为以后遇到这个问题的同学做下记录,避免此坑。

问题

整合Spring WebFlux与Vert.x后,底层网络通信使用netty,压测一段时间后,出现netty堆外内存溢出,如下图:

662e8878d174f93390f2329270bdd880.png

意思就是告诉我们netty去申请堆外内存的时候,出现了内存不足的情况。

排查过程

看到错误这种日志的时候,习惯性往最下面翻查,是reactor工作线程抛出的,除此之外没有任何有用信息。按照平时的排查思路,再去看dump文件,也没有发现任何异常(此处排除略)。

阶段一:

这个时候发现不能按照平时排查策略来解决问题,重新分析日志,这里有这么一段:

5a8c70932b69fe026dfeff872f2910ca.png

io.netty.util.internal.PlatformDependent.incrementMemoryCounter(...)是用来统计分配netty堆外内存的,其中有个字段用来保存已分配内存private static final AtomicLong DIRECT_MEMORY_COUNTER;于是决定把DIRECT_MEMORY_COUNTER这个字段值打印出来,用PlatformDependent.usedDirectMemory();可以直接获取,如下图:

e6cdbd7a94c41b934bcc6da457833799.png

阶段二:

定位堆外内存增长速度,压测了几分钟后:

6a335cee819faa3132d242b8a7bb9da2.png

b1b87fb7fafff6f4c4961c54900c4b73.png

发现是在不断的缓慢增长。

阶段三:

IDE中断点排查。

断点决定打在处理请求、返回的处理器上,如下图:

e45da2c518dc9014f3b50766c3f8b8af.png

当断点进入这里的时候,一路F7进入调用方法中,并不断的观察控制台,堆外内存的大小变化。

跟踪到如下图的位置,执行过这个断点的时候就会出现堆外内存使用统计变化:

911d61f1c2dfade5e554e41bda081667.png
申请堆外内存的地方

7daeaf90d8e31fad168861af0aaf0e74.png
堆外内存统计出现变化图

到这里基础就找到堆外内存溢出问题的原因了,再来就是如何解决问题。

阶段四:

解决问题。

因在org.springframework.http.codec.json.AbstractJackson2Encoder.encode(...)方法中申请了堆外内存分配,只需要在接口调用完毕的时候,手动释放此内存即可。

620a3155ed4c945fa1347746061d775e.png

阶段五:

线上验证。

1 测试服务器上,启动程序,启动参数如下:

f52d90a1b0038058e28bfd98ae4360fa.png

2 使用jmeter对用户分页接口进行压测(数据库:mysql),启动500个线程,压测10分钟,结果如下:

945b2b53e00e4a131ee54e1d510aa3fa.png

3 发现堆外内存使用变化:

93113c792afc03a1076e49ba2644b494.png

4 Arthas Dashboard监控:

1e996415857a196e3b80f12f5e6b5b9d.png

到此问题解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值