Java WebSocket导致的OOM(内存溢出)问题排查

1.问题背景

线上某个工程总是会出现OOM导致系统宕机

2.排查追踪

拿到dump文件使用MAT工具分析
Overview

在dominator_tree中,AbstractProtocol类占据了绝大部分堆内存
看到AbstractProtocol类猜测可能和协议有关,HTTP、TCP、SMTP、WebSocket等
在这里插入图片描述
继续展开,可以发现WsFrameServer的类占据了大部分堆内存,定位为WebSocket协议导致的内存溢出。
再继续展开,可以发现HeapCharBuffer占据了大部分的内存。
如果项目中只有一个ws功能则就可以定义到具体业务了,如果有多个功能模块涉及ws则需要根据ws地址确认功能。
在这里插入图片描述
通过requestUri可以查看到ws地址和请求ip
在这里插入图片描述
通过上面排查是messageBufferText过大且链接过多导致的内存溢出,查看messageBufferText大小约20MB,则需要搞明白下面的问题:

  • 20MB是否是初始化大小?
  • 如果不是初始化大小,在哪里赋值/配置修改?
  • 如果是初始化大小,在哪里可以赋值/配置修改?

那就需要查看源码分析messageBufferText是怎么初始化大小的。

首先找到了WsFrameServer类,发现messageBufferText是WsFrameServer父类WsFrameBase的成员变量
图片描述
WsFrameBase类
在这里插入图片描述
查看messageBufferText初始化:
CharBuffer.allocate静态方法创建CharBuffer的对象,其中会初始化一个大小为getMaxTextMessageBufferSize的Char类型的数组。
下面主要看wsSession.getMaxTextMessageBufferSize()方法
在这里插入图片描述
wsSession.getMaxTextMessageBufferSize()可以看到获取的是maxTextMessageBufferSize的数值
在这里插入图片描述
查看maxTextMessageBufferSize赋值
有一个默认值是8K,显然与想要的20MB差距比较大,继续看哪里有赋值了
在这里插入图片描述
wsSession.setMaxTextMessageBufferSize()
在这里插入图片描述
查看setMaxTextMessageBufferSize方法的调用
在这里插入图片描述
在代码实现里增加了这个配置,由于char类型占两个字节,1010241024*2 约 20MB,所以这个就是原因
在这里插入图片描述
不过我们继续看另外一个调用PojoMessageHandlerWholeText
在这里插入图片描述
往下追踪发现默认是-1,注解OnMessage的maxMessageSize字段获取值。
在这里插入图片描述

3. 解决思路

  1. 临时解决: 现场临时增加内存分配空间
    ps:默认情况下,-Xms是物理内存的1/64,-Xmx是物理内存的1/4
  2. message初始值大小: 统计ws的maxTextMessageBufferSize大小,设置合理的数值,或考虑压缩message大小。
  3. 产品层面: 问题同步至产品,从产品层面优化。
    如:从根据可用内存对ws链接数做最大限制
  4. 服务优化:
    如:由于在项目中ws是长链接,及时释放不再使用的WebSocket链接(超时)、同一个ip和ws地址使用同一个链接
    超时功能:项目中使用nginx,可以在nginx中增加超时配置proxy_read_timeout
  5. 运维层面: 增加健康检查对于意外崩溃自动重启服务
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值