TCP存活检测的背景

由于 TCP 位于传输层,两端的连接为逻辑信道(由五元组控制)而非物理连接,所以当两端处于连接状态但未发送数据时,理论上即使中间的路由器崩溃重启、或者中间的网络线路拔掉在插上等等,只要客户端和服务器端的主机没有发生异常,这个TCP连接仍然是处于连接状态的。这会引发以下问题:

  1. 服务器资源被持续占用(需要保存连接的状态信息)
  2. 防火墙和NAT设备可能会保存一个连接超时的定时器,如果这个 TCP 连接长时间没有数据传输,定时器超时后,服务器端和客户端实际上已经不能在进行通信。

为了解决上面的两个问题,TCP连接需要一个存活检测机制,定时检测当前的 TCP 连接是否可用,以刷新防火墙和 NAT 信息,或者当检测到连接失败的时候释放相关资源。TCP 存活检测机制主要为 长连接 服务。

存活检测实现方式

  1. 应用层心跳机制
  2. TCP保活机制

相比传输层的存活检测,应用层的检测更灵活且不依赖传输层的协议,但需要应用自定义心跳消息头。心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉对方自己还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

应用层心跳机制

应用层的心跳包其实就是一个预先规定好格式的数据包,在程序中启动一个定时器,定时发送即可,这是最简单的实现思路。通常,当双端正常通信时,各端接收到数据包本身也能说明连接是“有心跳的”,故此时无需心跳包。所以,对于用于保活的心跳包,我们仅在没有数据来往达到一定时间间隔时才发送一次心跳包。一般是客户端主动给服务器端发送心跳包,服务器端做心跳检测决定是否断开连接。

TCP保活机制

在TCP存活检测中有一个 存活定时器 ,当 TCP 连接的任何一个方向有业务数据传输时,就会把这个存活定时器重置为 keepalive time ,当固定时间内没有数据传输导致本端这个定时器超时的时候,TCP就会发送一个探测包(keepalive probe ),若对端接收到这个探测包后响应一个 ACK,本端接收到这个 ACK 时就会重置这个存活定时器为 keepalive time 。如果本端没有收到这个 ACK 响应,会以 keepalive interval 为间隔时间重复发送探测包,如果一直发送了keepalive probes 次都没有收到 ACK 响应,则认为这个连接已经失活。如果中间的某次收到 ACK 响应则会重置存活定时器为 keepalive time ,并且停止 keepalive interval 为间隔的探测包重复发送。

keepalive time 一般为 7200 ms,即两个小时(时间太长,没有实际意义);keepalive interval 一般为 75 ms;keepalive probs 一般为 9 次。所以如果连接一直未响应,最晚两个小时十多分钟就会自动断开连接。keepalive功能必须默认关闭

为什么有了TCP保活机制,还需要应用层心跳检测?

因为 TCP 的保活机制并不能准确体现应用层的可用性。应用层心跳除了说明进程还活着,更重要的是说明进程还能正常工作。一旦客户端发生死锁, 其心跳机制也会锁住,这样服务端就能感知到不正常,从而及时断开连接。而 TCP 的保活机制依然正常,所以无法向外界反馈正确信息。

文章参考:TCP37知乎

文章作者: 极简
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 后端技术分享
网络理论
喜欢就支持一下吧