ios http长连接_Nginx篇05——http长连接和keeplive


nginx中http模块使用http长连接的相关配置(主要是keepalive指令)和http长连接的原理解释。

1、http长连接

1.1 预备知识

连接管理是一个 HTTP 的关键话题:打开和保持连接在很大程度上影响着网站和 Web 应用程序的性能。在 HTTP/1.x 里有多种模型:短连接, 长连接, 和 HTTP 流水线。在解释这三种模型之前,我们需要先明确一些前提知识:

•HTTP是属于应用层(七层)的协议,同时它的传输层(四层)使用的是TCP协议,那么也就是说,HTTP的长连接和短连接,其本质就是TCP的长连接和短连接;•HTTP是一个无状态的面向连接的协议(使用TCP,面向连接、可靠传输),指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接);•TCP建立连接和断开连接是需要三握四挥的,由于这个属于计算机网络基本知识,所以原理这里不再赘述;

接下来我们开始解释。

1.2 HTTP短连接模型

在早期,HTTP 使用一个简单的模型来处理这样的连接。这些连接的生命周期是短暂的:每发起一个请求时都会创建一个新的连接,并在收到应答时立即关闭。这就是类似上面说的三次握手,在互联网发展的早期一个网页的资源并没有现在这么多,很多可能只是一个简单的静态页面而已,所以这样的模型显然很OK。客户端获取完所需资源之后,就断开连接,不再占用服务器的资源。

套用TCP连接的三握四挥的模型来举例:

三次握手:

A→B:今晚下班一起吃饭吗?

B→A:好的,今晚下班一起吃饭。

A→B:好的,我知道你答应我今晚下班一起吃饭的邀请了。


然后开始去吃饭,吃完饭到了两个人需要各自回家的时候:


四次挥手:

A→B:我吃完饭准备走了

B→A:等一下,我快吃完了

B→A:好了,我吃完了可以走了

A→B:好的,我知道你吃完了我们可以走了


然后两人吃完饭就各回各家了

HTTP 短连接模型是最早期的模型,也是 HTTP/1.0 的默认模型。每一个 HTTP 请求都由它自己独立的连接完成;这意味着发起每一个 HTTP 请求之前都会有一次 TCP 握手,而且是连续不断的。实际上,TCP 协议握手本身就是耗费时间的,所以 TCP 可以保持更多的热连接来适应负载。短连接破坏了 TCP 具备的能力,新的冷连接降低了其性能。

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

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

1.3 HTTP长连接模型

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

在 HTTP/1.1 之前,长连接也被称为keep-alive 连接。

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

套用上面的例子来进一步解释:

三次握手:

A→B:今晚下班一起吃饭吗?

B→A:好的,今晚下班一起吃饭。

A→B:好的,我知道你答应我今晚下班一起吃饭的邀请了。


然后开始去吃饭,但是这时吃完饭就不是马上四次挥手断开连接,AB两人还顺便去逛街、看电影(相当于省去了三次握手使用已建立的连接来传输多个资源)


此处省略四次挥手


最后两人就各回各家了

长连接也还是有缺点的;也就是前面提到的资源占用问题,就算是在空闲状态,它还是会消耗服务器资源,也更容易被DDoS攻击。本质上长连接是因为不断地三次握手建立连接消耗的资源要大于维持连接所需要的资源才使用的,如果服务器处于高负载时段或者被DDoS,可以使用非长连接,即尽快关闭那些空闲的连接,也能对性能有所提升。

1.4 HTTP流水线模型

流水线模型的实现要复杂很多,而已效果也并不是特别好,主要还要考虑到各种兼容性,所以默认是不启用这个流水线模型的,而在HTTP/2中,流水线已经被更好的算法给代替,如multiplexing

