【Nginx08】Nginx学习:HTTP核心模块(五)长连接与连接处理

Nginx学习:HTTP核心模块(五)长连接与连接处理

HTTP 基础知识大家掌握的怎么样呀?对于长连接这一块的内容应该也不是什么新鲜东西了吧。毕竟 HTTP1.1 都已经发布这么久了。今天主要来看的就是长连接相关的配置,另外还会介绍几个和连接有关的内容。同时,今天的内容除了 HTTP 外,还需要一点 TCP 的知识。没办法,毕竟 Ngxin 本身就是一个网络代理服务器软件,离不开的就是各种网络相关的知识。相信大家肯定没问题的,毕竟很早前在短视频中就说过,基础能比我差的程序员估计在全国范围内都找不到几个了。

但是不要脸和硬着头皮啃的水平咱还是有的,因此,如果有遗漏或错误的地方,也恳请各位大佬在评论区指出。

好了,不多废话了,进入主题吧。

长连接

关于长连接的知识,属于 HTTP 的基础知识了,咱们不多说,不了解的小伙伴可以去查阅下相关资料。简单来说,一次 HTTP 连接,就要经历 TCP 的三次握手四次挥手,毕竟它是处于网络的第七层,同时也是基于第四层的 TCP 来实现的。如果请求很多,需要不停地建立 TCP 连接,效率明显下降。而长连接则是一次连接后保持这个连接一段时间,如果有其它的请求就可以复用这条连接,从而减少网络连接开销,提升效率。比如很多门户或者电商站,一打开就是一大堆的 JS、图片之类的请求。如果每一个都要单独建立连接,势必会影响页面的整体打开速度。

同时,在进行反向代理的时候,也可以启用长连接功能,减少后端代理的连接次数。反向代理相关的配置我们在后面学习反向代理相关的内容时再说,现在学习的主要是针对 http、server、location 模块的长连接配置。

在 Nginx 中,有完整的长连接配置。

keepalive_disable

指定哪些浏览器不使用长连接功能,或者说是针对行为异常的浏览器关闭长连接功能。

keepalive_disable none | browser ...;

默认 msie6 , 值为 msie6 表示在遇到POST请求时,关闭与老版本 MSIE 浏览器建立长连接。 值为 safari 表示在遇到 Mac OS X 和类 Mac OS X 操作系统下的 Safari 浏览器和类 Safari 浏览器时,不与浏览器建立长连接。 值为none表示为所有浏览器开启长连接功能。

在 nginx 1.1.18 版本及以前,safari 将匹配所有操作系统上的 Safari 和类 Safari 浏览器,并默认不与这些浏览器建立长连接。

我本地是 Mac 电脑,因此,直接设置一个 safari 的配置。

http {……keepalive_disable safari;……
}

配置完成后,使用 Safari 和 Chrome 分别测试,可以看到 Safari 的 Response Header 中的 Connection 的值变成了 close ,而 Chrome 还是正常的 keep-alive 。

keepalive_requests

设置通过一个长连接可以处理的最大请求数。 请求数超过此值,长连接将关闭。

keepalive_requests number;

在版本1.19.10之前,默认值为100,现在默认值是 1000 。定期关闭连接对于释放每个连接的内存分配是必要的。因此,使用过高的最大请求数可能会导致内存使用过多,因此不建议使用。

我们直接配置一个,将它的 number 设置为 2 ,然后建立一个 html 页面以及一堆空的 js 文件。

// nginx.conf
http {……keepalive_requests 2;……
}// testkeepalive1.html
~
~
"testkeepalive1.html" 23L, 461C                                                                                                                                                  20,19-26      All
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>This is testkeepalive1.html<script src="js1/1.js"></script>
<script src="js1/2.js"></script>
<script src="js1/3.js"></script>
<script src="js1/4.js"></script>
<script src="js1/5.js"></script></body>
</html>

好了,现在访问 http://192.168.56.88/testkeepalive1.html 页面,查看所有的请求,目前我们算上这个 html 页面,一共会有 6 个请求。你会发现有的请求的 Connection 会变成 Close ,也就是说一条长连接在请求数量达到设置的值之后就断了,然后又是一个新的请求连接。

一般情况下不需要刻意设置这个值,上面文档的说明中也说过了使用过高的最大请求数可能会导致内存使用过多,正常来说 1000 已经相当够用了,即使是淘宝这样的网站,首页上的请求数也没多少,毕竟大家还会合并请求及图片来进行连接的优化。

