1 为什么要有Connection: keep-alive?
在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重用连接。
在后来的HTTP/1.0中以及HTTP/1.1中,引入了重用连接的机制,就是在http请求头中加入Connection: keep-alive来告诉对方这个请求响应完成后不要关闭,下一次咱们还用这个请求继续交流。
协议规定HTTP/1.0如果想要保持长连接,需要在请求头中加上Connection: keep-alive。而HTTP/1.1默认是支持长连接的,有没有这个请求头都行。
2 非长链接和长链接的图示
3 keep-alive的优缺点
3.1 优点
1)节省了服务端 CPU 和内存适用量
2)降低拥塞控制 (TCP 连接减少)
3)减少了后续请求的延迟(无需再进行握手)
3.2 缺点
对于某些低频访问的资源 / 服务,比如一个冷门的图片服务器,一年下不了几次,每下一次连接还保持就比较浪费了(这个场景举的不是很恰当)。Keep-Alive 可能会非常影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间,额外占用了服务端的连接数
4 连接复用后会有什么问题
在没有连接复用时,Http 接收端(注意这里是接收端,并没有特指 Client/Server,因为 Client/Server 都同是发送端和接收端)只需要读取 Socket 中所有的数据就可以了,解决 “拆包” 问题即可;但是连接复用后,无法区分单次 Http 报文的边界,所以还需要额外处理报文边界问题。当然这个通过 Http 中 Header 的长度字段,按需读取即可解决
5 Http 连接复用后包边界问题处理
由于 Http 中 Header 的存在,通过定义一些报文长度的首部字段,可以很方便的处理包边界问题。
在 Http 中,有两种方式处理包边界问题。
5.1 Content-Length 处理包边界
这个是最通常的处理方式,接收端处理报文时首先读取完整首部(Header),然后通过 Header 中的Content-Length来确认报文大小,读取报文时按此长度读取即可,超出长度的报文(“粘包”)不读取,不够长度的报文缓存等待继续读取(“拆包”)。
5.2 Chunked 处理包边界
对于无法确认总报文大小的情况,可以使用 Chunked 的方式来对报文进行分块传输,每一块内标示报文大小。比如 Nginx,开启 Gzip 压缩后,就会开启 Chunked 的传输方式。
通过 Wireshark 抓包,可以很直观的看初 Chunked 的原理:
注意,这里的 chunk 包,和 tcp segment 不是一回事,chunk 只是应用层的一个分包,而 tcp 的 segment 是对应用层报文再次进行分组
每个 chunk 报文前,会携带当前 chunk 的大小
6 Http 连接复用后怎样断开连接
通过 Keep-Alive 已经做到连接复用了,但复用之后什么时候断开连接呢,不然一直保持连接,造成资源的浪费。
Http 协议规定了两种关闭复用连接的方式:
6.1 通过 Keep-Alive Timeout 标识
如果服务端 Response Header 设置了Keep-Alive:timeout={timeout},客户端会就会保持此连接 timeout(单位秒)时间,超时之后关闭连接。
6.2 通过 Connection close 标识
还有一种方式是接收端通在 Response Header 中增加Connection close标识,来主动告诉发送端,连接已经断开了,不能再复用了;客户端接收到此标示后,会销毁连接,再次请求时会重新建立连接。
注意:配置 close 配置后,并不是说每次都新建连接,而是约定此连接可以用几次,达到这个最大次数时,接收端就会返回 close 标识
7 nginx的keepalive相关配置
官方文档:https://nginx.org/en/docs/http/ngx_http_upstream_module.html
7.1 nginx保持keepalive做的事情
1)client到nginx的连接是长连接
2)nginx到server的连接是长连接
7.2 配置TCP层keepalive探活机制的三个参数
#情况1:
http {
server {
listen 127.0.0.1:3306 so_keepalive=on;#开启keepalive探活,探测策略走系统默认
}
}
#情况2:
http {
server {
listen 127.0.0.1:3306 so_keepalive=7m:75s:9;#把空闲时长从系统默认的5分钟改为了7分钟
}
}
其中so_keepalive有如下选择配置
so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]
* on: 开启,探测参数更加系统默认值
* off: 关闭
* keepidle: 连接空闲等待时间
* keepintvl: 发送探测报文间隔时间
* keepcent: 探测报文重试次数
如果nginx未设置so_keepalive配置,则走系统默认的探活策略
7.3 nginx与客户端(一般为浏览器、APP等)保持的长连接进行限制管理
http {
# 客户端连接的超时时间, 为 0 时禁用长连接,
keepalive_timeout 120s;
# 在一个长连接上可以服务的最大请求数目, 当达到最大请求数目且所有已有请求结束后, 连接被关闭, 默认为 100, 即每个连接的最大请求数
keepalive_request 10000;
}
keepalive_timeout:客户端连接在服务器端空闲状态下保持的超时值(默认75s);值为0会禁用keep-alive,也就是说默认不启用长连接;第二个参数:响应的header域中设置“Keep-Alive: timeout=time”;告知浏览器对长连接的维持时间
keepalive_requests:默认100,某个长连接连续处理请求次数限制,超过次数则该长连接被关闭;如果需要释放某个连接占用的内存,必须关闭该链接,内存不大的情况下,不建议开大该配置;在QPS较高的场景,则有必要加大这个参数
7.4 nginx与上游server保持长连接
http {
upstream BACKEND {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
keepalive 300; //空闲连接数
keepalive_timeout 120s;//与上游空闲时间
keepalive_requests 100;//与上游请求处理最大次数
}
server{
listen 8080;
location /{
proxy_pass http://BACKEND;
proxy_http_version 1.1;
proxu_set_header Connection "";
}
}
}
keepalive:限制nginx某个worker最多空闲连接数,此处不会限制worker与上游服务长连接的总数;
keepalive_timeout:nginx与上游长连接最大空闲时间,默认值为60s;
keepalive_requests:nginx与上游长连接最大交互请求的次数,默认值为100;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-11-03 Idea移除和删除模块
2021-11-03 IDEA创建新的模块springboot