基於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