keepalive_time

限制通过一个保持活动连接处理请求的最长时间。

keepalive_time time;

达到此时间后,连接在后续请求处理后关闭,默认值是 1h 。它是 Nginx 1.19.10 之后新出的配置,咱们就不做详细的测试了,如果想要测试的同学,可以根据下面的 keepalive_timeout 测试,然后访问一个动态能够 sleep 的请求路径,让 sleep 时间超过这个配置的时间,接着使用一个静态页面来定时发送 ajax 请求查看连接复用情况。比较麻烦,日常估计使用的小伙伴也不会很多,它默认的 1h 估计很多耗时连接也不可能去做这么长时间的操作。

keepalive_timeout

设置客户端的长连接在服务器端保持的最长时间

keepalive_timeout timeout [header_timeout];

在 timeout 设置的时间内,客户端未发起新请求,则长连接关闭。第二个参数为可选项,设置 “Keep-Alive: timeout=time” 响应头的值,可以为这两个参数设置不同的值。“Keep-Alive: timeout=time” 响应头可以被 Mozilla 和 Konqueror 浏览器识别和处理,MSIE 浏览器在大约 60 秒后会关闭长连接。

默认安装完成之后的 Nignx 配置中,这个选项被设置为 65 。如果发现 Nginx 占用服务器的 CPU 特别高,可以尝试调低这个时间,或者直接设置成 0 ,设置成 0 后将整个关闭 keepalive 长连接的功能。

现在我们一起来进行测试,首先添加如下配置。

http {……keepalive_timeout  0;……
}

重载配置后使用一个 Linux 命令查看连接情况。

[root@localhost html]# netstat -nat|grep -i "80"
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN

看来目前还没有连接过来,我们可以访问之前的 /testkeepalive1.html ,马上就能看到有新的连接建立了。

[root@localhost html]# netstat -nat|grep -i "80"
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 192.168.56.88:80        192.168.56.1:49816      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49811      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49810      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49814      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49805      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49812      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:49813      TIME_WAIT

因为我们将 keepalive_timeout 设置成 0 了,所以现在有 7 条连接建立成功,注意,我使用的是 Chrome ,所以还会自带一个 /favicon.ico 请求,加上前面的 html 以及 5 个 js ,正好 7 个连接。如果速度快点过来查看的话,可以看到连接是 ESTABLISHED 状态,表示连接正在使用,TIME_WAIT 表示连接在等待中。

接下来,我们修改 keepalive_timeout 为 5 ,意思就是 5 秒,如果没有使用,就会用新的连接。现在再次访问,会看到依然建立了 5 个连接,毕竟我们相当于同时请求本地的虚拟机,速度还是够快的,只有两个连接被复用了,其它的还是建立了连接。另外,默认 Chrome 可以同时建立 6 个连接,你可以测试再多加几个 js ,然后试试,最多它就只能建立 6 个连接,前面的 js 没有加载完,后面的就会等待加载,这里和长连接无关,即使不使用长连接,也会在 6 个连接中的某一个连接释放之后才会建立新的连接。

[root@localhost html]# netstat -nat|grep -i "80"
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 192.168.56.88:80        192.168.56.1:52469      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52471      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52470      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52472      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52465      ESTABLISHED

在 5 秒内,刷新页面,不会有新的连接出现,但是等待 5 秒后,再次刷新,就会发现又有新的连接建立了。

[root@localhost html]# netstat -nat|grep -i "80"
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 192.168.56.88:80        192.168.56.1:52469      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:52471      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:52692      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52691      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52690      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52686      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52693      ESTABLISHED
tcp        0      0 192.168.56.88:80        192.168.56.1:52470      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:52472      TIME_WAIT
tcp        0      0 192.168.56.88:80        192.168.56.1:52465      TIME_WAIT

再等待一段时间后,所有连接全部关闭。这里关闭连接的时间是操作系统决定的,与操作系统被动断开 TCP 连接的配置有关,主要是 net.ipv4.tcp_tw_reuse 这个配置,大家可以自己查阅相关的资料。正常情况下是在 TIME_WAIT 状态后等待大约 2 分钟,最低可以修改为 1 分钟,通过下面的命令。这个是操作系统的固定值,最低只能是 60 秒,也就是这个 1 分钟。

