一、TCP 长连接 (Keep Alive)

TCP 长连接是一种保持 TCP 连接的机制。当一个 TCP 连接建立之后,启用 TCP Keep Alive 的一端便会启动一个计时器,当这个计时器到达 0 之后,一个 TCP 探测包便会被发出。这个 TCP 探测包是一个纯 ACK 包,但是其 Seq 与上一个包是重复的。

打个比喻,TCP Keep Alive 是这样的:

TCP 连接两端好比两个人,这两个人之间保持通信往来(建立 TCP 连接)。如果他俩经常通信(经常发送 TCP 数据),那这个 TCP 连接自然是建立着的。但如果两人只是偶尔通信。那么,其中一个人(或两人同时)想知道对方是否还在,就会定期发送一份邮件(Keep Alive 探测包),这个邮件没有实质内容,只是问对方是否还在,如果对方收到,就会回复说还在(对这个探测包的 ACK 回应)。

需要注意的是,keep alive 技术只是 TCP 技术中的一个可选项。因为不当的配置可能会引起诸如一个正在被使用的 TCP 连接被提前关闭这样的问题,如在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),所以默认是关闭的。

二、TCP KeepAlive相关配置

TCP KeepAlive并不是默认开启的,在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。需要开启KeepAlive的应用必须在TCP的socket中单独开启。Linux Kernel有三个选项影响到KeepAlive的行为:

tcp_keepalive_time 7200 // 距离上次传送数据多少时间未收到新报文判断为开始检测,单位秒,默认7200s(2小时)

tcp_keepalive_intvl 75 // 检测开始每多少时间发送心跳包,单位秒,默认75s

tcp_keepalive_probes 9 // 发送几次心跳包对方未响应则close连接,默认9次

在 Linux 操作系统中,TCP Keep Alive 相关的配置可以在 /proc/sys/net/ipv4/ 目录中找到:

haproxy tcp如何进行会话保持 haproxy tcp长连接_TCP

more /proc/sys/net/ipv4/tcp_keepalive_*

TCP长连接和HTTP长连接(Keep Alive)

tcp_keepalive_time 的含义是在空闲相应时间(单位是秒)之后,TCP 协议栈将发送 Keep Alive 探测包;tcp_keepalive_intvl 的含义是开始探测之后每个探测包所间隔的时长,单位同样是秒;tcp_keepalive_probes 是探测包的个数。

三、HTTP 长连接 (Keep Alive)

在 HTTP 1.0 时期,每个 TCP 连接只会被一个 HTTP Transaction(请求加响应)使用。之后,这个 TCP 连接便会被关闭。当网页内容越来越复杂,包含大量图片、CSS 等资源之后,这种模式效率就显得太低了。所以,在 HTTP 1.1 中,引入了 HTTP persistent connection 的概念,也称为 HTTP keep-alive(后面统一称呼为 HTTP 长连接)。

keep-alive属性保持连接的时间长短是由服务端决定的,通常配置都是在几十秒左右。

TCP连接建立之后,HTTP协议使用TCP传输HTTP协议的请求(Request)和响应(Response)数据,一次完整的HTTP事务如下图:

haproxy tcp如何进行会话保持 haproxy tcp长连接_TCP_02

TCP长连接和HTTP长连接(Keep Alive)

这张图简化了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表示关闭。

TCP长连接和HTTP长连接(Keep Alive)

haproxy tcp如何进行会话保持 haproxy tcp长连接_haproxy tcp如何进行会话保持_03

四、TCP Keep Alive 与 HTTP Keep-Alive 比较

TCP的keepalive是侧重在保持客户端和服务端的连接,一方会不定期发送心跳包给另一方,没有断掉一方的定时发送几次心跳包。如果间隔发送几次,对方都返回的是RST,而不是ACK,那么就释放当前连接。

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是在ESTABLISHED状态的时候,双方如何检测连接的可用性。而HTTP的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。