默认情况下,HTTP 请求是按顺序发出的。下一个请求只有在当前请求收到应答过后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。流水线是在同一条长连接上发出连续的请求,而不用等待应答返回。这样可以避免连接延迟。理论上讲,性能还会因为两个 HTTP 请求有可能被打包到一个 TCP 消息包中而得到提升。就算 HTTP 请求不断的继续,尺寸会增加,但设置 TCP 的 MSS(Maximum Segment Size) 选项,仍然足够包含一系列简单的请求。

并不是所有类型的 HTTP 请求都能用到流水线:只有 idempotent方式,比如 GETHEADPUT和 DELETE能够被安全的重试:因为有故障发生时,流水线的内容要能被轻易的重试,即出现了问题重试的成本要尽可能低,否则还不如使用长连接模型。

正确的实现流水线是复杂的:传输中的资源大小,多少有效的 RTT 会被用到,还有有效带宽,流水线带来的改善有多大的影响范围。不知道这些的话,重要的消息可能被延迟到不重要的消息后面。这个重要性的概念甚至会演变为影响到页面布局!因此 HTTP 流水线在大多数情况下带来的改善并不明显。此外,流水线受制于 HOL 问题。

摘自wiki

队头阻塞(Head-of-line blocking或缩写为HOL blocking)在计算机网络[1]的范畴中是一种性能受限的现象。它的原因是一列的第一个数据包(队头)受阻而导致整列数据包受阻。例如它有可能在缓存式输入的交换机中出现,有可能因为传输顺序错乱而出现,亦有可能在HTTP流水线中有多个请求的情况下出现。

我们还是使用上面的例子来进行解释,这次的握手请求就变了,A一次向B发出了三个请求:

三次握手:

A→B:今晚下班一起吃饭、逛街、看电影吗?

B→A:好的,今晚下班一起吃饭、逛街、看电影。

A→B:好的,我知道你答应我今晚下班一起吃饭、逛街、看电影的邀请了。


实际上这样子是有很大的风险的

如果是按照长连接模型,A可以根据B在吃饭的时候的反应来决定要不要继续去逛街看电影,也就是如果传输完了一次数据之后还保持连接就继续传输,万一连接突然断开或者是不稳定,那可能就要重新建立连接。(万一B在吃饭的时候吃的不开心不想继续逛街看电影那就等下次再吃饭逛街看电影)

但是如果按照流水线模型,A一次发送三个请求,虽然发送请求的时候省事儿了(三次握手的时候TCP打包传输请求更省事),但是谁也不知道吃饭逛街看电影的过程中会发生什么意外,时间越长越不稳定,而且还容易出现万一B想减肥不想吃饭,只想逛街看电影的情况呢?(HOL问题)

最后这里补充一张图片来对比三种模型之间的差别:

5ab0e1b5802712a34422dbfb8ed10d0f.png

2、Nginx中的keepalive指令

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

了解了上面的原理之后,Nginx中的keepalive指令我们就非常好理解了,相关的指令主要有三个,我们逐个进行解释:

2.1 keepalive

Syntax:    keepalive connections;
Default: —
Context: upstream
This directive appeared in version 1.1.4.

在upstream模块中配置,启用连接到upstream中的服务器的缓存,connections参数的主要作用是设定每个Nginx的单个worker进程(each worker process)对于upstream中的server的最大空闲连接数,当超过该数字的时候,会关闭使用得最少的连接。

对于HTTP,应将proxy_http_version指令设置为“ 1.1”,并且应清除Connection标题字段

对于FastCGI服务器,需要设置fastcgi_keep_conn以启用keepalive连接

upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}

server {
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}

lcaotion /FastCGI/ {
fastcgi_pass fastcgi_backend;
fastcgi_keep_conn on;
}
}

需要注意的是,keepalive指令并不会限制Nginx的所有worker进程能开启的连接到upstream服务器中的连接总数(total number)。也就是如果设得太大了,会导致过多的空闲连接占满了upstream中的server资源,导致新的连接无法建立,因此这个数值的设定需要根据worker进程数量来调整。

2.2 keepalive_requests

Syntax:    keepalive_requests number;
Default: keepalive_requests 100;
Context: upstream
This directive appeared in version 1.15.3.