[root@localhost html]# sysctl net.ipv4.tcp_tw_reuse=1
[root@localhost html]# sysctl -p

这样一分钟以后这些连接信息就会消失了。设置成 0 不管用的,一样会等待,客户端关掉浏览器也没用。这个命令真实的作用其实是如果连接是安全可控的,可以复用 TIME_WAIT 的连接为新的连接所用。它可以快速复用处于 TIME_WAIT 状态的 TCP 连接,也就相当于缩短 TIME_WAIT 状态的持续时间。只有客户端主动关闭连接才会让服务器的正常关闭,使用 curl 命令测试就可以看到效果,你不会看到任何等待的连接。

关于 TIME_WAIT ,其实是为了能够正确、自然地进行 TCP 四次挥手而预留的等待时间,更具体的内容,大家可以再自行查阅 WSL(最大报文生产周期) 相关的知识点。同时,net.ipv4.tcp_tw_reuse 也要慎用,当客户端与服务端主机时间不同步时,客户端的发送的消息有可能会被直接拒绝掉。正式环境使用时,建议:别动!保持默认就好。

长连接总结

关于长连接的内容写了这么多,但其实也仅仅只是四个配置指令而已。更重要的其实是对于 HTTP 基础知识的学习,长连接现在在 Nginx 中是默认打开的,这几个选项也都是有默认值配置好的。所以平常其实我们不太需要去关心他们的配置。就像上面说的,如果发现 CPU 莫名升高,而且是因为 Nginx 的话,那么可以适当调节部分参数。但 CPU 的问题也不一定仅仅是连接的问题,gzip 同样也会带来 CPU 的压力。因此,调优是一个综合的活,要找到问题所在才好应对,比如我们还可以查看连接中 TIME_WAIT 的情况来看是不是连接非常多,这时更好的方案其实是要做负载均衡分散压力了。

连接处理

连接处理主要是针对 Nginx 如何来关闭客户端连接的一些配置操作。Nginx 在接收客户端的请求时可能由于客户端或服务端出错了,要立即响应错误信息给客户端,而 Nginx 在响应错误信息后大分部情况下是需要关闭当前连接的。Nginx 执行完 write() 系统调用(操作系统函数,参考网络编程或操作系统相关资料)把错误信息发送给客户端,write() 系统调用返回成功并不表示数据已经发送到客户端,有可能还在 tcp 连接的 write buffer 里。所以当在某些场景下出现 tcp write buffer 里的数据在 write() 系统调用之后到 close() 系统调用执行之前没有发送完毕,且 tcp read buffer 里面还有数据没有读,close() 系统调用会导致客户端收到 RST 报文且不会拿到服务端发送过来的错误信息数据。

所以,解决问题的重点是,让服务端别发 RST 包。或者说延迟发送,这就是下面要讲的 lingering_close 所要解决的问题。

上面的概念看着就很晕吧,如何测试我也没找到相关的资料,自己也尝试了半天没有什么效果。所以对这一块有了解的同学可以评论区留言哦。在实际应用中,是否应该打开 lingering_close 呢?这个就没有固定的推荐值了,lingering_close 的主要作用是保持更好的客户端兼容性,但是却需要消耗更多的额外资源(比如连接会一直占着)。因此,秉承对于不懂的东西,默认的就是最好的原则,咱们保持默认状态就好了。将来如果学习或者接触到这一块的内容了,再写文章和录视频进行详细的学习吧。

lingering_close

控制 Nginx 如何关闭客户端连接。

lingering_close off | on | always;

它的默认值是 on ,指示 Nginx 在完成关闭连接前等待和处理客户端发来的额外数据。但只有在预测客户端可能发送更多数据的情况才会做此处理。为了控制关闭HTTP/2连接,必须在 server 下(1.19.1)指定该指令。

  • always 指示 Nginx 无条件等待和处理客户端的额外数据。

  • off 指示nginx立即关闭连接,而绝不等待客户端传送额外数据。 这样做破坏了协议,所以正常条件下不应使用。

lingering_time

lingering_close 生效时(非off),这条指令定义 Nginx 处理(读取但忽略)客户端额外数据的最长时间。

lingering_time time;

默认值是 30s,超过这段时间后,Nginx 将关闭连接,不论是否还有更多数据待处理。

lingering_timeout

