https://www.jianshu.com/p/9fe2c140fa52css
首先,咱们要明确咱们谈的是TCP的 KeepAlive
仍是HTTP的 Keep-Alive
。TCP的KeepAlive和HTTP的Keep-Alive是彻底不一样的概念,不能混为一谈。实际上HTTP的KeepAlive写法是Keep-Alive
,跟TCP的KeepAlive
写法上也有不一样。面试
TCP的keepalive是侧重在保持客户端和服务端的链接,一方会不按期发送心跳包给另外一方,当一方端掉的时候,没有断掉的定时发送几回心跳包,若是间隔发送几回,对方都返回的是RST,而不是ACK,那么就释放当前连接。设想一下,若是tcp层没有keepalive的机制,一旦一方断开链接却没有发送FIN给另一方的话,那么另一方会一直觉得这个链接仍是存活的,几天,几月。那么这对服务器资源的影响是很大的。浏览器
HTTP的keep-alive通常咱们都会带上中间的横杠,普通的http链接是客户端链接上服务端,而后结束请求后,由客户端或者服务端进行http链接的关闭。下次再发送请求的时候,客户端再发起一个链接,传送数据,关闭链接。这么个流程反复。可是一旦客户端发送connection:keep-alive头给服务端,且服务端也接受这个keep-alive的话,两边对上暗号,这个链接就能够复用了,一个http处理完以后,另一个http数据直接从这个链接走了。减小新建和断开TCP链接的消耗。服务器
两者的做用简单来讲:网络
HTTP协议的Keep-Alive意图在于短期内链接复用,但愿能够短期内在同一个链接上进行屡次请求/响应。负载均衡
TCP的KeepAlive机制意图在于保活、心跳,检测链接错误。当一个TCP链接两端长时间没有数据传输时(一般默认配置是2小时),发送keepalive探针,探测连接是否存活。运维
总之,记住HTTP的Keep-Alive和TCP的KeepAlive不是一回事。异步
tcp的keepalive是在ESTABLISH状态的时候,双方如何检测链接的可用行。而http的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。socket
1.为何要有KeepAlive?tcp
在谈KeepAlive以前,咱们先来了解下简单TCP知识(知识很简单,高手直接忽略)。首先要明确的是在TCP层是没有“请求”一说的,常常听到在TCP层发送一个请求,这种说法是错误的。
TCP是一种通讯的方式,“请求”一词是事务上的概念,HTTP协议是一种事务协议,若是说发送一个HTTP请求,这种说法就没有问题。也常常听到面试官反馈有些面试运维的同窗,基本的TCP三次握手的概念不清楚,面试官问TCP是如何创建连接,面试者上来就说,假如我是客户端我发送一个请求给服务端,服务端发送一个请求给我。。。
这种一听就知道对TCP基本概念不清楚。下面是我经过wireshark抓取的一个TCP创建握手的过程。(命令行基本上用TCPdump,后面咱们还会用这张图说明问题):
如今我看只要看前3行,这就是TCP三次握手的完整创建过程,第一个报文SYN从发起方发出,第二个报文SYN,ACK是从被链接方发出,第三个报文ACK确认对方的SYN,ACK已经收到,以下图:
可是数据实际上并无传输,请求是有数据的,第四个报文才是数据传输开始的过程,细心的读者应该可以发现wireshark把第四个报文解析成HTTP协议,HTTP协议的GET方法和URI也解析出来,因此说TCP层是没有请求的概念,HTTP协议是事务性协议才有请求的概念,TCP报文承载HTTP协议的请求(Request)和响应(Response)。
如今才是开始说明为何要有KeepAlive。连接创建以后,若是应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当连接好久没有数据报文传输时如何去肯定对方还在线,究竟是掉线了仍是确实没有数据传输,连接还需不须要保持,这种状况在TCP协议设计中是须要考虑到的。
TCP协议经过一种巧妙的方式去解决这个问题,当超过一段时间以后,TCP自动发送一个数据为空的报文给对方,若是对方回应了这个报文,说明对方还在线,连接能够继续保持,若是对方没有报文返回,而且重试了屡次以后则认为连接丢失,没有必要保持连接。
2.怎么开启KeepAlive?
KeepAlive并非默认开启的,在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。须要开启KeepAlive的应用必须在TCP的socket中单独开启。Linux Kernel有三个选项影响到KeepAlive的行为:
- tcp_keepalive_time 7200// 距离上次传送数据多少时间未收到新报文判断为开始检测,单位秒,默认7200s
- tcp_keepalive_intvl 75// 检测开始每多少时间发送心跳包,单位秒,默认75s
- tcp_keepalive_probes 9// 发送几回心跳包对方未响应则close链接,默认9次
TCP socket也有三个选项和内核对应,经过setsockopt系统调用针对单独的socket进行设置:
- TCPKEEPCNT: 覆盖 tcpkeepaliveprobes
- TCPKEEPIDLE: 覆盖 tcpkeepalivetime
- TCPKEEPINTVL: 覆盖 tcpkeepalive_intvl
举个例子,以个人系统默认设置为例,kernel默认设置的tcpkeepalivetime是7200s, 若是我在应用程序中针对socket开启了KeepAlive,而后设置的TCP_KEEPIDLE为60,那么TCP协议栈在发现TCP连接空闲了60s没有数据传输的时候就会发送第一个探测报文。
3. 须要注意,KeepAlive的不足和局限性
其实,tcp自带的keepalive仍是有些不足之处的。
keepalive只能检测链接是否存活,不能检测链接是否可用。例如,某一方发生了死锁,没法在链接上进行任何读写操做,可是操做系统仍然能够响应网络层keepalive包。
TCP keepalive 机制依赖于操做系统的实现,灵活性不够,默认关闭,且默认的 keepalive 心跳时间是 两个小时, 时间较长。
代理(如socks proxy)、或者负载均衡器,会让tcp keep-alive失效
基于此,咱们旺旺须要加上应用层的心跳。这个须要本身实现,这里就不展开了。
1. HTTP为何须要Keep-Alive?
一般一个网页可能会有不少组成部分,除了文本内容,还会有诸如:js、css、图片等静态资源,有时还会异步发起AJAX请求。只有全部的资源都加载完毕后,咱们看到网页完整的内容。然而,一个网页中,可能引入了几十个js、css文件,上百张图片,若是每请求一个资源,就建立一个链接,而后关闭,代价实在太大了。
基于此背景,咱们但愿链接可以在短期内获得复用,在加载同一个网页中的内容时,尽可能的复用链接,这就是HTTP协议中keep-alive属性的做用。
- HTTP的Keep-Alive是HTTP1.1中默认开启的功能。经过headers设置"Connection: close "关闭
- 在HTTP1.0中是默认关闭的。经过headers设置"Connection: Keep-Alive"开启。
对于客户端来讲,不管是浏览器,仍是手机App,或者咱们直接在Java代码中使用HttpUrlConnection,只是负责在请求头中设置Keep-Alive。Keep-Alive属性保持链接的时间长短是由服务端决定的,一般配置都是在几十秒左右。
TCP链接创建以后,HTTP协议使用TCP传输HTTP协议的请求(Request)和响应(Response)数据,一次完整的HTTP事务以下图:
这张图我简化了HTTP(Req)和HTTP(Resp),实际上的请求和响应须要多个TCP报文。
从图中能够发现一个完整的HTTP事务,有连接的创建,请求的发送,响应接收,断开连接这四个过程,早期经过HTTP协议传输的数据以文本为主,一个请求可能就把全部要返回的数据取到,可是,如今要展示一张完整的页面须要不少个请求才能完成,如图片.JS.CSS等,若是每个HTTP请求都须要新建并断开一个TCP,这个开销是彻底没有必要的。
开启HTTP Keep-Alive以后,能复用已有的TCP连接,当前一个请求已经响应完毕,服务器端没有当即关闭TCP连接,而是等待一段时间接收浏览器端可能发送过来的第二个请求,一般浏览器在第一个请求返回以后会当即发送第二个请求,若是某一时刻只能有一个连接,同一个TCP连接处理的请求越多,开启KeepAlive能节省的TCP创建和关闭的消耗就越多。
固然一般会启用多个连接去从服务器器上请求资源,可是开启了Keep-Alive以后,仍然能加快资源的加载速度。HTTP/1.1以后默认开启Keep-Alive, 在HTTP的头域中增长Connection选项。当设置为Connection:keep-alive
表示开启,设置为Connection:close
表示关闭。