【nginx实战】通过nginx实现http 长连接(即keep alive)

文章目录

  • 一. http的长连接历史
    • 1. HTTP短连接模型
    • 2. HTTP长连接模型
  • 二. nginx作为代理时实现HTTP长连接
    • 1. nginx与client的长连接
      • 1.1. keepalive_timeout指令
      • 1.2. keepalive_requests指令
        • * 场景分析
    • 2. 保持和server的长连接
      • 2.1. location设置
        • * 场景分析
      • 2.2. upstream设置
        • * 场景分析
          • 场景1
          • 场景2
          • 场景3

长连接基础:先了解为什么要保持长连接,http的长连接历史。
长连接实战:接着如何分析如何通过nginx设置长连接。如果不恰当的设置长连接,会出现什么问题。

一. http的长连接历史

HTTP是属于应用层(七层)的协议,传输层(四层)使用的是TCP协议,所以HTTP的长连接和短连接,其本质就是TCP的长连接和短连接;
HTTP是一个无状态的面向连接的协议,指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态,但无状态不代表HTTP不能保持TCP连接;
TCP建立连接和断开连接是需要三握四挥的,也就说HTTP连接的建立与断开是消耗资源的。

接下来正式了解下http长短连接模型

1. HTTP短连接模型

短连接的基本逻辑与特点
HTTP 短连接模型是最早期的模型,也是 HTTP/1.0 的默认模型。在早期,HTTP 使用一个简单的模型来处理这样的连接。这些连接的生命周期是短暂的:每发起一个请求时都先有一次TCP握手,然后创建一个新连接,并在收到应答时立即关闭。

持续的短连接是耗时、耗费资源的
实际上,TCP 协议握手本身就是耗费时间的,所以 TCP 可以保持更多的热连接来适应负载。短连接破坏了 TCP 具备的能力,新的冷连接降低了其性能。

长短连接的设置

在 HTTP/1.0 中如果没有指定 Connection协议头,或者是值被设置为 close就会启用短连接模型,要在 HTTP/1.0 中启用长连接模型,需要在协议头中指定Connection: Keep-Alive ,不过并不建议这样操作。

而在 HTTP/1.1 中,默认使用长连接模型,只有当 Connection被设置为 close 时才会用到这个短连接模型,协议头都不用再去声明它(但是一般还是会把它加上,以防万一因为某种原因要退回到 HTTP/1.0 )。

 

2. HTTP长连接模型

长连接的趋势
后来,网页需要请求的资源越来越多,短连接模型显然已经十分吃力了。因为短连接有两个比较大的问题:创建新连接耗费的时间尤为明显(三次握手很耗费时间),另外 TCP 连接的性能只有在该连接被使用一段时间后(热连接)才能得到改善。因此在HTTP/1.1中引入了长连接模型。

在 HTTP/1.1 之前,长连接也被称为keep-alive 连接。
一个长连接会保持一段时间,重复用于发送一系列请求,节省了新建 TCP 连接握手的时间,还可以利用 TCP 的性能增强能力(ing)。当然这个连接也不会一直保留着:连接在空闲一段时间后会被关闭(服务器可以使用 Keep-Alive 协议头来指定一个最小的连接保持时间)。

长连接的缺点:资源占用问题
使用长连接本质上是因为当不断地三次握手建立连接所消耗的资源大于维持连接所需要的资源

当处于空闲状态时,它还是会消耗服务器资源。如果空闲较长,可以使用非长连接,即尽快关闭那些空闲的连接,也能对性能有所提升。

二. nginx作为代理时实现HTTP长连接

当我们配置Nginx作为代理服务器的时候,想要支持HTTP长连接,需要client到Nginx和Nginx到server(nginx中upstream配置的server)都是长连接,因为此时Nginx既是client的server也是server的client。

多个HTTP请求通过复用TCP连接,会达到以下效果:

  1. 减少握手次数
  2. 通过减少并发连接数减少了服务器资源的消耗
  3. 降低TCP拥塞控制的影响

 

1. nginx与client的长连接

为了在client和nginx之间保持长连接,有两个要求:

  1. client发送的HTTP请求要求keep alive
    2.nginx设置上支持keep alive:默认情况下,nginx已经自动开启了对client连接的keep alive支持。

 

1.1. keepalive_timeout指令

语法:用户一个HTTP请求连接完成以后,最多经过timeout时间,如果还是没有新的请求,就会关闭连接

Syntax:    keepalive_timeout timeout [header_timeout];
Default:   keepalive_timeout 75s;
Context:   http, server, location1. 第一个参数设置keep-alive客户端连接在服务器端保持开启的超时值。值为0会禁用keep-alive客户端连接。默认75s一般情况下也够用,对于一些请求比较大的内部服务器通讯的场景,适当加大为120s或者300s。2. (可选的)第二个参数在响应的header域中设置一个值“Keep-Alive: timeout=time”。第二个参数通常可以不用设置。

 