lingering_close 生效时(非off),这条指令定义 Nginx 等待客户端更多数据到来的最长时间。

lingering_timeout time;

默认值是 5s ,如果在这段时间内,Nginx 没有接收到数据,Nginx 将关闭连接。否则,Nginx 将接收数据,忽略它,然后再等待更多数据。 这个“等待——接收——忽略”的循环一直重复,但总时间不会超过 lingering_time 指令定义的时间。

总结

怎么说呢,学这些真的想回去好好再补补网络知识了。就这么点内容,也已经是边查资料边测试边写了,后面还有那么多配置以及牵涉到的相关知识,想想都头大。不过没关系,谁让自己喜欢这行呢,各位同学是不是也感觉到每次看完文章或者视频也会跟我一样多少会有一点点的进步呢?

长连接一般我们都会简单配置一下,通常也是以 keepalive_time 和 keepalive_time_out 的配置为主,其它两个说实话,没学之前我都不知道有这俩货。另外一个连接处理相关的配置更是从来没用过。但是,现在起码我们了个印象,将来或许哪天它们就能为我们解决大问题呢。

参考文档:

http://nginx.org/en/docs/http/ngx_http_core_module.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ylb-接口4投资排行榜

总览&#xff1a; 1、使用Redis存储投资信息 2、Redis常量类 在common模块constants包&#xff0c;创建一个Redis常量类&#xff08;RedisKey&#xff09;&#xff1a; package com.bjpowernode.common.constants;public class RedisKey {/*投资排行榜*/public static fin…

Qt5.15.2安装

解释一下 Qt 的版本号 比如 5.15.2 是完整的 Qt 版本号&#xff0c;第一个数字 5 是大版本号&#xff08;major&#xff09;&#xff0c;第二个数字 15 是小版本号&#xff08;minor&#xff09;&#xff0c;第三个数字 2 是补丁号&#xff08;patch&#xff09;。 只要前面两个…

oracle 如何连同空表一起导出成dmp的方法

1、oracle导出dmp文件的时候&#xff0c;经常会出现一些空表&#xff0c;没有一并被导出的情况。 执行sql select alter table ||table_name|| allocate extent; from user_tables where num_rows0 or num_rows is null; 新建一个sql窗口&#xff0c;把查询结果的sql&#…

GSV6201替代方案|CS5466设计资料|CS5466原理图|typec转HDMI_8k方案芯片

GSV6201是一款高性能、低功耗、高性能的&#xff0c;USB Type-C备用模式显示端口1.4至HDMI 2.1转换器。通过集成增强型微控制器&#xff0c;GSV6201创造了一个经济高效的解决方案提供了上市时间优势。显示端口接收机支持高达32.4Gbps&#xff08;HBR3&#xff0c;4通道&#xf…

go map[string]any 转map[string]string

目录 一 、map[string]any参数转为map[string]string 二 、go 请求参数绑定 gin框架示例 三、 go 中实现接口 四 、go中设计模式策略模式实现 一 、map[string]any参数转为map[string]string 场景&#xff1a;在go中有将map[string]any参数转为map[string]string 其中…

uniapp和uview组件实现下拉触底刷新列表

下面是一个在UniApp中使用uView组件实现下拉触底刷新列表的示例&#xff0c;并使用Axios来请求分页数据列表&#xff1a; 首先&#xff0c;确保你已经在UniApp项目中添加了uView组件库。你可以在项目根目录执行以下命令安装它们&#xff1a; npm install uview-ui或者使用 Hb…

曲师大2023大一新生排位赛-D.Factor题解

D.Factor 题目描述 你有一个集合 &#xff0c;和具有 个正整数的数组 . 最初&#xff0c;集合 为空&#xff08;不包含任一元素&#xff09;。你将按照以下方式填充集合 : 以此枚举数组 a 中的每个元素。对于数组中的第 i 个元素 &#xff0c;生成 ​ 的因子集合 ​。如果…

使用对象解构赋值,将对象的某些属性赋值给另一个对象

在处理接口返回的数据时&#xff0c;我需要将接口返回的数据&#xff08;对象&#xff09;的某些属性用另一个对象进行接收&#xff0c;学习对象解构赋值之前&#xff0c;我一直使用的都是最笨的方法&#xff1a; this.formData.projectId res.data.projectId this.formData.…

idea中常用的快捷键

