一、为什么要引入keep_alive
HTTP是一个请求+响应模式的典型范例,即客户端向服务器发送一个请求信息,服务器来响应这个信息。在老版本的HTTP中,每个请求都将被创建一个新的客户端到服务器的连接,在这个连接上发送请求,然后接收请求。
优点:简单,容易理解和编程实现;
缺点:效率很低。
因此,Keep-Alive被提出用来解决效率低的问题。
二、HTTP中使用keep_alive的好处
HTTP是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive也没能改变这个结果。Keep-Alive也不能保证客户端和服务器之间的连接一定是活跃的。唯一能保证的就是当连接被关闭时,能得到一个通知,所以不应该让程序依赖于Keep-Alive的保持连接特性,否则会有意想不到的后果。
在HTTP/1.0版本中,并没有官方的标准来规定Keep-Alive如何工作,实际上它是被附加到HTTP/1.0协议上,如果客户端浏览器支持Keep-Alive,那么就在HTTP请求头中添加一个字段Connection: Keep-Alive,当服务器收到附带有Connection: Keep-Alive的请求时,它也会在响应头中添加一个同样的字段来使用Keep-Alive。这样,客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接。
使用keep-alive可以改善TIME_WAIT这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。
但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。
三、keepalvie timeout时间设置
Httpd守护进程,一般都提供了keep-alive timeout时间设置参数。如nginx的keepalive_timeout,和Apache的keep_alive_timeout。这个keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住keepalive_timeout秒后,才开始关闭这个连接。
当httpd守护进程发送完一个响应后,理应马上主动关闭相应的tcp连接,设置 keepalive_timeout后,httpd守护进程会想说:”再等等吧,看看浏览器还有没有请求过来”,这便是keepalive_timeout时间。如果守护进程在这个等待的时间里,一直没有收到浏览发过来http请求,则关闭这个http连接。
1. 当keepalive_timeout=0时(不启用Keep-Alive)
在没有设置 keepalive_timeout 情况下,一个socket资源从建立到真正释放需要经过的时间是:建立tcp连接 + 传送http请求 +数据传输 + 传送http响应 + 关闭tcp连接 + 2MSL。
2. 当keepalive_timeout>0时(启用Keep-Alive)
服务端httpd守护进程发完响应后,没有立即主动关闭tcp连接。keepalive_timeout时间后,服务端主动关闭这个tcp连接。这个时间,是我们设置的keepalive_timeout的时间。
所以,设置了keepalive_timout时间情况下,一个socket建立到释放的时间多了keepalive_timeout时间。
3. 当keepalive_timeout>0,且在同一个tcp连接发送多个http响应
当设定了keepalive_timeout,一个socket由建立到释放,需要时间是:tcp建立 + (最后一个响应时间 – 第一个请求时间) + tcp关闭 + 2MSL。
注意:正在关闭或者TIME_WAIT状态的tcp连接,不能传输http请求和响应。即,当一个连接结束keepalive_timeout计时,服务端守护进程发送第一个FIN标志ip包后,此时该连接不能再使用了。
四、http keep-alive与tcp keep-alive
http keep-alive为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率;
而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。tcp keep-alive保鲜定时器。
keepalive是TCP保鲜定时器,当网络两端建立了TCP连接之后,闲置(双方无任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等)。如果没有收到对方的ack包,则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对方的ack,如果一直没有收到对方的ack,则会尝试 tcp_keepalive_probes次,每次的间隔时间是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes次,依然没有收到对方的ack包,则会丢弃该TCP连接。TCP连接默认闲置时间是2小时,一般设置为30分钟足够了。
也就是说,仅当http_keepalive_timeout值设置高于tcp_keepalive_time,并且距此tcp连接传输的最后一个http响应,经过了tcp_keepalive_time时间,操作系统才会发送侦测包来决定是否要丢弃这个TCP连接。一般不会出现这种情况。
五、keep-alive与TIME_WAIT
使用http keep-alvie,可以减少服务端TIME_WAIT数量(因为由服务端httpd守护进程主动关闭连接)。启用keep-alive,建立的tcp连接少了,自然要被关闭的tcp连接也相应少了。