Netty OOM案例
问题:最近公司某产品商用发布在即,连续性能测试1个小时左右,开始发生时延变大、应答消息丢失等问题,最后抛出OOM异常,服务端宕机。
异常日志如下:
问题分析
通过异常堆栈和HeapAnalyzer工具分析,发现是Netty的内存池直接内存溢出,由于业务的消息接收和发送ByteBuf都使用了内存池直接内存,首先排查消息接收ByteBuf,业务处理流程如下:
1、业务的解码器继承自LengthFieldBasedFrameDecoder,根据报文中的消息长度做半包解码,解码成功之后将消息投递到后端业务线程池;
2、业务没有主动释放消息接收ByteBuf, 由于Netty解码之后会主动释放ByteBuf,所以不主动释放也没问题
排查完消息接收之后,再查看消息发送。消息发送流程是对请求消息包装之后,编码转发给其它第三方模块,消息发送采用了1个独立的发送线程,在发送线程中通过Netty的NioSocketChannel直接write ByteBuf,ByteBuf在发送线程中分配,发送完成之后没有调用release方法主动释放内存。
示例代码如下:
execut.execute(new Runnable() {
@Override
public void run() {
ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer(1024 * 1024);
CodeC.endcode(sendMessage, buf);
channel.write(buf);
//后续业务逻辑处理,没有主动释放内存
}
});
在业务线程中通过内存池申请了一个直接内存,编码发送之后并没有主动释放内存,是否有问题? 我们继续看Netty的源码:
通过代码分析,我们发现当Netty的ChannelOutboundBuffer将ByteBuf发送之后,会将ByteBuf从Entry[] buffer 中删除,同时调用safeRelease方法将ByteBuf释放。即便业务代码不主动释放发送的ByteBuf,Netty也会帮助用户释放,不应该发生内存泄漏啊?!
查看业务的Netty版本,发现业务使用的是Netty 4.0.X版本,突然想到了前段时间Netty 4内存池泄漏问题:在业务线程中通过内存池申请内存,又在Netty的NIO线程中释放内存,这会导致内存泄漏。该问题是Netty 4内存池机制和线程模型优化导致的问题,原理如下:
使用Netty 4.X +版本的内存池,内存的申请和释放必须要在同一个线程中,否则会导致内存引用错乱、内存溢出等问题。
问题定位出来之后,将内存池ByteBuf申请的代码迁移到ChannelHandler的CodeC中,由Netty的NIO线程统一申请和释放。优化之后,性能测试72个小时,内存占用平稳、GC正常,问题解决。
随后进行压力测试,客户端启动N个线程,使用同一个SocketChannel对服务端进行压测,24小时之后又发生了OOM异常,分析之后仍然是内存池的直接内存泄漏,怎么回事?
通过定位发现,在压力测试模式下,消息发送速度大于消息接收处理的速度,也就是说ByteBuf的申请速度大于释放速度,这导致了内存池不断膨胀,最终内存溢出。
如何解决这个问题? 业务建议通过调大服务端work线程数的方式提升服务端并行处理性能,但实际行不通。因为对于单链路场景,1个链路只被某一个work线程处理,增加work线程是没有效果的。
既然通过增大服务端线程数无法解决问题,那有没有更好的解决办法?方法有三个:
1、放弃内存池,使用非内存池模式;
2、动态流量控制;
3、采用多链路的方式。
使用非内存池模式,内存最终被JVM回收,而不是缓存在线程中,因而只要堆内存设置合适就可以解决内存溢出问题。
动态流控方案:可以使用Netty默认提供的流量整形功能,它可以解决两个问题:
1、防止由于上下游网元性能不均衡导致下游网元被压垮,业务流程中断
2、防止由于通信模块接收消息过快,后端业务线程处理不及时导致的“撑死”问题
原理如下:
多链路方案:通过调大服务端work线程个数,提升服务端的并行处理性能,满足高峰期的浪涌冲击。
案例总结
尽管Netty使用起来比较简单,但是如何在高并发和负载情况下保证系统平稳运行,却是并非一件易事。
除了完善的性能测试、压力测试之外,对Netty底层处理机制的理解和Code Review也是必不可少的。
相关推荐
Netty OOM案例 ##### 14.1 问题描述 Netty运行过程中出现OutOfMemoryError错误。 ##### 14.2 问题分析 分析OOM错误的原因,可能涉及内存泄露、大对象分配等问题。 ##### 14.3 问题总结 总结OOM错误的解决方法...
这个“netty入门案例.zip”文件提供了一个简单的 Netty 应用示例,旨在帮助初学者快速理解并掌握 Netty 的基本概念和使用方法。下面将详细介绍这个入门案例中的关键知识点。 首先,Netty 的核心是其 ChannelHandler...
《Netty进阶之路-跟着案例学Netty》是由知名技术专家李林峰撰写的一本专为Java开发者深入理解Netty框架而准备的书籍。这本书旨在通过实例教学,帮助读者全面掌握Netty的核心特性和实战技巧,提升网络编程的能力。 ...
读书笔记:Netty实战案例
"基于Netty5.0的高级案例NettyWebsocket" 这个标题揭示了我们将会探讨一个使用Netty 5.0框架实现的WebSocket服务器的高级应用场景。Netty是一个高性能、异步事件驱动的网络应用程序框架,主要用于快速开发可维护的高...
Netty进阶之路 跟着案例学Netty 整本书无密码,Netty进阶之路 跟着案例学Netty
Netty案例集锦
netty案例,netty4.1中级拓展篇八《Netty心跳服务与断线重连》源码 https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724845&idx=1&sn=8631c590ff4876ba0b7af64df16fc54b&scene=19#wechat_redirect
netty案例,netty4.1中级拓展篇九《Netty集群部署实现跨服务端通信的落地方案》源码 ...
《Netty进阶之路:跟着案例学Netty》中的案例涵盖了Netty的启动和停止、内存、并发多线程、性能、可靠性、安全等方面,囊括了Netty绝大多数常用的功能及容易让人犯错的地方。在案例的分析过程中,还穿插讲解了Netty...
在深入探讨 Netty 的实践学习案例之前,我们先了解一下 Netty 的核心特性: 1. **异步非阻塞 I/O**:Netty 基于 Java NIO(非阻塞I/O)构建,允许它处理大量并发连接,减少了线程创建和上下文切换的开销。 2. **零...
netty案例,netty4.1中级拓展篇十三《Netty基于SSL实现信息传输过程中双向加密验证》源码 ...
netty案例,netty4.1中级拓展篇一《Netty与SpringBoot整合》源码 https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724796&idx=1&sn=ce5dc3c913d464b0e2e4e429a17bb01e&scene=19#wechat_redirect
本资料《Netty案例集锦(并发编程篇)》着重介绍了Netty在并发编程方面的应用,以下将详细阐述其中可能包含的知识点。 1. **Java NIO基础**:Netty基于Java NIO(非阻塞I/O)构建,NIO允许程序选择非阻塞方式读写数据...
(Netty案例大全)Netty 4.x 用户指南Demo 《Netty 4.x 用户指南》/《Netty原理解析与开发实战》,文中用到的示例源码。版本涉及的相关技术及版本如下。Netty 4.1.52.Final杰克逊 2.10.1JUnit 5.5.2示例包含示例...
netty案例,netty4.1基础入门篇十一《netty udp通信方式案例Demo》源码 https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724927&idx=1&sn=a16bc8e98d6a27816da0896adcc83778&scene=19#wechat_redirect
这个"netty案例.zip"压缩包提供了一个简单的Netty入门示例,帮助初学者理解如何使用Netty进行网络编程。下面将详细解释这个案例中的核心知识点。 1. **Netty基础架构**: Netty采用了Reactor模式,它是一种处理...
Java进阶技术-netty进阶之路
netty案例,netty4.1基础入门篇六《NettyServer群发消息》源码 https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724778&idx=1&sn=72e4b1ea5323475b16e99c6720c7069d&scene=19#wechat_redirect
netty案例,netty4.1基础入门篇十二《简单实现一个Netty的Http服务》源码 https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724932&idx=1&sn=eb1631ddbd0e7a0dcb3a655374631f48&scene=19#wechat_redirect