快捷键: 1.快速生成main方法 main/psvm public static void main(String[] args) {} 2.快速复制当前行的代码: ctrld 3.快速捕获异常: altctrlt 4.快速打印结果: sout/soutv System.out.println(s); System.out.println("s " s); 5.自动生成对象的返回值…

【运维工程师学习六】LAM部署搭建个人Discuz论坛

【运维工程师学习六】LAM部署搭建个人Discuz论坛 1、先卸载Mariadb再安装Mysql2、MySQL官网rpm包下载3、在rpm包路径下安装 YUM Repo 文件4、更新软件仓库本地数据库信息5、开始部署——php的安装6、搜索yum包7、开始部署——配置apache以支持php&#xff08;1&#xff09;配置…

GitHub上整理的一些实用的工具

1. Visual Studio Code 简称VScode&#xff0c;是一个轻量且强大的跨平台开源代码编辑器&#xff08;IDE&#xff09;&#xff0c;支持Windows&#xff0c;OS X和Linux。内置JavaScript、TypeScript和Node.js支持&#xff0c;而且拥有丰富的插件生态系统&#xff0c;可通过安装…

关于GDP调试

说出一些常见的指令 break&#xff08;或缩写为b&#xff09;&#xff1a;设置断点&#xff0c;例如 b main 在 main 函数处设置断点run&#xff08;或缩写为r&#xff09;&#xff1a;运行程序。step&#xff08;或缩写为s&#xff09;&#xff1a;单步执行程序&#xff0c;进…

SylixOS下SSH和SFTP连接

简要 基于网络的连接&#xff08;telnet&#xff0c;ftp&#xff09;方便高效&#xff0c;但其是基于明文的通信&#xff0c;容易被窃取、篡改和攻击&#xff0c;存在网络安全问题&#xff0c;尤其在进行远程访问时&#xff0c;穿过复杂未知的公网环境非常危险&#xff0c;为此…

快速替换chatgpt-web项目的access token的脚本

问题背景&#xff0c;由于GPT access token 会定期失效&#xff0c;更换服务器的项目的access token较为繁琐&#xff0c;特写一脚本协助完成更换access token。 使用方法&#xff1a; # token从https://chat.openai.com/api/auth/session获取 ./replace_token.sh token脚本内…

ELK-日志服务【es-安装使用】

目录 【1】安装-配置elasticsearch&#xff08;01、02、03相同&#xff09; 端口 【2】安装-配置-启动-Kibana 【3】浏览器访问测试&#xff08;10.0.0.21:5601&#xff09; 【4】使用kibana创建、更新、删除es索引、文档 【5】组es集群&#xff08;投票选举机制&#xf…

代码随想录一刷day49

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣121. 买卖股票的最佳时机二、力扣122.买卖股票的最佳时机II 前言 一、力扣121. 买卖股票的最佳时机 class Solution {public int maxProfit(int[] pr…

64.合理使用预训练网络-3

64.1 目标检测中如何从零开始训练(train from scratch) 目标检测和其他任务从零训练模型一样,只要拥有足够的数据以及充分而有效的训练,同样能训练出不亚于利用预训练模型的检测器。 1、数据集不大时,同样需要进行数据集增强。2、预训练模型拥有更好的初始化,train from sc…

【多线程】(六)Java并发编程深度解析:常见锁策略、CAS、synchronized原理、线程安全集合类和死锁详解

文章目录 一、常见锁策略1.1 乐观锁和悲观锁1.2 读写锁1.3 重量级锁和轻量级锁1.4 自旋锁1.5 公平锁和非公平锁1.6 可重入锁和不可重入锁 二、CAS2.1 什么是CAS2.2 CAS的实现原理2.3 CAS应用2.4 ABA问题 三、synchronized原理3.1 synchronized锁的特点3.2 加锁工作过程3.3 锁消…

自动驾驶多任务框架 MultiTask V3、HybridNets和YOLOP比较

目标检测和分割是自动驾驶汽车感知系统的两个核心模块。它们应该具有高效率和低延迟,同时降低计算复杂性。目前,最常用的算法是基于深度神经网络的,这保证了高效率,但需要高性能的计算平台。 在自动驾驶汽车的场景下,大多使用的都是计算能力有限的嵌入式平台,这使得难以满…

力扣 332. 重新安排行程

一、题目描述 给你一份航线列表 tickets&#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK 开始。…