现象说明
研发说有一台线上服务器(此处称为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天,如下图:
如此看来应该不是这条语句影响,为了解决问题,索性把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
- 本文固定链接: http://www.jiagou.cc/983/
- 转载请注明: 摘星怪 于 架构迷 发表