MySQL Server端为什么有大量的TCP TIME_WAIT?

最近客户的一台MySQL Server告警处于TCP TIME_WAIT状态的连接过多,通过查看相关监控发现TCP Connections中处于TIME_WAIT状态的连接一直在3000~4000,如图:

在OS上查看TCP处于TIME_WAIT状态的连接:

(其中161服务器是本地的MySQL Server,4125是数据库端口,234是远程应用服务器)

可以看到所有处于TIME_WAIT状态的TCP连接都是应用服务器234到本地161的数据库连接,此时心中有一个疑问:只有主动关闭TCP连接的一端才会存在TIME_WAIT状态,主观的想法就是大量的TIME_WAIT应该位于应用服务器一端,哪为何MySQL Server这一端有这么多处于TIME_WAIT状态的TCP连接?难道是有大量由于wait_timeout超时的连接,所以MySQL Server这一端主动关闭了连接,还是由于网络异常或客户端异常关闭,导致MySQL Server一端主动关闭了连接,但是通过观察MySQL Connections相关监控发现连接数量一直都是比较少的:

所以就不是由于大量的连接因为wait_timeout超时而造成的MySQL Server一端主动关闭了连接。

通过查看mysqld error log里面也没有太多关于“Aborted connection”或“Got an error reading communication packets”,所以也不是由于网络异常或客户端异常关闭导致的MySQL Server一端主动关闭了连接。
此时就想从系统角度入手看能不能进行相关调整,之后将net.ipv4.tcp_tw_recycle系统参数从0调整为了1,然后观察TCP Connections相关监控发现效果非常明显,TIME_WAIT状态的TCP连接瞬间就降下去了:

但是查询相关资料发现tcp_tw_recycle这个参数是有坑的:

所以虽然效果很明显,但是为了稳妥起见,还是将net.ipv4.tcp_tw_recycle参数改回了0。

这时就只能换一个思路:通过抓包看看数据库服务器和应用服务器到底是如何通信的,由于没有权限登录应用服务器,就只能在161数据库服务器上通过tcpdump单向抓包并使用Wireshark工具进行分析。
通过分析发现在抓取的68000多个包中存在大量的FIN包和SYN包,由此说明应用服务器存在大量的短连接,一直在连接数据库,短时间的查询之后又断开连接,并不断反复:

但是这依旧不能解释为什么MySQL Server一端存在大量处于TIME_WAIT状态的TCP连接。

继续分析网络包之后发现当Client请求退出之后,Client和Server之间的TCP连接有两种断开方式:
第一种:
234应用服务器发出退出请求,161数据库服务器回复“ACK”包,然后由234应用服务器主动断开连接。

第二种:

234应用服务器发出退出请求,161数据库服务器主动断开与234应用服务器的连接。

此时我们就可以得出结论:在MySQL退出会话时,Client与MySQL Server之间,TCP连接的断开有可能是由Client发起的,也有可能是由Server发起的,而并不是我们主观认为的都是由Client发起的,所以当Client与MySQL Server之间存在大量的短连接时,MySQL Server的OS上就可能会存在大量处于TIME_WAIT状态的TCP连接,而解决方法就是由应用侧将大量的短连接由少量的长连接代替。

在MySQL Internals Manual上也有相关Client退出会话时MySQL Server的动作说明:

这也刚好印证了通过抓包看到的现象。

posted @ 2023-03-27 21:36  吃饭端住碗  阅读(68)  评论(0编辑  收藏  举报