一、背景

1:系统通过MQ接受数据,经过业务处理,调用第三方推送SDK api

2:系统上线后(使用腾讯skd),线程数达到15K(1w5个线程)

生产环境内存溢出(OOM)排查

3:报错:java.lang.OutOfMemoryError: unable to create new native thread,内存溢出

生产环境内存溢出(OOM)排查

 

二、排查

1:查看tcp状态

生产环境内存溢出(OOM)排查

1.1:establish状态有4k,在系统高峰并发下,这么多建立连接可以理解为正常

1.2:close_wait达到了13k, 说明是服务端(推送sdk服务端)主动断开连接,(为什么是服务端主动断开,正常是client断开连接)

 

2:通过jstack查看jvm线程堆栈状态统计数

生产环境内存溢出(OOM)排查

2.1:目前正在wait的线程达到8k

2.2:打印具体详细线程栈

生产环境内存溢出(OOM)排查

2.3:基本可以确定占用线程数高就是okhttp

 

三、思考

1:服务端主动断开连接,说明是连接达到了服务端的超时时间,不然不会主动断开 -->

2:使用了okhttp,为什么就会有那么多线程数 -->

3:查看源码,okhttp每次创建socket,默认keepalive(HTTP 2)是5分钟,所以可以理解为5分钟的长连接

4:每一次new一个okHttpClient,会有一个http连接的线程池(为了复用),同时又有一个线程通过死循环回收线程池过期的http连接

生产环境内存溢出(OOM)排查

 

5:业务代码每来一次请求,就new一个okHttpClient,在并发高的情况下和默认5分钟的http生命周期,可以导致上面说的大量被动断开连接的状态close_wait(5分钟达到了服务器的timeout时间)

生产环境内存溢出(OOM)排查

 

6:new一个okHttpClient,同时会有一个守护线程在死循环回收http连接,可以导致上面说的为什么线程数15k

 

四、解决

1:使用单例okhttpclient, okhttpclient本身就提供http(socket)请求连接池,目标就是复用连接,避免tcp三次握手和挥手带来的效率问题。

 

线程数恢复正常

生产环境内存溢出(OOM)排查

无、总结

1:监控一定要全

2:基础网络知识要会

3:使用jvm排查工具

4:熟悉框架的源码

相关文章: