首页 > 首页 > 数据库 > 关系型数据库 > Mysql > 【原创】MySQL远程长连接很短时间就超时夯(hang)住
2024
09-06

【原创】MySQL远程长连接很短时间就超时夯(hang)住

现象说明

研发说有一台线上服务器(此处称为A服务器)需要远程连接数据库服务器,A服务器上配置了连接池,需要每小时跑一次任务,连接池设置的超时时间是1小时,但是发现如果没有数据传输,不到半小时数据库上的连接就消失了,而A服务器上面的已建立的连接却夯住不动了,无法继续执行sql命令,需要运维查看下什么原因

问题排查

根据研发描述的状况,如果应用的连接池设置时间没有问题,就需要考虑的是数据库的超时设置,于是登录数据库服务器,进行如下操作:

mysql> show global variables like 'wait_timeout';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| wait_timeout  | 28800 |

+---------------+-------+

1 row in set (0.00 sec)

有上面可以看出,数据库的连接超时时间是8小时,所以也不存在数据库主动断开连接的问题,于是用如下命令查看观察所有连接状态:

# mysql -uroot -p -e "show processlist"

发现所有处于sleep状态的连接不到半个小时就消失了,这个现象的原因是什么?

后来研发发来一篇文章:https://segmentfault.com/a/1190000002790395说他们的报错跟这篇文章的一样,现象也一样。

仔细阅读后发现确实跟公司得状况一样,尤其是文章最后的解决办法说是因为服务器之间有硬件防火墙,防火墙上面配置的TCP长连接的超时时间过短造成的。而恰巧我们公司A服务器和数据库之间也有硬件防火墙。

但是后来仔细一想,发现我们的问题应该不是这个,因为这两个网段之间还有很多别的数据库服务器,有很多长链接都没有问题,如果是防火墙问题,那么这种想象就不应该只是这一台DB。

但是这篇文章给了我启发,我尝试查看A服务器和数据库服务器上的系统参数和防火墙,果真问题出在这两个上面。

解决问题

A服务器上的防火墙被同事给启动了,默认这个网段的防火墙都是关闭的,查看A服务器上的防火墙设置,发现并没有放行数据库服务器所在网段,但是有一条如下的语句:

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

上面策略的大概意思是和A服务器成功建立的连接,以及这个ESTABLISHED连接再产生一个主连接之外的连接都放行。这也符合可以从A服务器正常连接数据库服务器,但是为什么不到半个小时就断开连接了呢?然道是上面命令有一个超时时间?

继续翻文档查看ESTABLISHED,RELATED这个两个参数的超时时间,直接说结果吧,发现这个ESTABLISHED的超时时间是5天,如下图:

【原创】MySQL远程长连接很短时间就超时夯(hang)住 - 第1张  | 架构迷

如此看来应该不是这条语句影响,为了解决问题,索性把A服务器上的防火墙关闭查看,发现问题依旧。

到这开始考虑有没有可能是数据库服务器的参数问题呢?查看参数ESTABLISHED,也是5天,没有问题,到这又陷入迷糊了,但是转念一想,linux系统参数中还有一项是keepalive_time时间,赶紧查看一下数据库服务器,果然问题出现在这,如下:

#  sysctl -a| grep keepalive

net.ipv4.tcp_keepalive_intvl = 20

net.ipv4.tcp_keepalive_probes = 9

net.ipv4.tcp_keepalive_time = 1200

三个参数的含义如下:

tcp_keepalive_time            #两个TCP连接之间的最大空闲时间,默认值为7200秒(2小时)

tcp_keepalive_probes          #发几个ack包不回复才当对方死了

tcp_keepalive_intvl            # 两个ack包之间间隔多长

问题结论

所以可以计算出断开连接的时间是1380秒,经过验证也正好是这个时间以后会断开。所以问题找到了。

由于从A服务器发送的连接长时间没有数据传输,数据库服务器经过1380秒探测认为连接不活动了,即不存活了,所以主动断开了连接,导致A服务器上的数据库连接被夯住了,无法继续操作。

解决办法

在数据库服务器上执行如下命令,改成两个小时以后探测

临时:

# echo 7200 > /proc/sys/net/ipv4/tcp_keepalive_time

永久:

# vim /etc/sysctl.conf

net.ipv4.tcp_keepalive_time = 7200

# syctl -p

最后编辑:
作者:摘星怪
这个作者貌似有点懒,什么都没有留下。

留下一个回复

你的email不会被公开。