简介:TCP协议和HTTP协议中,都有keepalive机制,只是二者的含义有所不同。TCP中keepalive主要用来进行链路检测;HTTP中keepalive主要用来进行链路复用。其中http1.1版本已经默认支持keepalive,即支持持久连接。下面将详细分析TCP和HTTP中keepalive机制。
1、TCP keep alive
(1)
TCP是无感知的虚拟连接,中间断开两端不会立刻得到通知。一般在使用长连接的环境下,需要心跳保活机制可以勉强感知其存活。业务层面有心跳机制,TCP协议也提供了心跳保活机制。
长连接的环境下,一旦有热数据需要传递,若此时连接已经被中介设备断开,应用程序没有及时感知的话,那么就会导致在一个无效的数据链路层面发送业务数据,结果就是发送失败。
无论是因为客户端意外断电、死机、崩溃、重启,还是中间路由网络无故断开、NAT超时等,服务器端要做到快速感知失败,减少无效链接操作。
(2)
在一个正常的TCP连接上,当我们用无限等待的方式调用下面的recv或send的时候:
ret=recv(s);或ret=send(s);如果TCP连接被对方正常关闭,也就是说,对方是正确地调用了closesocket(s)或者shutdown(s)的话,那么上面的recv或send调用就能马上返回,并且报错。这是由于closesocket()或者shutdown()有个正常的关闭过程,会告诉对方“TCP连接已经关闭,你不需要再发送或者接受消息了”。但是,如果是网线突然被拔掉,TCP连接的任何一端的机器突然断电或重启动,那么这时候正在执行recv或send操作的一方就会因为没有任何连接中断的通知而一直等待下去,也就是会被长时间卡住。这种情形解决的办法是启动TCP编程里的keepAlive机制。
keepaliveinterval=5000; //单位为毫秒
keepalivetime=1000; //单位为毫秒
此处的keepalivetime表示的是TCP连接处于畅通时候的探测频率,一旦探测包没有返回,就以keepaliveinterval的频率发送,经过若干次的重试,如果探测包都没有返回,那么就得出结论:TCP连接已经断开,于是上面的recv或send调用也就能马上返回,不会无限制地卡住了。
(3)
keepalive三个参数:
sk->keepalive_probes:探测次数
sk->keepalive_time 探测的超时
sk->keepalive_intvl 探测间隔
对 于一个已经建立的tcp连接。如果在keepalive_time时间内双方没有任何的数据包传输,则开启keepalive功能的一端将发送 keepalive数据包,若没有收到应答,则每隔keepalive_intvl时间再发送该数据包,发送keepalive_probes次。一直没有 收到应答,则发送rst包关闭连接。若收到应答,则将计时器清零。
sk->keepalive_probes = 3;
sk->keepalive_time = 30;
sk->keepalive_intvl = 1;
意 思就是说对于tcp连接,如果一直在socket上有数据来往就不会触发keepalive,但是如果30秒一直没有数据往来,则keep alive开始工作:发送探测包,收到响应则认为网络,是好的,结束探测;如果没有响应,就每隔1秒发探测包,一共发送3次,3次后仍没有响应,则发送RST包关闭连接,也就是从网络开始到你的socket能够意识到网络异常,最多花33秒。但是如果没有设置keep alive,可能你在你的socket(阻塞性)的上面,接收: recv会一直阻塞不能返回,除非对端主动关闭连接,因为recv不知道socket断了。
我们知道TCP连接关闭时,需要连接的两端中的某一方发起关闭动作,如果某一方突然断电,另外一端是无法知道的。tcp的keep_alive就是用以检测异常的一种机制。
但是,tcp自己的keepalive有这样的一个bug:正常情况下,连接的另一端主动调用colse关闭连接,tcp会通知,我们知道了该连接已经关闭。但是如果tcp连接的另一端突然掉线,或者重启断电,这个时候我们并不知道网络已经关闭。而此时,如果有发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive,那就意味着,我们的keepalive总是不能发送出去。 而此时,我们也并不知道该连接已经出错而中断。在较长时间的重传失败之后,我们才会知道。
2、HTTP keep alive
在http早期,每个http请求都要求打开一个tcp socket连接,并且使用一次之后就断开这个tcp连接。
使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。
但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。
http keep-alive与tcp keep-alive,不是同一回事,意图不一样。http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。
3、TCP和HTTP的Keep-Alive总结:
HTTP协议的Keep-Alive意图在于连接复用,同一个连接上串行方式传递请求-响应数据。
TCP的keepalive机制意图在于保活、心跳,检测连接错误。