keepalive_requests设定可以通过一个连接(connection)发送的请求(request)数量,超过最大请求数量之后,该连接会被关闭。为了释放每个连接的内存分配,定期关闭连接是很有必要的。因此,不建议将keepalive_requests设定过大,否则可能会导致过高的内存占用。

2.3 keepalive_timeout

Syntax:    keepalive_timeout timeout;
Default: keepalive_timeout 60s;
Context: upstream
This directive appeared in version 1.15.3.

设定连接超时时间,在此设定的时间内,client与upstream中的server的空闲keepalive连接将保持打开状态(open)。此外,虽然官方文档说的默认值是60s,但是1.17.9版本的Nginx在安装之后配置文件nginx.conf上面设定的是65s。

References

[1] 计算机网络: https://zh.wikipedia.org/wiki/计算机网络

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

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

相关文章

php 目录555 权限_CMS网站安全权限划分设置教程

DiYunCMS(帝云CMS)-免费开源可商用的PHP万能建站程序CMS网站安全权限划分设置教程网站安全是网站搭建运营过程中非常重要的一部分,DiYunCMS非常注重安全,开发了强大的安全功能。本文给大家介绍下DiYunCMS网站的安全设置方法。首先需要安装【系统安全】插…

python 列表生成式

python笔记21-列表生成式 前言 python里面[]表示一个列表,快速生成一个列表可以用range()函数来生成。 对列表里面的数据进行运算和操作,生成新的列表最高效快速的办法,那就是列表生成式了。 range() 1.一个连续的数字类型列表&#xff0…

php mysql grant_mysql grant命令详解_MySQL

bitsCN.comgrant 权限 on 数据库对象 to 用户一、grant 普通数据用户,查询、插入、更新、删除 数据库中所有表数据的权利。grant select on testdb.* to common_user%grant insert on testdb.* to common_user%grant update on testdb.* to common_user%grant delet…

python matplotlib简单使用

一、简单介绍 Matplotlib是Python的一个绘图库,是Python中最常用的可视化工具之一。 二、安装方法 安装方法:pip install matplotlib 注意:安装matplotlib前需要先安装numpy才可以 三、基本绘图命令 1、plt.fig([num]) 在绘图过程中&a…

python窗体设计插件_Python 界面生成器 wxFormBuilder 的入门使用(wxPython的界面设计工具的初学笔记)...

环境,Win10,python3.7.3,wxPython 4.0.4,wxFormBuilder 3.91、准备一个窗体。点击wxformbuilder上方的标签“forms”,并点击标签下方的第一个类似窗体的图标“Frame”然后,下面就会出现一个窗体。但是现在还…

用cmd编译c++程序

1、设置好环境变量(已安装vs) ①在计算机的系统环境变量--》用户变量--》path中添加 D:\VS15\VC\bin ②新建变量INCLUDE:D:\VS15\VC\include ③新建变量LIB:D:\VS15\VC\lib 2、利用cl编译c文件 打开cmd 输入c…

python插入排序_直接插入排序(python实现)

这篇博文用来介绍直接插入排序直接插入排序基本思想:每次将一个待排序的记录插入到已经排好序的数据区中,直到全部插入完为止直接插入排序算法思路:在直接插入排序中,数据元素分为了有序区和无序区两个部分,在这里我们…

STL1-函数模板

1、函数模板和普通函数区别 //普通函数可以进行自动类型转换&#xff0c; //函数模板必须精确类型匹配; //函数模板可以被重载;c优先考虑普通函数;#include<iostream> using namespace std; //函数模板-->产生模板函数-->调用函数 template<class T> T MyAd…

jupyter安装与迁移文件

1、安装 pip install jupyter notebook -i https://pypi.tuna.tsinghua.edu.cn/simple 2、测试安装成功 安装完后输入 jupyter notebook 出现一个jupyter网址&#xff0c;即证明安装成功 3、数据迁移 将之前的jupyter notebook产生的文件复制在python所安装的盘目录下。然…

