022024.02

包拯断案 | 程序连接频繁出现超时怎么破@还故障一个真相

2024.02.02


提问:作为DBA运维的你是否有过这些苦恼

1)数据库部署完成后,测试时发现程序连接频繁出现连接超时的情况?

2)每次遇到该问题,应用程序重连后基本能连上,检查数据库集群未出现异常,但严重影响测试及上线进度,不知是什么原因?



## 心中有章,遇事不慌

作为DBA的你,遇到问题无从下手,除了在问题面前徘徊,还能如何选择?如果你一次或多次遇到该问题还是无法解决,又很懊恼,该如何排忧呢?关注公众号,关注《包拯断案》专栏,让小编为你排忧解难~

## 包拯秘籍
一整套故障排错及应对策略送给你,让你像包拯一样断案如神:
#首先
遇到此类问题后 我们要做到心中有章(章程),遇事不慌。一定要冷静,仔细了解故障现象(与研发/用户仔细沟通其反馈的问题,了解故障现象、操作流程、数据库架构等信息)

#其次
我们要根据故障现象进行初步分析。心中要想:什么情况会导致程序连接频繁出现连接超时?例如:是设备状态还是配置参数的问题?

#然后
针对上述思考,我们需要逐步验证并排除,确定问题排查方向。

#接着
确定了问题方向,进行具体分析。通过现象得出部分结论,通过部分结论继续排查并论证。

#最后
针对问题有了具体分析后,再进行线下复现,最终梳理故障报告。


## 真刀实战我们能赢

说了这么多理论,想必实战更让你心动。那我们就拿一个真实案例进行分析---

2.1故障处理场景

在项目现场兢兢业业赶进度的你,正在为某个客户部署了一套安全数据库GreatDB分布式,却在应用测试阶段,发现程序连接频繁出现连接超时的情况,经过多次重连后虽然恢复了连接,却影响了测试进度,对现场情况和原因不太清楚。

2.2 故障处理

客户现场部署GreatDB分布式集群,应用需要连接集群调度节点进行读写请求。有三个调用节点均可接收应用请求,使用了客户侧提供的F5设备做负载均衡。通过F5地址连接数据库集群频繁出现连接超时退出等情况,直接连接数据库调度节点物理IP地址无法复现。

1)问题复现

• 编写脚本分别通过F5地址和每个调度节点实际地址测试登录数据库集群;

• 发现只有通过F5连接时才能复现该问题,分别登录每个调度节点都无法复现,推测问题点可能出现在F5负载转发方面。

2)F5设备状态及配置检查

• F5运维人员反馈F5状态正常,且配置和其余三个集群并无区别。结合现场情况了解到,其余三个集群通过F5地址登录均无法复现该问题。

3)系统配置检查
(由于上述两步均未发现问题,因此尝试从系统环境配置方面排查一遍)

• 首先想到了操作上有不少网络相关配置,可以先对比一下正常环境和出现问题的环境参数配置。

通过sysctl -a 将每个环境中的配置读取并写到文件中,然后使用 diff 工具比对差异。

通过对比发现,可疑参数net.ipv4.tcp_tw_recycle,连接有问题的环境该参数配置为1,查找相关资料分析该参数的影响。


4)初步定位问题

• 通过查阅资料发现 net.ipv4.tcp_tw_recycle参数在特定场景下确实会引起类似问题,因此我们先针对这个参数展开测试和验证。

• 资料显示,net.ipv4.tcp_tw_recycle参数和net.ipv4.tcp_timestamps参数配合使用。在使用NAT转发的网络环境中,由于多个设备之间不能保证时间完全同步,如果开启了net.ipv4.tcp_tw_recycle,会检查对端IP的时间戳是否递增,如果不是递增则会丢失网络包。

• 之后,登录服务器查看TCP数据情况,发现有大量的TCP SYN包被丢弃,并且数量一直在增长。


```powershell
$ netstat -s | grep -i listen
1825 times the listen queue of a socket overflowed
2751213 SYNs to LISTEN sockets dropped
```

5)修改配置,验证问题是否解决

• 在窗口时间修改net.ipv4.tcp_tw_recycle为0

• 使用脚本测试持续使用F5地址登录集群,发现该问题不再复现。


## 2.3原因分析
1.为什么会丢包?

time_wait出现在主动关闭tcp连接的一端(可能是服务端,也可能是客户端,以下简称“本端”,对应的另外一段称为“对端”),如果本端开启了tcp_tw_recycle,触发per-host PAWS机制,会检查对端IP维度的timestamps是否递增;如果不是递增,会直接丢弃包(现象例如:发送SYN包或数据包,对方没有回包,这边却一直在重试,直到多次重试都失败了,连接就会超时异常);

2.什么环境下会丢包?

一般情况下,这种超时问题只会出现在对端是NAT的环境,如F5、LVS等负载均衡方案都使用了NAT技术。在本端看来,是同一个对端NAT IP连接过来的,而对端NAT环境下的多个设备时间肯定会存在差异,因此一旦在本端开启了net.ipv4.tcp_tw_recycle=1,对端发送过来的携带timestamps的包就很难全部递增(无论是对端NAT环境下哪个设备发送的包,都会被认为是对端NAT IP的包),本端就会丢弃timestamps不递增的包,此时可能就会导致对端部分设备收不到回包,多次重传均失败,连接就会出现异常。

3.如何避免该问题导致的丢包?

大多数情况下,tcp连接上的客户端会主动发起fin关闭,则time_wait状态会出现在客户端而非服务端。这种情况下,服务端不需要考虑优化回收time_wait。但现在,大多数应用部署在服务器上,它即会作为服务端对外提供服务,也会作为客户端去请求其他服务器上接口,前者是因为作为服务端,很少出现time_wait状态;后者是因为作为客户端很容易在服务器上产生大量TCP time_wait状态。因此,我们想快速回收time_wait,主要是针对后者的情况。

此时,如果我们想解决后者time_wait过多情况,在服务器(注意是服务器,不是服务端)上开启tcp_tw_recycle快速回收端口,因为这台服务器上的应用同时又是作为服务端对外提供服务,tcp_tw_recycle触发的pre-host PAWS机制则会使客户端超时异常,因此,net.ipv4.tcp_tw_recycle=1不能轻易开启。


## 本期复盘总结


1)本次部署过程中,只关注了对数据库影响较大的系统参数,忽视了一些常规参数;

2)现场基础环境复杂多样,部署前要做好基线检查;

3)基线检查要尽可能融合到自动化工具里,实现标准化、规范化。


## 番外篇-展昭答疑解惑


1)怎么规避tcp_tw_recycle带来的问题呢?

答:首先,要明确自己的环境是否适合开启此参数,比如用到NAT 网络地址转换的场景下,尽量避免开启tcp_tw_recycle参数;
另外,Linux 从内核4.12版本开始移除了tcp_tw_recycle 参数。因此,用大于4.12内核版本的小伙伴就不用担心这个问题啦;
最后,生产环境的内核升级总是存在滞后性。因此,线上操作系统内核版本仍会存在大量4.12之前的内核版本,在环境部署时仍要稍加注意这个参数。