作者简介:大厂一线资深开发。从crud开发到资深开发,再到研究员兼技术经理。《资深开发讲技术》 从一线实战中总结有故事,有背景的案例,希望带给大家一系列技术盛宴。
欢迎大家 评论,关注,欢迎技术交流。友情提醒,往期的文章也精彩。
问题现象
项目上线后,通过正常流程, 处理存量数据。预期QPS 2K,持续时间大约1天。但是调用方的QPS开始的时候满足需求,很快过了一段时间,QPS就降下来了,而且不再升起来了。
排查过程
我负责服务器端项目,因此我们双方一起联合排查这个问题。
按照上线之前的压测结果,服务端部署4台虚机,QPS 4K是可以轻松满足的。我也挺奇怪的,登录服务器,看了下响应日志,响应速度很快。而且我的work线程,连接数开的挺足的。
我登录到调用方的系统,看了下日志,出现比较多的,下面的异常信息。
![464d70c059075ee114f922051efca404.png](https://i-blog.csdnimg.cn/blog_migrate/d8493cd76295ac96a5d690fc62f5b24b.jpeg)
cannot assign requested address executing,表示没有有效的端口也已分配了。
控制台执行,netstat -anp|grep TIME_WAIT,发现大量tcp连接处在 TIME_WAIT,大约5w多。
![8db283c543b56f1101861275171557b3.png](https://i-blog.csdnimg.cn/blog_migrate/b0d185b76868d12009079c3a93398605.jpeg)
我吓了一跳,一个系统的端口总共6w多。怎么这么多处于待关闭状态。和调用方的同学沟通后, 了解到,他们使用的是fegin客户端。我猜测是没有使用http连接池或者连接池配置的有问题。
沟通后发现,调用方使用的是默认的feign配置,并没有配置http连接池。所以需要看下源码,需要了解feign是如何处理http请求的。
![1486188ce5d0a258ca5568c7e2ac1151.png](https://i-blog.csdnimg.cn/blog_migrate/52d97214e8476c60730d8779989d0baa.jpeg)
如上面截图,feign默认的会使用java.net.HttpURLConnection 创建连接,处理完请求就关闭连接。
至此我就明白了,当调用方持续大量发起调用的时候,每次请求都会创建一个连接,然后主动销毁,但是连接关闭是需要时间的(2MSL),而处于TIME_WAIT的tcp连接是不会释放端口的。所以导致端口被大量占用,系统中的连接很多处于TIME_WAIT中
![8a258f2481bb7e9482325d08b886f08c.png](https://i-blog.csdnimg.cn/blog_migrate/f727403bb745867bcf6d86c60da62756.jpeg)
处理过程
给feign增加了一个Http连接池,重新上线后,开启存量数据处理请求,服务正常,连接状态平稳。
结论
1. TIME_WAIT状态结束之前,tcp连接会一直占用的本地端口号无法释放。高并发并且采用短连接方式,运行一段时间后,就常常会出现做为客户端的程序,无法向服务端建立新的连接的情况。此时用"netstat-anp"命令查看系统将会发现机器上存在大量处于TIME_WAIT状态的并且占用大量的本地端口号。最后该机器上的,可用本地端口号均被占完。
2. 目前很多团队在做微服务化,采用spring cloud体系。基本上都会使用feign,但是默认的配置,并不支持高负载的场景,您踩到这个坑了吗?
往期文章:
增加消费能力,导致的线上故障
一次限速,导致的线上故障
日志中的连接异常信息,你get到了吗?
听过限流熔断,但是对于超时你重视了吗?
cpu 负载过高,服务抗不住了?