部分参考:小林coding
- HTTP的Keep-Alive,是由应用层(用户态)实现的,称为HTTP长连接
- TCP的Keepalive,是有TCP层(内核态)实现的,称为TCP保活机制
HTTP的Keep-Alive
由于HTTP是基于TCP传输协议实现的,客户端与服务端要进行HTTP通信前,需要先建立TCP连接,然后客户端发送送HTTP请求,服务端收到后就返回响应。
短连接
就是每次请求都要经历:建立TCP->请求资源->响应资源->释放资源 的过程
长连接
HTTP的header头中的Connection:Keep-Alive,可以使用同一个TCP连接来发送和接收多个HTTP请求/应答,避免了连接建立和释放的开销
HTTP长连接的特点是:只要任意一端没有明确提出断开要求,则保持TCP的连接状态
如何使用HTTP的Keep-Alive功能
在HTTP 1.0中,长连接默认是关闭的,必须在请求头和响应头中都包含
ruby
Connection:Keep-Alive
连接才不会中断
在HTTP 1.1中,默认开始Keep-Alive,所以如果要关闭Keep-Alive,需要在HTTP请求的包头中加入
arduino
Connection:close
现在大多数浏览器都是默认使用HTTP/1.1,所以Keep-Alive是默认打开的,一旦客户端和服务端达成协议,那么长链接就建立好了
长连接的好处
HTTP长连接不仅减少了TCP资源的开销 ,而且这给HTTP流水线技术提供了可实现的基础。
HTTP流水线
客户端可以先一次性发送多个请求,而在发送过程中,不需要先等待服务器的回应 ,以减少整体的响应时间。服务器按照顺序响应,先回应A请求,完成后再回应B请求。
但是,要等服务端响应完客户端第一批发送的请求后,客户端才能发出下一批请求,也就是说如果服务端响应第一批请求的过程中发生了阻塞,那么客户端就无法发出下一批的请求,此时就造成了「队头阻塞」的问题
keepalive_timeout参数
为了避免资源浪费的情况(在长连接中,客户端完成一个HTTP请求后,就不再发起新的请求,此时这个TCP连接一直占用的情况),web服务软件(比如nginx) 一帮都会提供keepalive_timeout参数,用来指定HTTP长连接的超时时间
若设置的HTTP长连接的超时时间是60s,web服务软件就会启动一个定时器,如果客户端在收到最后一个HTTP响应后,在60s内都没有再发起新的请求,定时器的时间一到,就会触发毁掉函数来释放该链接
TCP的Keepalive
TCP的Keepalive是TCP的保活机制,即如果两端的TCP连接一直没有数据交互,达到了触发TCP保活机制的条件(超过了设置的idle时间),那么内核里的TCP协议栈就会发送探测报文。
- 如果对端程序是正常工作的,当TCP爆火的探测报文发送给对端,对端会正常响应,这样TCP保活时间会被重置,等待下一个TCP保活时间的到来
- 如果对端主机奔溃,或对端由于其它原因导致报文不可达。当TCP保活的探测报文发送给对端后,没有响应,连续几次,达到保活探测次数后,TCP会报告该TCP连接已经死亡
keepAlive默认情况下是关闭的,如果应用程序想要使用TCP保活机制,需要通过socket接口设置SO_KEEPALIVE选项才能够生效(在Java中,应用程序一般通过设置 java.net.SocketOptions 来开启TCP连接的KeepAlive),如果没有设置,那么就无法使用TCP保活机制
如果HTTP没有设置Keep Alive,则关闭连接时,由于是两端主动发的FIN报文,因此即使TCP已经设置了KeepAlive,TCP连接也会被正常关闭
那么只开启HTTP长链接而不开启TCP长连接的话,HTTP的KeepAlive还起作用吗
此时HTTP的KeepAlive还会正常起作用,TCP连接还会复用,但是被复用的TCP连接出现故障的概率会高很多。 由于没有开启TCP的KeepAlive,防火墙或负载转发服务等中间设备可能因为该TCP空闲太长而悄悄关闭该链接,当HTTP从自己的连接池中拿出该TCP链接时,可能并不知道该链接被关闭,继续使用就会出现错误,所以一般来说,开启HTTP的KeepAlive的应用都会开启TCP的KeepAlive
mac中可以使用sysctl -A | grep net.inet.tcp来查看本机tcp的一些配置
通过man 4 tcp可以看到
默认的保活时间为 7200秒(两小时)
总结
1、HTTP的Keep-Alive也叫HTTP长连接,该功能是由应用程序实现的,在Header头中添加Connect:Keep-Alive,只有到了keepalive 头部规定的timeout,或者携带Connect:Close,才会关闭该TCP连接,可以使得用同一个TCP连接来发送和接收多个HTTP请求/应答,减少了HTTP端链接带来的多次TCP连接建立的释放和开销
2、TCP的Keepalive也叫TCP保活机制,该功能是由内核实现的,通过keep-alive报文来防止TCP连接被对端、防火墙或其他中间设备意外中断,和上层应用没有任何关系,只负责维护单个TCP连接的状态,其上层应用可以复用该TCP长链接,也可以关闭该TCP长连接
注意
和TCP连接不同,一个完整的HTTP事务,可能会横跨多个TCP连接,比如浏览器请求某个网页,请求可能先通过浏览器与负载均衡之间的TCP连接传输,再经过负载均衡到Nginx的TCP连接,最后在经过Nginx与业务Tomcat服务器的TCP连接,Tomcat处理完请求并返回响应后,响应沿着同样的TCP连接路线返回
因此HTTP的头部被分为了两部分:End-to-end 头部和 Hop-by-hop 头部,End-to-end 头部会被中间的代理原样转发,比如浏览器请求报文中的 host 头部,会被负载均衡、反向代理原样转发到Tomcat里,除非特意修改。而 Hop-by-hop 头部则只在当前TCP连接里有效,大部分头部都是 End-to-end ,但KeepAlive相关头部很明显和TCP连接有密切关系,因此是 Hop-by-hop 的
也就是说,即使浏览器请求时携带了 Connection: Keep-Alive ,也只表示浏览器到负载均衡之间是长连接,但负载均衡到nginx、nginx到tomcat是否是长连接则需要具体分析。比如Nginx虽然支持HTTP的Keep-Alive,但由Nginx发起的HTTP请求默认不是长连接,此时如果需要的话,我们可能要手动设置一下nginx和tomcat的TCP长链接