长连接服务tcp连接断连问题

1. 问题

我司最近一长连接服务(该服务是接收合作企业的车辆运行数据)频繁出现断连问题。
从监控显示,这周已经出现过三次,发生的时间点分别是:
2024-11-18 14:00
2024-11-19 14:36
2024-11-20 04:45

image.png

对方反馈,之前偶尔出现断连,代码层面出现 socket read timed out 或者 connect timed out 异常。
最近是程序跑着一段时间后就会大批量断连,代码层面出现 Connection reset by peer 异常。

2. 排查过程

日志

我方分析连接断开的日志,以11月18日为例。 大体断开的情况分为3种。
case 1:连接正常断开。只触发 netty 的 handlerRemoved 事件,表示由客户端正常关闭连接。
联系对方排查对应时间点的日志,对方表示均在发送数据后,由于同步等待响应超时,捕获 java.net.SocketTimeoutException: Read timed out异常后主动断开连接。

case 2:连接异常断开。触发了 netty 的 exceptionCaught 事件,具体异常为


image.png

根据异常栈显示,是服务端在读取数据时引发的超时。(至于为什么是 Connection timed out, 而不是 Read timed out 后续再深入探究),
对于以上两种 case, 由于是偶发,暂时归因为网络抖动。因为数据是在公网传输,加上对方服务器部在长春,我们的是在上海,对方通过测试 ping 连接地址,延时都是50ms+,所以其实网络质量不能得到很好的保证。

case 3: 连接异常断开。触发了 netty 的 exceptionCaught 事件,具体异常为


image.png

这种异常通常表示连接被对方异常关闭连接导致,结合网络拓扑以及服务端角度来看,对方指代的有两种可能:
1、远端合作企业侧(他们的程序、 网关、防火墙等)
2、我们的ELB
究竟是哪一方触发的连接重置? 我们可以通过抓包进一步分析

tcpdump 抓包

tcpdump -n -C 250M -s 0 -i eth0 -w data.pcap port 12089

wireshark分析

tcp.flags.port == 6380 过滤数据包


image.png

可以看到 在 16:12:19.180501 客户端ip 100.125.64.31 发了一个 RST 包过来,因此导致我们的程序捕获到了 Connection reset by peer异常,100.125.64.31 是 ELB 的 IP, 因为没设置透传真实客户端 IP,因此这里也无法知道是哪一端发起的 RST。

分析 TTL

TTL是IP数据包在计算机网络中可以转发的最大跳数,该值由IP数据包的发送者设置(Window默认128,Linux默认64),在IP数据包从源到目的地整个转发路径上,每经过一个路由器,路由器将TTL的值减1,然后再将IP包转发出去,如果在IP包到达目的地之前,TTL减少为0,路由器将会丢弃数据包。通过TTL机制能避免IP包在网络中的无限循环和收发,节省了网络资源。

正常的数据包TTL


image.png

RST包TTL


image.png

可以看到,正常有对方合作企业端发出的数据包,经过公网的传输后中间过了很多跳,TTL剩下39。
而RST包的TTL是61只经过3跳,那就说明数据包的发送方离服务端“很近”,因此锁定该数据包是由天翼云ELB发出的。
另外还发现一个比较重要的特征,就是所有的RST包背后的tcp连接,都没有任何其他数据的传输(我们抓包的时间周期是3分钟左右),猜测是不是触发了天翼云ELB某种机制,由此联想到空闲连接超时机制,因此上去检查了一下,发现天翼云ELB默认设置了300秒(5分钟)的空闲连接超时机制,后跟天翼云的工程师确认过,当触发超时机制后,ELB会向双方各发一个RST包中断连接。因此对方和我们的代码都会捕获到Connection reset by peer异常。

image.png

结合之前的监控来看,2024-11-18 14:14:00左右开始,传输的数据量开始往下掉

image.png

日常情况下的数据传输需要200条左右的tcp长连接,数据量骤降后,大部分连接处于空闲状态,从14:20:00左右并发连接数也发生骤降,这个时间窗口刚好也是5分钟左右,因此也就对得上了。

image.png

3. 解决措施

方案一:使用心跳协议。如果连接长时间无数据交互,定期发送心跳包
优点:能保持长连接keep alive
缺点:增加开发成本;且我们的通讯协议是依据某国标协议实现的,该国标并无通过心跳包来保活的定义;而且在流量低谷期(可能只需几条连接)还一直维持着高峰期的连接数(200条)会占用着资源

方案二:调整服务器配置中的空闲超时设置。如果服务器配置了空闲超时,确保它设置得足够高,以避免过早地断开连接。
提高超时配置仅能延缓断连的情况,且我们在使用的ELB产品最大只能设置900秒,一味地设置成900秒意义并不大。

方案三:增加重试机制。在捕获这个异常后,客户端重新发起尝试重新建立连接(现状)

最后经过讨论,我们决定保持现状即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容