基于springboot编写了一个简单Websocket服务,主要用来接收客户端上报的各种数据。由于网络环境不稳定,经常出现websocket连接中断,客户端自动重连的现象。
某日,生产环境突然出现上百个客户端集体掉线的警报,而且是同一时间发生的,平常也就一两个掉线告警。
起初以为是网络问题,但从客户端现象看,一直时连接超时,网络可以ping通。搜索后台日志,发现大量connection reset异常,并伴有OutOfMemoryError: java heap space (先重启解决离线了问题)
想办法在本地重现:调整JVM -Xms500M -Xmx500M
一个客户端,一直发送消息,通过jconsole发现,jvm堆内存并不会一直增长,大部分数据在没有进入年老代就被回收了。
连续建立多个客户端,不中断连接,很快就出现了OOM,dump内存数据,使用jvisualvm进行简要分析:
找出最大的对象,如下:竟然全部是WsFrameServer对象,继续点击去看下对象细节
主要是两个buffer占用的大量空间!
看源码,发现端倪,每初始化一个WsFrameServer对象,jvm都要分配maxBinaryMessageBufferSize和maxTextMessageBufferSize的内存,过多的websocket连接,很快就把内存沾满了。
知道了原因,也就有应对方法。减小bufferSize,设置合理的空闲超时时间。
bufferSize设置:
@Configuration @ComponentScan @EnableAutoConfiguration public class WebSocketConfig implements ServletContextInitializer{ //配置websocket传输大小 @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.addListener(WebAppRootListener.class); servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","128000"); servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize","128000"); } }
和客户端连接建立后,配置空闲超时时间
session.setMaxIdleTimeout(10000);
再重新测试,系统的容量提高了很多(虽然无法完全避免OOM)
参考:https://www.cnblogs.com/qiantao/p/13576441.html