1.2. keepalive_requests指令

使用语法:

Syntax:	keepalive_requests number;
Default:	keepalive_requests 1000;
Context:	http, server, location;该指令首次出现在版本0.8.0中。在版本1.19.10之前,默认值为1001.参数的作用
>一个TCP(keep-alive)连接上最多执行多少个HTTP请求。
>当达到这个参数设置的最大值(默认是1000)时,则nginx会强行关闭这个长连接,
>逼迫客户端不得不重新建立新的长连接。注意:
定期关闭连接是为了释放每个连接的内存分配。
因此,设置过高的最大请求数可能导致过多的内存使用,这是不推荐的。

 

* 场景分析

这个参数往往被大多数人忽略,因为大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10万QPS,甚至达到30万,50万甚至更高) 的场景,默认的1000就不适用了。因为此时会频繁创建长连接。

出现频繁的关闭、创建连接:

当QPS=10万/s时,客户端每秒发送10万个请求(通常建立有多个长连接),每个连接只能最多跑1000次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。

大量的TIME_WAIT

如果用netstat命令看客户端机器,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。

 

2. 保持和server的长连接

2.1. location设置

为了让nginx和server(upstream块中的servers)之间保持长连接,典型设置如下:

http {upstream  BACKEND {server   192.168.0.18080  weight=1 max_fails=2 fail_timeout=30s;server   192.168.0.28080  weight=1 max_fails=2 fail_timeout=30s;keepalive 300;        // 这个很重要!}server {listen 8080 default_server;server_name "";location /  {proxy_pass http://BACKEND;proxy_set_header Host  $Host;proxy_set_header x-forwarded-for $remote_addr;proxy_set_header X-Real-IP $remote_addr;add_header Cache-Control no-store;add_header Pragma  no-cache;proxy_http_version 1.1;                    // 这两个最好也设置proxy_set_header Connection "";client_max_body_size  3072k;client_body_buffer_size 128k;}}
}

location中的两个参数:

  proxy_http_version 1.1;                   proxy_set_header Connection "";
  1. HTTP协议中对长连接的支持是从1.1版本之后才有的,因此最好通proxy_http_version指令设置为"1.1";
  2. 代表来自client的请求Connection header会被清理。清理 Connection 头可以确保代理层完全控制连接的生命周期。

 

* 场景分析

假设client和nginx之间是短连接,nginx和upstream之间可以开启长连接。这种情况下必须清理来自client请求中的Connection header,如果不清理,则会将client的header传递过来导致不能开启长连接。

 

2.2. upstream设置

upstream设置中,有个参数要特别的小心,就是这个keepalive。

nginx keepalive语法:

Syntax:   keepalive connections;
Default:  —
Context:  upstream

keepalive参数作用

connections参数设置每个worker进程与upstream server建立的最多空闲 的keepalive连接数量。当这个数量被突破时,最近使用最少的连接将被关闭。

特别提醒:keepalive指令不会限制一个nginx worker进程到upstream服务器连接的总数量。connections参数应该设置为一个足够小的数字来让upstream服务器来处理新进来的连接。

 

* 场景分析

场景描述

有一个HTTP服务,作为upstream server接收请求,响应时间为100毫秒(一秒能处理10个请求)。如果要达到10000 QPS的性能,就需要在nginx和upstream服务器之间建立大约1000条HTTP连接。
nginx为此建立连接池,然后请求过来时为每个请求分配一个连接,请求结束时回收连接放入连接池中,连接的状态也就更改为idle。

我们再假设这个upstream服务器的keepalive参数设置比较小,比如常见的10.
 

场景1

假设请求和响应是均匀而平稳的,那么这1000条连接应该都是一放回连接池就立即被后续请求申请使用,线程池中的idle线程会非常的少,趋进于零。
我们以100毫秒为一个单位,来看连接的情况:

  • 每100毫秒有100个新请求,需要100个连接;根据前面假设可以知道每100毫秒有100个请求结束,可以释放100个连接
  • 如果请求和应答都均匀,则100毫秒内释放的连接刚好够用,不需要新建连接,连接池也不空闲。
场景2

回到现实世界,请求通常不是足够的均匀和平稳,为了简化问题,我们假设应答始终都是平稳的,只是请求不平稳:

  1. 假设此时100毫秒内只有50个请求。此时连接池内有50个空闲连接。注意看keepalive=10的设置,这意味着连接池中最多容许保留有10个空闲连接。因此nginx不得不将这50个空闲连接中的40个关闭,只留下10个。
  2. 再下一个100个毫秒,有150个请求进来,有100个请求结束任务释放连接。150 - 100 = 50,空缺了50个连接,减掉前面连接池保留的10个空闲连接,nginx不得不新建40个新连接来满足要求。
    我们可以看到,在短短的200毫秒内,仅仅因为请求不够均匀,就导致nginx在前100毫秒判断空闲连接过多关闭了40个连接,而后10毫秒又不得不新建40个连接来弥补连接的不足。
场景3

假设请求是均匀的,而应答不再均匀,前100毫秒只有50个请求结束,后100毫秒有150个:

  1. 前100毫秒,进来100个请求,只结束了50个请求,导致此时连接不够下次请求用,nginx为此新建50个连接,此时有150个连接;
  2. 后100毫秒,进来100个请求,结束150个请求,导致空闲连接过多,ngixn为此关闭了150-10=140个空闲连接。

 

小结

现实世界中请求往往不均匀,服务器处理请求的时间也不平稳,当qps很高时,就会在短时间内导致两种非常矛盾现象: 1. 连接不够用,造成新建连接;2. 连接空闲,造成关闭连接。从而使得总连接数出现反复震荡,不断的创建新连接和关闭连接,使得长连接的效果被大大削弱。

keepalive参数设置方法:比如前面10000 QPS和100毫秒响应时间就可以推算出需要的长连接数量大概是1000. 然后将keepalive设置为这个长连接数量的10%到30%。

 

参考:
https://www.jianshu.com/p/142b35998947

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

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

相关文章

typescript 的基本用法说明

声明数组的两种方式 let x1: number[]; x1 [1, 2, 3]; // 方式1 let x2: Array<number> [1, 2, 3]; // 泛型 元组的含义 let x3: [string, number]; // 确定数量和类型 x3 [12, 10]; 枚举 enum Color { // 默认从0开始编码 &#xff0c;或者从第一个数字开始递增…

PVE报错处理:kvm [2205]: vcpu0 ignored RDMSR: 0x1b8

PVE使用过程中如果遇到&#xff1a;kvm [2205]: vcpu0 ignored RDMSR: 0x1b8 报错信息处理方法 vim /etc/modprobe.d/kvm.conf "options kvm ignore_msrsY"&#xff0c;这里在msrsY后面加一个空格&#xff0c;然后粘贴report_ignored_msrsN&#xff0c;使其变成 op…

【pytorch进阶】| 各类张量形状变化函数总结对比分析,view,reshape,pernute,transpose,squeeze,unsqueeze

文章目录 1 view&#xff08;&#xff09;函数1.1 基本用法 2 view_as&#xff08;&#xff09;函数3 reshape&#xff08;&#xff09;函数4 permute&#xff08;&#xff09;函数5 transpose&#xff08;&#xff09; 函数6 squeeze&#xff08;&#xff09;函数 和 unsqueez…

为什么建议不要买入耳式的耳机?有没有不伤听力的蓝牙耳机

为什么建议不要买入耳式的耳机&#xff1f;因为长时间佩戴入耳式耳机可能会导致耳朵不适甚至疼痛&#xff0c;且存在听力损伤、耳膜损伤的风险&#xff0c;还可能诱发耳道发炎。那么有没有不伤听力的蓝牙耳机呢&#xff1f;当然是有的&#xff0c;我建议尝试一下骨传导蓝牙耳机…

简单实践 java spring cloud 负载均衡

1 概要 1.1 实现一个最简单的微服务。远程调用负载均衡&#xff0c;基本上完成了最核心的微服务框架。 远程调用&#xff1a;RestTemplate 注册中心&#xff1a;eureka 负载均衡&#xff1a;Ribbon 1.2 要点 1.2.1 依赖 1.2.1.1 主框架依赖 spring boot 依赖 <depe…

HarmonyOS鸿蒙 虚拟像素 图片显示

Android中&#xff0c;有的sp&#xff0c;dp&#xff0c;dpi&#xff0c;px等概念。 dpi&#xff0c;dots per inch&#xff0c;代表屏幕像素密度。是指屏幕上每英寸&#xff08;1英寸 2.54 厘米&#xff09;距离中有多少个像素点。 dp&#xff0c;device independent pixels&…

Camille-接口测试

* 接口&#xff1a;不同的系统之间相互连接的部分&#xff0c;是一个传递数据的通道 * 接口测试&#xff1a;检查数据的交换、传递和控制管理过程 网络模型&#xff1a; OSI七层模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 TCP/IP四层模型 应用层 传输层 网络…

GPT-4 Vision根据应用程序截图生成博客和Readme 升级Streamlit八

GPT-4 Vision 系列: 翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式一翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式二翻译: GPT-4 Vision静态图表转换为动态数据可视化 升级Streamlit 三翻译: GPT-4 Vision从图像转换为完全可编辑的表格 升级St…

虚拟机(VMware)ubuntu16.04 直接连接网口设备 USRP 吊舱

编辑虚拟网络编辑器 点击之后 选择网卡之后&#xff0c;点击确定。 电脑配置 使用了&#xff1a;192.168.2.56 虚拟机内部配置 和PC的配置一致

leetcode刷题(剑指offer) 101.对称二叉树

101.对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; …

Elasticsearch性能调优

背景 项目上是用 ES 做数据库&#xff0c;存储的告警数据&#xff0c;量级在千万级别左右。测试在压测之后&#xff0c;系统频繁出现告警记录查询报错&#xff0c;系统不可用。基于此排查分析项目上 Elasticsearch 的使用是否合理。 版本及硬件 环境&#xff1a;10.xx.xxx.x…

vue前端html导出pdf

package.json中添加依赖 调用方&#xff1a; import htmlToPdf from ../../../utils/file/htmlToPdf.js// 下载方法&#xff0c;pdfDownloadDpi为onClickDownLoad() {htmlToPdf.getPdf(标题1, jsfgyzcpgxmShow, this.pdfDownloadDpi)}htmlToPdf.js // 页面导出为pdf格式 imp…

漏洞01-目录遍历漏洞/敏感信息泄露/URL重定向

目录遍历漏洞/敏感信息泄露/URL重定向 文章目录 目录遍历敏感信息泄露URL重定向 目录遍历 敏感信息泄露 于后台人员的疏忽或者不当的设计&#xff0c;导致不应该被前端用户看到的数据被轻易的访问到。 比如&#xff1a; ---通过访问url下的目录&#xff0c;可以直接列出目录下…

秋招面试—JS篇

2024 JavaScript面试题 1.new 操作符的工作原理 ①.创建一个新的空对象 ②.将这个对象的原型设置为函数的 prototype 对象 ③.让函数的this指向该对象&#xff0c;为函数添加属性和方法 ④.最后返回这个对象 2.什么是DOM&#xff0c;什么是BOM? DOM&#xff1a;文档对象…

代码随想录算法训练营第二十二天|235 二叉搜索树的最近公共祖先、701 二叉搜索树中的插入操作、450 删除二叉搜索树中的节点

235 二叉搜索树的最近公共祖先 题目链接&#xff1a;二叉搜索树的最近公共祖先 思路 因为二叉搜索树是有序的&#xff0c;因此p和q的最近公共祖先一定在两者之间&#xff0c;所以每到一个节点&#xff0c;该节点的数值如果大于p和q&#xff0c;则朝左子树走&#xff1b;如果…

C/C++ - 函数模板

目录 函数模板基础 函数模板定义 函数模板实例 函数模板调用 函数模板本质 模板函数特化 模板参数限定 默认模板参数 多个模板参数 非类型模板参数 函数模板拓展 模板参数匹配规则 函数模板基础 函数模板定义 使用 template <typename T>​​​​​ 或 templ…

ElementUI Form:Input 输入框

ElementUI安装与使用指南 Input 输入框 点击下载learnelementuispringboot项目源码 效果图 el-input.vue &#xff08;Input 输入框&#xff09;页面效果图 项目里el-input.vue代码 <script> export default {name: el_input,data() {return {input: ,input1: ,i…

SOME/IP SD 协议介绍(五)使用SOME/IP-SD宣布非SOME/IP协议的协议。

使用SOME/IP-SD宣布非SOME/IP协议的协议。 除了SOME/IP之外&#xff0c;车辆内部还使用其他通信协议&#xff0c;例如用于网络管理、诊断或闪存更新。这些通信协议可能需要传递服务实例或具有事件组。 对于非SOME/IP协议&#xff0c;应使用特殊的服务ID&#xff0c;并使用配置…

养猫家庭必备宠物空气净化器吗?性价比猫用空气净化器牌子推荐

家里的可爱猫咪们带来了很多快乐&#xff0c;但是它们的毛发却无处不在&#xff0c;飞舞在整个房间里。而且如果猫砂盆不及时清理&#xff0c;整个屋子都会弥漫着难闻的气味。每天都要清理工作&#xff0c;但是有时候我们也没有那么多精力。虽然享受着猫咪们带来的快乐&#xf…

C# wpf 字体图标预览,html字符与unicode转换

在进行wpf 开发工作过程中遇到字体图标无法预览的问题&#xff0c;特此记录。 1、把需要预览的字体文件上传到网站上进行转换 Create Your Own font-face Kits Font Squirrel2、下载文件后进行解压。 3、找到 Glyph Chart 查看字体html字符编码4、在wpf中直接使用即可 <…