某应用在压测过程中,发现OTSClient与OTS服务端之间的TCP连接有大量处于TIME_WAIT状态。
查看与OTS服务端进行交互的不同TCP连接状态的数量:
netstat -ant | grep 10.4.170.39 | awk '/^tcp/{ state[$NF]};END{for(key in state) print key,state[key]}'
图1 不同状态连接的数量
分析过程TIME_WAIT图2 TCP四次挥手
OTSClient连接处于TIME_WAIT状态,由上图可知TCP连接是由OTSClient主动关闭的,所以OTSClient为什么要频繁的关闭TCP连接?在什么情况下关闭的?
通过tcpdump抓包可以清楚OTSClient与OTS服务端通讯协议及建立连接、传输数据、断开连接的过程。
OTSClient与OTS服务端通讯协议是HTTP1.1,HTTP1.1默认开启长连接,所以代码在某个地方主动断开了连接,接下来是找到代码中什么地方主动关闭的连接。
OTSClient构造方法中用于构造与OTS服务端通讯的代码如下:
图3 构造方法
AsyncServiceClient构造方法如下:
图4 定时间隔逻辑
IdleConnectionEvictor图5 空闲连接管理
场景回顾应用中配置的socketTimeout=50ms,根据上面逻辑closePeriod=20ms,即当TCP连接空闲20ms的时候就主动关闭,主动关闭造成的现象是大量连接处于TIME_WAIT状态。
对系统的影响- 连接无法复用,每次请求OTS服务端都要新建TCP连接/关闭连接,造成客户端和服务端资源浪费
- 频繁新建/关闭连接,更容易造成响应时间的毛刺
- 大量连接处于TIME_WAIT状态,消耗系统内存、文件描述符等资源
Q:是否可以调大socketTimeout来避免TIME_WAIT的问题?
A:不合适,该应用在线上访问OTS服务端平均响应时间是5ms,如果设置的过大,当与OTS服务端交互发生超时的时候,线程需要等待更长的时间会造成整个接口超时(业务要求该查询接口响应时间在60ms以下,线上平均响应时间是30ms)。
查看了OTSClient 5.13.7的实现,与当前版本实现逻辑一致,所以更新OTSClient版本并不能解决这个问题。
图6 pom依赖
已经向阿里反馈该问题,估计阿里的改动如下:
- 将IdleConnectionEvictor定时间隔参数开放出来,让业务可以配置
- 将IdleConnectionEvictor空闲时间参数开发出来,让业务可以配置