MySQL数据库连接超时
应用日志报错,应用反馈频繁连接超时,导致应用无法正常提供服务。
可能的问题原因如下:
- 数据库timeout参数设置不合理
- 数据库连接串设置有误
- 连接池配置不是最佳实践或者连接池满
- 网络波动
- 防火墙策略异常
- 数据库压力大导致响应缓慢
- 数据库连接达到上限
- 未知原因
处理过程:
- 检查数据库状态,排除1,6,7
数据库连接数未达到上限;数据库压力很低;timeout设置600秒(全司标准配置),error count; - 检查应用连接串,排除2
jdbc:mysql://ip:port/dbname?
useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&connectTimeout=3000&socketTimeout=10000 - 检查连接池,排除3
max,min配置合理,并且active未达到max。1分钟探测一次idle,超过5分钟的idle会话,回收连接池连接。配合MySQL error日志,未看MySQL主动断开空闲连接的相关报错。 - 检查网络。排除4,5
网络反馈网络无波动、防火墙配置正常。
经过各个专业组排查,都反馈无问题。目前分析下只有一个原因:超出认知范围内的未知原因
实践是检验真理的唯一标准!
减少影响因素,逐步缩小故障范围。
1、因应用跟数据库不同网段,通过jdbc短连接的方式在应用服务器上、以及数据库同网段服务器进行探活测试。
测试结果:数据库同网段探活无报错,应用测探活有报错。
结论:数据库无问题、连接池无问题
2、因应用是k8s部署,屏蔽k8s影响,将一台应用服务器剥离k8s集群,继续进行测试。
测试结果:应用探活无报错。
结论:网络策论、防火墙配置等无问题,可能k8s有问题(k8s为项目组私有部署,不是司内标准服务)。
3、网络抓包:在pod所在宿主机跟数据库主机之间进行抓包。
测试结果:SYN重传,第三次握手被重传了,重传的SYN没有收到服务器端的ACK确认。
结论:1、应用服务器SYN重传。2、数据库服务器端不响应重传的SYN!
测试结果导向:当k8s开启后,会向数据库重复发送tcp请求,数据库主机会屏蔽这些重复的tcp请求。
经过查资料发现:
一、服务端在什么情况下会不响应重传SYN--->当开启下面两个参数时,服务端会检查TCP连接报文的时间戳,当收到相同IP的的请求时,时间戳小于当前已经建立的TCP连接的时间戳时,会丢弃该请求。
数据库主机配置了如下参数,用户快速回收TCP连接。防止高并发下服务器端积压大量TCP连接TIME_WAIT的socket。
net.ipv4.tcp_timestamps=1 ##3.x内核默认配置,校验TCP报文的时间戳
net.ipv4.tcp_tw_recycle=1 ##开启TCP连接中TIME_WAIT socket快速回收
net.ipv4.tcp_timestamps默认开启,net.ipv4.tcp_tw_recycle默认关闭。当这两个参数都开启后,会激活TCP的如下行为:
TCP可以缓存每个主机最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。
二、客户端为什么会有重传SYN现象
客户端是k8s容器,容器内的tcp请求,会使用NAT进行转换,转换成宿主机的物理IP后,再与数据库通信。而在NAT转换时,会造成TCP请求的时间戳不是递增的。这就造成了“SYN”重传现象。
结合以上两点,可以从理论上判断出应用服务器连接超时现象的原因。
解决方案:
数据库服务器设置如下参数。
net.ipv4.tcp_timestamps=0
net.ipv4.tcp_tw_recycle=0
我们将数据库服务器的参数关闭后,应用服务器不再发生连接失败现象。