You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

工作原理

当一个 TCP 连接建立之后,启用 TCP Keepalive 的一端便会启动一个计时器,当这个计时器数值到达 0 之后(也就是经过tcp_keep-alive_time时间后,这个参数之后会讲到),一个 TCP 探测包便会被发出。这个 TCP 探测包是一个纯 ACK 包(RFC1122#TCP Keep-Alives规范建议:不应该包含任何数据,但也可以包含1个无意义的字节,比如0x0),其 Seq号 与上一个包是重复的,所以其实探测保活报文不在窗口控制范围内。

如果一个给定的连接在两小时内(默认时长)没有任何的动作,则服务器就向客户发一个探测报文段,客户主机必须处于下表中的4个状态之一。

详细解释一下就是:

1)客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常的,服务器在两小时后将保活定时器复位。

2)客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务端将不能收到对探测的响应,并在75秒后超时。服务器总共发送10个这样的探测 ,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。

3)客户主机崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。

4)客户机正常运行,但是服务器不可达,这种情况与2类似,TCP能发现的就是没有收到探测的响应。

直观来说,TCP KeepAlive的交互过程大致如下图所示:

具体使用举例

以linux内核为例,应用程序若想使用TCP Keepalive,需要设置SO_KEEPALIVE套接字选项才能生效。

对应的,有三个重要的参数:

  1. tcp_keepalive_time,在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2h)

  2. tcp_keepalive_probestcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包次数,默认值为9(次)
  3. tcp_keepalive_intvl,在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包的发送频率,默认值为75s

可能导致的问题

Keepalive 技术只是TCP协议中的一个可选项。因为不当的配置可能会引起一些问题,所以默认是关闭的

具体来说,可能导致下列问题:

  1. 在短暂的故障期间,Keepalive设置不合理时可能会因为短暂的网络波动而断开健康的TCP连接;
  2. 需要消耗额外的宽带和流量(对于现在这个时代来说,这貌似已经不是问题了);
  3. 在以流量计费的互联网环境中增加了费用开销。

在移动网络时代的局限性

不可否认,TCP协议作为TCP/IP协议族中最重要部分,对互联的发展确实功不可没。但如今移动网络时代,无线通信越来越普及,作为上个世纪中期发明的TCP协议来说,客观的讲,在某些场景下确实有先天不足。那么,既然TCP协议本身有KeepAlive,为什么还要自已在应用层实现网络保活/心跳机制?

以移动端IM应用为例:

  1. 一方面,运营商ISP的网络资源更为稀缺,TCP协议默认2小时的KeepAlive基本不可能实现IM长连接“保活”(为了提升无线网络资源的利用率,运营商长则几分钟,短则数十秒就有可能回收空闲的网络连接)。
  2. 另一面,无线网络本身存在弱网问题,即使TCP连接是“好的”,但实际上处于“假死”状态,也无法起到长连接该有的作用。


所以说,IM应用层自已做网络保活(心跳机制)是不可避免的。

参考资料


Content Menu

  • No labels