1. 前言
最近在浏览知乎的时候发现了这个问题,觉得很有趣,在此处记录一下。
借用小林coding的回答:
HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制。
2. TCP的keepalive
TCP Keepalive是一种机制,用于检测TCP连接是否仍然有效,即对方主机是否仍然可达。这个机制可以帮助识别和清理“死”连接,即那些在网络中断或对方主机崩溃后仍然打开的连接。TCP Keepalive通过定期发送探测消息给对方主机来工作。如果在一定时间内没有收到响应,连接被认为是死的,并且会被关闭。
2.1 工作原理
空闲时间:当TCP连接在一定时间(称为“Keepalive时间”)内没有数据传输时,TCP层会自动发送一个Keepalive探测包给对方。
探测尝试和间隔:如果对方没有响应这个探测包,TCP会继续发送更多的探测包。这些探测包之间的间隔时间以及尝试的次数也可以配置。
连接关闭:如果所有的探测包都没有得到响应,连接最终会被关闭。
2.2 主机配置
TCP Keepalive的行为可以通过操作系统进行配置。不同的操作系统提供了不同的配置接口,此处仅介绍Linux系统下配置。
查看当前设置:
sysctl net.ipv4.tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_intvl
sysctl net.ipv4.tcp_keepalive_probes
修改当前设置:
sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_intvl=60
sysctl -w net.ipv4.tcp_keepalive_probes=10
在应用程序中,可以通过客户端选项,明确TCP连接启用keepalive,示例如下(Netty项目):
需要注意的是,TCP keepalive默认设置较为保守,具体如下所示:
因此,在实际应用场景中,多会启用定时心跳机制(例如默认五分钟),以维持客户端与服务端的TCP连接。
此外,在内网网络环境较好的情况下,建议修改主机的TCP keepliave设置(缩短心跳间隔,减少心跳探测次数),以保证中间件通信能够快速感知连接失效等异常情况。
3. HTTP的keepalive
HTTP Keep-Alive,也称为持久连接,是一种通信机制,它允许客户端和服务器在完成一次HTTP请求-响应后,保持TCP连接打开,以便用于后续的HTTP请求。这种机制减少了因为频繁建立和关闭连接而产生的开销,提高了HTTP通信的效率。
3.1 工作原理
连接复用:通过保持底层的TCP连接打开,HTTP Keep-Alive允许在同一连接上发送和接收多个HTTP请求/响应,而不是每次交换都打开一个新的连接。
Connection头部:HTTP Keep-Alive通过HTTP头部
Connection
来控制。客户端在HTTP请求中包含Connection: keep-alive
,表明它希望服务器保持连接打开。如果服务器支持Keep-Alive,它也会在响应中包含Connection: keep-alive
。超时和最大请求数:服务器通常会为Keep-Alive连接设置超时时间和最大请求数限制。当超时时间到达或达到最大请求数后,服务器会关闭连接。
3.2 优点
减少延迟:避免了每次请求都进行TCP三次握手的延迟。
提高性能:减少了CPU和内存的使用,提高了连接的效率。
更有效的网络利用:减少了TCP连接的开销,使网络资源得到更有效的利用。
3.3 示例
客户端请求示例,请求头中包含Connection: keep-alive
:
GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
服务器响应示例,响应头中也包含Connection: keep-alive
,并可能包含Keep-Alive
头部,指示超时时间和最大请求数:
HTTP/1.1 200 OK
Date: Mon, 23 May 2022 22:38:34 GMT
Server: Apache/2.4.1 (Unix)
Connection: keep-alive
Keep-Alive: timeout=5, max=100
Content-Type: text/html
<html>
...
</html>
3.4 注意事项
默认超时时间:浏览器默认的HTTP keepalive时长为60s,因此建议服务端的代理(例如Nginx)设置keepalive时长略大于60s;
Nginx的
keepalive_requests
:在 HTTP 配置中,它控制 Nginx 与客户端之间 keep-alive 连接的请求次数;
在 upstream 配置中,它控制 Nginx 与上游服务器之间 keep-alive 连接的请求次数;
数值默认为100,满足常规web端代理场景;
在HTTP 2代理场景中,因为协议的特殊性,需要放宽此数值以便充分利用http2特性(参考文章:漏洞处置:HTTP/2 快速重置攻击对 F5 NGINX 的影响)