修正的判定条件覆盖例题_语句覆盖、判断覆盖、条件覆盖、条件判定组合覆盖、多条件覆盖、修正条件覆盖...

int function(bool a,bool b,boolc){intx;x0;if(a&&(b||c)){x1;returnx;}}1、语句覆盖(SC)选择足够多的测试数据&#xff0c;使得被测程序中的每条语句至少执行一次。测试用例&#xff1a;aT,bT,cT2、判断覆盖(DC)设计足够的测试用例&#xff0c;使得程序中的每个判定至…

STL2-类模板

1、类模板实现 函数模板在调用时可以自动类型推导 类模板必须显式指定类型 #include<iostream> using namespace std;template<class T> class Person { public:T mId;T mAge; public:Person(T id,T age){this->mAge age;this->mId id;}void Show(){cout…

STL3-MyArray动态数组类模板实现

注意 1、右值的拷贝使用 2、拷贝构造函数的使用 #include<iostream> using namespace std;template<class T> class MyArray{ public:MyArray(int capacity){this->mCapacity capacity;this->mSize 0;//申请内存this->pAddr new T[this->mCapac…

mysql udf提权hex_Mysql_UDF提权

Mysql_UDF提权作者&#xff1a;admin 发布于&#xff1a;2013-5-25 18:55 Saturday分类&#xff1a;MYSQLRoot权限一、上传udf.dll小于mysql5.1版本C:\\WINDOWS\\udf.dll 或C:\\WINDOWS\\system32\\udf.dll等于mysql5.1版本%mysql%\\plugin\\udf.dll 用 selectplugin_dir 查询…

STL4-类型转换

#include<iostream> using namespace std;class Building{}; class Animal{}; class Cat :public Animal {}; //Cat是Animal的子类//static_cast //用于内置的数据类型及具有继承关系的指针或者引用 void test01() {int a 97;//static_cast<要转换的类型>(转换的…

python argparse模块

argparse模块 argparse是python用于解析命令行参数和选项的标准模块&#xff0c;用于代替已经过时的optparse模块 使用步骤 import argparse # 1 导入模块&#xff0c;这个没什么说的 parser argparse.ArgumentParser() # 2 实例化一个对象&#xff0c;默认参数一堆&#…

STL5-异常

异常可以跨函数 异常必须处理 1、 #include<iostream> using namespace std; //c异常机制 跨函数 //c异常必须处理 不能留&#xff0c;否则报错 int divided(int x, int y) {if (y 0)throw y; //抛异常return (x / y); } void test01() {int x 10, y 0;//试着去捕获…

java 并发组件_Java 并发计数组件Striped64详解

作者&#xff1a; 一字马胡转载标志 【2017-11-03】更新日志日期更新内容备注2017-11-03添加转载标志持续更新Java Striped64Striped64是在java8中添加用来支持累加器的并发组件&#xff0c;它可以在并发环境下使用来做某种计数&#xff0c;Striped64的设计思路是在竞争激烈的时…

ubuntu的MySQL远程数据库连接问题查找

1、开放端口3306 2、添加权限 3、服务器本身没有在安全组规则中开放权限 添加安全组规则后重试。

java中集合怎么定义_Java集合系列(一):集合的定义及分类

1. 集合的定义什么是集合呢&#xff1f;定义&#xff1a;集合是一个存放对象的引用的容器。在Java中&#xff0c;集合位于java.util包下。2. 集合和数组的区别(面试常问)提到容器&#xff0c;就会想起数组&#xff0c;那么集合和数组的区别是什么呢&#xff1f;(这里是重点&…

STL6-输入输出流

cout 是 console output 缩写 程序 和键盘 之间有一个输入缓冲区 程序 和 显示器 之间有一个输出缓冲区 #include<iostream> #include<windows.h> #include<iomanip> using namespace std; #if 0 cout << "dd"; //全局流对象&#xff0c;默…