查看: 1523|回复: 0

从科来抓包看TCP保活:神秘的7200秒倒计时

[复制链接]
发表于 2025-5-15 17:09:02 | 显示全部楼层 |阅读模式

今天我们来聊聊连接TCP Keepalive机制(后文统称“保活机制”)机制与Timeout机制(后文统称“超时机制”)的原理、在时序图中的表现形式,以及如何通过流量分析精准识别与应对这些问题,助力读者在实际的IT运维工作中更好地保障网络传输的高效与可靠。

本期互动问题,欢迎大家评论区一起聊聊:

TCP保活机制和HTTP长连接如何区分?

  什么是TCP保活机制?

TCP保活机制是一种用于检测空闲连接是否仍然有效的功能。当一条TCP连接在一定时间内没有数据传输时,保活机制会发送探测包以确认对方是否仍然在线。如果对方响应,则连接被认为有效;若对方无响应,经过多次尝试后,系统将认为连接已失效并主动关闭该连接。保活机制的主要目的是防止连接因网络故障或对方主机异常而处于无效状态,同时释放系统资源。


保活定时器如何工作?


  • 启动保活定时器:当TCP连接建立后,系统会启动保活定时器。定时器的默认值通常由操作系统配置,例如在Linux系统中,tcp_keepalive_time参数表示连接空闲多久后开始发送保活探测包,默认值通常为7200秒(2小时)。


  • 交互保活探测包:如果在保活定时器到期时,连接上没有数据交互,系统会发送一个保活探测包。该探测包是一个带有ACK标志的空数据包,其目的只是确认连接是否仍然有效。如果对方仍然存活,会回复一个ACK确认包;如果对方没有响应,系统会认为连接可能已经失效。


  • 重试机制:如果未收到响应,系统会间隔一定时间(通常为75秒)再次发送保活探测包,直到达到最大重试次数(默认为9次)。如果所有探测包都未收到响应,系统会认为连接已经失效,并主动关闭该连接。保活时间间隔通过Linux系统中的tcp_keepalive_intvl参数控制,默认值通常为75秒。保活重试次数通过Linux系统中的tcp_keepalive_probes参数控制,默认值通常为9次。

需要注意的是,如果TCP连接在空闲7200秒后才启动保活探测,7200秒的时间在实际业务场景中有些过长。因此,某些应用程序或防火墙、负载均衡设备可能会有自己的TCP keepalive的默认参数。例如Nginxkeepalive_timeout参数和PostgreSQLtcp_keepalives相关参数。


  如何通过时序图分析TCP保活流量?


以下是一个在CSNAS系统的时序图功能中观察到的典型TCP保活场景:


  • 观察图1中,序号4为客户端发送的HTTP Request包,序号5为针对序号4数据包的TCP ACK


  • 服务器久久未能进行HTTP响应,会话空闲45秒后,客户端启动保活机制,开始发送序号5TCP保活探测数据包,该包序列号为序号4数据包的Next Seq字段数值-1,载荷长度为1CSNAS系统标记此数据包为“TCP Keepalive”包


  • 随后,服务器针对此保活探测包进行响应,响应包为图中数据包序号为7的数据包。CSNAS系统标记此数据包为“TCP Keepalive ACK”包


  • 0.85秒后,服务器进行了HTTP响应。保活机制很好的完成了“你还在不在?”的探测询问任务。


1 TCP保活


通过这段描述,读者应该已经可以理解TCP保活机制的基本工作原理及分析方法。


  保活失败后,多久断开连接?


1展示了保活机制的基本工作原理以及数据包现象,那么当保活数据包未得到ACK确认时,TCP该如何处理?这里涉及到两个问题:


  • 保活失败后,重新尝试保活的次数为?


  • 保活失败次数超限,断开连接的时间为?

由于linux系统默认的keepalive参数为7200秒开始保活、75秒重试、9次保活失败断开,不便于实验。笔者准备了一台Linux服务器,并设置相关参数为20秒开始保活、3秒重试、3次保活失败断开,如下表所示:


图2 不同情况对比

在如上表所示的参数中,笔者调整了Linux系统默认的keepalive相关参数,对数值进行了缩减,加快keepalive检测时间。同时,笔者模拟了keepalive ACK数据包丢失的情况,经过CSNA抓包分析,结果如下图所示:


图3 TCP保活失败


1. 序号3738的数据包,这是一次正常交互成功的keepalive包。通过时间差可知,37号数据包与上一数据包的时间差为10秒,正好是一个tcp_keepalive_time的时间。此时为会话第16秒,笔者设置了服务器流量过滤,导致TCP连接此时已发生了实际中断


2. 38号数据包交互完成后,再次间隔一个10秒,服务器继续发送39keepalive包,此时为会话第26秒,由于过滤原因,服务器无法再收到来自客户端的keepalive ACK


3. 服务器发现39keepalive包未得到回应后,间隔一个2秒的tcp_keepalive_intvl时间,再次发送了40keepalive包,此时为会话第28秒。


4. 服务器发现3940keepalive包均未得到回应,认为连接已经发生实际中断。于会话第30秒是发送RST包中断失效连接。


从会话开始出现中断,即会话第16秒,经过第26秒的一次keepalive和第28秒的第二次keepalive,服务器检测到连接已失效,通过RST断开了连接。因此,再回到本小节开头的两个问题:


  • 保活失败后,重新尝试保活的次数为2次,即tcp_keepalive_intvl次。


  • 保活失败次数超限,断开连接的时间为10+2*2秒,即tcp_keepalive_time+(tcp_keepalive_intvl* tcp_keepalive_probes)秒。

  保活的实际业务分析场景  


由于Linux系统默认的tcp_keepalive_time7200秒,这对于业务系统检测失效来说,未免太迟,因此TCP原生保活机制出现较少,在流量分析过程较难有分析的机会。


另一方面,也由于TCP保活时效性太低,因此一般的应用程序、负载设备、防火墙也自带类似的“定期超时”机制,会话在一段时间无数据包交互,就超时断开连接。这样的机制无需额外的keepalive包,keepalive包的功能由任一普通TCP包替代。在这样的机制下,只要TCP会话有数据包交互,就认为会话存活,一段时间没有交互后,即认为会话超时,断开连接。


基于应用或设备的保活机制工作如下图所示:


图4 基于其它机制的“会话保活超时”


观察图3中,序号45的数据包,这是一次正常的TCP交互,数据包5交互结束后的75秒内,双方无数据包交互,服务器即认为客户端已经保活超时,于是发送FIN包断开连接。

  相关的实际故障分析  


接下来观察一个经典的保活超时相关案例,这次的案例是一个扫码枪设备在闲置一段时间后,无法进行二次扫码的故障。科来工程师在分析过程中,经过测试发现了服务器的保活超时时间为120秒,读者可以尝试分析导致故障的原因:


图5 TCP快速重传


  结语  

本文介绍了TCP Keepalive保活机制与超时机制,深入探讨了保活与会话超时机制的流量现象,以及在CSNAS时序图中对于此类问题的分析方法,通过深入理解和掌握此类分析技巧,能够提升流量分析工程师在工作中快速分析解决此类故障的能力。

还记得开篇的互动问题吗?
TCP保活机制和HTTP长连接如何区分?
看了这篇文章,你有什么新的想法?欢迎在评论区留言和我们交流~
免费易用的流量分析工具下载
扫码关注公众号
更多网络分析技术、技巧、干货分享


- End -

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?CSNA会员注册

×
回复

使用道具 举报

您需要登录后才可以回帖 登录 | CSNA会员注册

本版积分规则

快速回复 返回顶部 返回列表