一、背景
1:系统通过MQ接受数据,经过业务处理,调用第三方SDK api
2:系统上线后,线程数达到15K(1w5个线程)
3:报错:java.lang.OutOfMemoryError: unable to create new native thread,内存溢出
二、排查
1:查看tcp状态
1.1:established状态有4k,在系统高峰并发下,这么多建立连接可以理解为正常
1.2:close_wait达到了13k, 说明是服务端(推送sdk服务端)主动断开连接,(为什么是服务端主动断开,正常是client断开连接)
2:通过jstack查看jvm线程堆栈状态统计数
2.1:目前正在wait的线程达到8k
2.2:打印具体详细线程栈
2.3:基本可以确定占用线程数高就是okhttp
三、思考
1:服务端主动断开连接,说明是连接达到了服务端的超时时间,不然不会主动断开 -->
2:使用了okhttp,为什么就会有那么多线程数 -->
3:查看源码,okhttp每次创建socket,默认keepalive(HTTP 2)是5分钟,所以可以理解为5分钟的长连接
4:每一次new一个okHttpClient,会有一个http连接的线程池(为了复用),同时又有一个线程通过死循环回收线程池过期的http连接
5:业务代码每来一次请求,就new一个okHttpClient,在并发高的情况下和默认5分钟的http生命周期,可以导致上面说的大量被动断开连接的状态close_wait(5分钟达到了服务器的timeout时间)
6:new一个okHttpClient,同时会有一个守护线程在死循环回收http连接,可以导致上面说的为什么线程数15k
四、解决
1:使用单例okhttpclient, okhttpclient本身就提供http(socket)请求连接池,目标就是复用连接,避免tcp三次握手和挥手带来的效率问题。
线程数恢复正常
无、总结
1:监控一定要全
2:基础网络知识要会
3:使用jvm排查工具
4:熟悉框架的源码