TCP Keepalive与HTTP Keep-Alive对比

HTTP Keep-Alive

HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使 这样也没有多大问题。可随着 HTTP 的普及与发展,文档中包含大量图片的 情况多了起来。比如,使用浏览器浏览一个包含多张图片的 HTML页面时,在发送 请求访问 HTML页面资源的同时,也会请求该 HTML页面里包含的 其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销。

为解决上述 TCP 连接的问题,HTTP/1.1 和一部分的 HTTP/1.0 想出了 持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。

HTTP 协议采用“请求-应答”模式,当使用普通模式,即非 Keep-Alive 模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP 协议为无连接的协议);当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。持久连接的特点是,只要任意一端 没有明确提出断开连接,则保持 TCP 连接状态。

在 HTTP 1.1 版本中,默认情况下所有连接都被保持,如果加入 "Connection: close" 才关闭。目前大部分浏览器都使用 HTTP 1.1 协议,也就是说默认都会发起 Keep-Alive 的连接请求了,所以是否能完成一个完整的 Keep-Alive 连接就看服务器设置情况。

由于 HTTP 1.0 没有官方的 Keep-Alive 规范,并且也已经基本被淘汰,以下讨论均是针对 HTTP 1.1 标准中的 Keep-Alive 展开的。

注意:

  • HTTP Keep-Alive 简单说就是保持当前的TCP连接,避免了重新建立连接。
  • HTTP 长连接不可能一直保持,例如 Keep-Alive: timeout=5, max=100,表示这个TCP通道可以保持5秒,max=100,表示这个长连接最多接收100次请求就断开。

Keep-Alive模式下如何知道某一次数据传输结束

如果不是Keep-Alive模式,HTTP协议中客户端发送一个请求,服务器响应其请求,返回数据。服务器通常在发送回所请求的数据之后就关闭连接。这样客户端读数据时会返回EOF(-1),就知道数据已经接收完全了。
但是如果开启了 Keep-Alive模式,那么客户端如何知道某一次的响应结束了呢?

以下有两个方法

  • 如果是静态的响应数据,可以通过判断响应头部中的Content-Length 字段,判断数据达到这个大小就知道数据传输结束了。
  • 但是返回的数据是动态变化的,服务器不能第一时间知道数据长度,这样就没有 Content-Length 关键字了。这种情况下,服务器是分块传输数据的,Transfer-Encoding:chunk,这时候就要根据传输的数据块chunk来判断,数据传输结束的时候,最后的一个数据块chunk的长度是0。

使用HTTP建立长连接

当需要建立 HTTP 长连接时,HTTP 请求头将包含如下内容:
Connection: Keep-Alive
如果服务端同意建立长连接,HTTP 响应头也将包含如下内容:
Connection: Keep-Alive
当需要关闭连接时,HTTP 头中会包含如下内容:
Connection: Close

img

其实对于HTTP keep-alive机制可以总结为上图所示。

在长连接情况下,多个HTTP请求可以复用同一个TCP连接,这就节省了很多TCP连接建立和断开的消耗


TCP Keep Alive

TCP 的连接,实际上是一种纯软件层面的概念,在物理层面并没有“连接”这种概念。TCP 通信双方建立交互的连接,但是并不是一直存在数据交互,有些连接会在数据交互完毕后,主动释放连接,而有些不会。在长时间无数据交互的时间段内,交互双方都有可能出现掉电、死机、异常重启等各种意外,当这些意外发生之后,这些 TCP 连接并未来得及正常释放,在软件层面上,连接的另一方并不知道对端的情况,它会一直维护这个连接,长时间的积累会导致非常多的半打开连接,造成端系统资源的消耗和浪费,为了解决这个问题,在传输层可以利用 TCP 的 KeepAlive 机制实现来实现。主流的操作系统基本都在内核里支持了这个特性。

HTTP的Keep-Alive与TCP的Keep Alive,有些不同,两者意图不一样。前者主要是 TCP连接复用,避免建立过多的TCP连接。而TCP的Keep Alive的意图是在于保持TCP连接的存活,就是发送心跳包。隔一段时间给连接对端发送一个探测包,如果收到对方回应的 ACK,则认为连接还是存活的,在超过一定重试次数之后还是没有收到对方的回应,则丢弃该 TCP 连接。

如果在一段时间(保活时间:tcp_keepalive_time)内此连接都不活跃,开启保活功能的一端会向对端发送一个保活探测报文。

  • 若对端正常存活,且连接有效,对端必然能收到探测报文并进行响应。此时,发送端收到响应报文则证明TCP连接正常,重置保活时间计数器即可。
  • 若由于网络原因或其他原因导致,发送端无法正常收到保活探测报文的响应。那么在一定探测时间间隔(tcp_keepalive_intvl)后,将继续发送保活探测报文。直到收到对端的响应,或者达到配置的探测循环次数上限(tcp_keepalive_probes)都没有收到对端响应,这时对端会被认为不可达,TCP连接随存在但已失效,需要将连接做中断处理。

在探测过程中,对端主机会处于以下四种状态之一:

img

TCP短连接

模拟一下TCP短连接的情况:

  1. client 向 server 发起连接请求
  2. server 接到请求,双方建立连接
  3. client 向 server 发送消息
  4. server 回应 client
  5. 一次读写完成,此时双方任何一个都可以发起 close 操作

连接只保持在数据传输过程,请求发起,连接建立,数据返回,连接关闭。只在需要发送数据时才去建立一个连接,数据发送完成后则断开此连接,即每次连接只完成一项业务的发送。

它适用于一些实时数据请求,配合轮询来进行新旧数据的更替。

TCP长连接

长连接便是在连接发起后,在请求关闭连接前客户端与服务端都保持连接,实质是保持这个通信管道,之后便可以对其进行复用。在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。
它适用于涉及消息推送,请求频繁的场景(直播,流媒体)。连接建立后,在该连接下的所有请求都可以重用这个长连接管道,避免了频繁了连接请求,提升了效率。

总结

  • TCP连接往往就是我们广义理解上的长连接,因为它具备双端连续收发报文的能力;开启了keep-alive的HTTP连接,也是一种长连接,但是它由于协议本身的限制,服务端无法主动发起应用报文。

  • TCP中的keepalive是用来保鲜、保活的;HTTP中的keep-alive机制主要为了让支撑它的TCP连接活的的更久,所以通常又叫做:HTTP persistent connection(持久连接) 和 HTTP connection reuse(连接重用)。

  • HTTP协议中的Keep-Alive意图在于连接复用,在同一个连接中传输多个HTTP请求。

  • TCP协议中的Keepalive意图在于连接的保活、心跳检测,空闲连接的释放。

参考文章

HTTP协议的Keep-Alive 模式 - 简书 (jianshu.com)

HTTP 协议 · 笔试面试知识整理 (hit-alibaba.github.io)

HTTP持久连接方式 - 掘金 (juejin.cn)

HTTP keep-alive和TCP keepalive的区别,你了解吗? - 知乎 (zhihu.com)

posted @ 2022-05-26 10:44  melons  阅读(123)  评论(0编辑  收藏  举报