精华推荐 | 深入浅出学习透析Nginx服务器的基本原理和配置指南「Keepalive性能优化实战篇」

news2025/1/26 15:33:27

在这里插入图片描述

  • Linux系统:Centos 7 x64
  • Nginx版本:1.11.5

Nginx 是一款面向性能设计的 HTTP 服务器,能反向代理 HTTP,HTTPS 和邮件相关(SMTP,POP3,IMAP)的协议链接。并且提供了负载均衡以及 HTTP 缓存。它的设计充分使用异步事件模型,削减上下文调度的开销,提高服务器并发能力。采用了模块化设计,提供了丰富模块的第三方模块。所以关于 Nginx,有这些标签:「异步」「事件」「模块化」「高性能」「高并发」「反向代理」「负载均衡」「长连接」。本章内容主要就是针对于长连接请求模块。

为什么要单独讲解keepalive指令?

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

大多数未仔细研读过nginx的同学通常都会误解这个参数,有些人理解为这里的keepalive是设置是否打开长连接,以为应该设置为on/off。有些人会被前面的keepalive_timeout误导,以为这里也是设置keepalive的timeout。

但是实际上这个keepalive参数的含义非常的奇特,请小心看nginx文档中的说明,因为Keepalive长连接非常重要而且容易理解错误,所以专门做连一期专门讲解keepalive的文章。

本文介绍如何使用Nginx进行配置和实现长连接Keepalive,并介绍如何设置 nginx 以提供静态内容服务,如何配置 nginx 作为代理服务器。

keepalive指令

在这里插入图片描述

支持keepalive长连接,当使用nginx作为反向代理时,为了支持长连接,需要做到两点:

  • 从client到nginx的连接是长连接
  • 从nginx到server的连接是长连接

从HTTP协议的角度看,Nginx在这个过程中,对于客户端它扮演着HTTP服务器端的角色。而对于真正的服务器端(在nginx的术语中称为upstream)Nginx又扮演着HTTP客户端的角色,keepalive指令出现在版本1.1.4。

keepalive指令格式

  • keepalive不是on/off之类的开关
  • keepalive不是timeout,不是用来设置超时值
Syntax:    keepalive connections;
Default:    —
Context:    upstream
Activates the cache for connections to upstream servers.

connections的取值代表着连接到upstream服务器的持续连接(即长连接)的数量。很多人都会有一个误解:认为这个参数是设置到upstream服务器的长连接的数量,分歧在于是最大连接数还是最小连接数

官方文档的介绍

The connections parameter sets the maximum number of idle keepalive connections to upstream servers

  • connections参数设置到upstream服务器的空闲keepalive连接的最大数量,这个”idle”的概念,何为idle。大多数人之所以误解为是到upstream服务器的最大长连接数,一般都是因为看到了文档中的这句话,而漏看了这个”idle”一词。

When this number is exceeded, the least recently used connections are closed.

  • 当这个数量被突破时,最近使用最少的连接将被关闭。

Nginx的官方文档给出了指示,否定了最大连接数的可能:keepalive指令不会限制一个nginx worker进程到upstream服务器连接的总数量请注意空闲keepalive连接的最大数量中空闲这个关键字

keepalive实际场景分析

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

  • 之后假设这个upstream服务器的keepalive参数设置比较小,比如常见的10.

  • 再次假设请求和响应是均匀而平稳的,那么这1000条连接应该都是一放回连接池就立即被后续请求申请使用,线程池中的idle线程会非常的少,趋进于零。我们以10毫秒为一个单位,来看连接的情况(注意场景是1000个线程+100毫秒响应时间,每秒有10000个请求完成):

    • 每10毫秒有100个新请求,需要100个连接
    • 每10毫秒有100个请求结束,可以释放100个连接
    • 如果请求和应答都均匀,则10毫秒内释放的连接刚好够用,不需要新建连接,连接池空闲连接为零
  • 如果请求通常不是足够的均匀和平稳,为了简化问题,我们假设应答始终都是平稳的,只是请求不平稳,第一个10毫秒只有50,第二个10毫秒有150:

    • 下一个10毫秒,有100个连接结束请求回收连接到连接池,但是假设此时请求不均匀10毫秒内没有预计的100个请求进来,而是只有50个请求。注意此时连接池回收了100个连接又分配出去50个连接,因此连接池内有50个空闲连接。

    • 最后注意看keepalive=10的设置,这意味着连接池中最多容许保留有10个空闲连接。因此nginx不得不将这50个空闲连接中的40个关闭,只留下10个

  • 再下一个10个毫秒,有150个请求进来,有100个请求结束任务释放连接。150 - 100 = 50,空缺了50个连接,减掉前面连接池保留的10个空闲连接,nginx不得不新建40个新连接来满足要求

    • 可以看到,在短短的20毫秒内,仅仅因为请求不够均匀,就导致nginx在前10毫秒判断空闲连接过多关闭了40个连接,而后10毫秒又不得不新建40个连接来弥补连接的不足。

    • 再来一次类似的场景,假设请求是均匀的,而应答不再均匀,前10毫秒只有50个请求结束,后10毫秒有150个:

  • 前10毫秒,进来100个请求,结束50个请求,导致连接不够用,nginx为此新建50个连接

  • 后10毫秒,进来100个请求,结束150个请求,导致空闲连接过多,ngixn为此关闭了150-100-10=40个空闲连接

    • 第二个应答不均匀的场景实际上是对应第一个请求不均匀的场景:正是因为请求不均匀,所以导致100毫秒之后这些请求的应答必然不均匀

现实世界中的请求往往和理想状态有巨大差异,请求不均匀,服务器处理请求的时间也不平稳,这理论上的大概1000个连接在反复的回收和再分配的过程中,必然出现两种非常矛盾场景在短时间内反复:

  1. 连接不够用,造成新建连接
  2. 连接空闲,造成关闭连接。从而使得总连接数出现反复震荡,不断的创建新连接和关闭连接,使得长连接的效果被大大削弱。

Keepalive参数建议

造成连接数量反复震荡的一个推手,就是这个keepalive 这个最大空闲连接数。毕竟连接池中的1000个连接在频繁利用时,出现短时间内多余10个空闲连接的概率实在太高。因此为了避免出现上面的连接震荡,必须考虑加大这个参数,比如上面的场景如果将keepalive设置为100或者200,就可以非常有效的缓冲请求和应答不均匀

keepalive参数分析

  • 对应的参数设置为每个worker子进程在缓冲中保持的到upstream服务器的空闲keepalive连接的最大数量。当超过这个数量值的时候,会将最近最少使用(LRU)的连接进行关闭。需要考虑的是keepalive指令不会限制一个worker进程到upstream服务器连接的总数量。其参数应该设置为一个足够小的数字来让upstream服务器来处理新进来的连接。
  • 如果想让upstream每次都处理新的进来的连接,就应该将这个值放的足够小。反过来理解,就是如果不想让upstream服务器处理新连接,就应该放大一些?

Keepalive的使用案例

Keepalive对接memcached服务

使用keepalive连接的memcached upstream配置的例子:

upstream memcached_backend {
    server 127.0.0.1:11211;
    server 10.0.0.2:11211;
    keepalive 32;
}
server {
    ...
    location /memcached/ {
        set $memcached_key $uri;
        memcached_pass memcached_backend;
    }
}
Keepalive对接Http1.1的Web服务

对于HTTP,proxy_http_version指定应该设置为”1.1”,而”Connection” header应该被清理:

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 "";
        ...
    }
}
Keepalive对接Http1.0的Web服务

HTTP/1.0 持久连接可以通过传递”Connection: Keep-Alive” header 到upstream server, 但是不推荐使用这种方法。

Keepalive对接FastCGI的Web服务

对于FastCGI服务器,要求设置fastcgi_keep_conn来让长连接工作:

upstream fastcgi_backend {
    server 127.0.0.1:9000;
    keepalive 8;
}
server {
    ...
    location /fastcgi/ {
        fastcgi_pass fastcgi_backend;
        fastcgi_keep_conn on;
        ...
    }
}

当使用默认的round-robin之外的负载均衡算法时,必须在keepalive指令之前激活他们。SCGI 和 uwsgi 协议没有keepalive连接的概念。

保持和client的长连接

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

  • client发送的HTTP请求要求keep alive
  • nginx设置上支持keep alive

HTTP配置

默认情况下,Nginx已经自动开启了对client连接的keep alive支持。一般场景可以直接使用,但是对于一些比较特殊的场景,还是有必要调整个别参数。需要修改nginx的配置文件(在nginx安装目录下的conf/nginx.conf):

http {
    keepalive_timeout  120s 120s;
    keepalive_requests 10000;
}

keepalive_timeout指令

keepalive_timeout指令的语法:

Syntax:    keepalive_timeout timeout [header_timeout];
Default:    keepalive_timeout 75s;
Context:    http, server, location
  1. 第一个参数设置keep-alive客户端连接在服务器端保持开启的超时值。值为0会禁用keep-alive客户端连接。
  2. 可选的第二个参数在响应的header域中设置一个值“Keep-Alive: timeout=time”。这两个参数可以不一样。

注:默认75s一般情况下也够用,对于一些请求比较大的内部服务器通讯的场景,适当加大为120s或者300s。第二个参数通常可以不用设置

keepalive_requests指令

keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量。当最大请求数量达到时,连接被关闭。默认是100。

keepalive_requests指令的实现原理
  • 指一个keepalive请求建立之后,Nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则Nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。

这个参数往往被大多数人忽略,因为大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,默认的100就显得太低

  • 简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭

  • 为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,如果用netstat命令看客户端机器,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。

因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT

保持和server的长连接

为了让Nginx和server(Nginx称为upstream)之间保持长连接,典型设置如下:

http {
    upstream  BACKEND {
        server   192.168.0.1:8080  weight=1 max_fails=2 fail_timeout=30s;
        server   192.168.0.2:8080  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;
        }
    }
}

总结

  • keepalive 这个参数一定要小心设置,尤其对于QPS比较高的场景,推荐先做一下估算,根据QPS和平均响应时间大体能计算出需要的长连接的数量。比如前面10000 QPS和100毫秒响应时间就可以推算出需要的长连接数量大概是1000. 然后将keepalive设置为这个长连接数量的10%到30%。

  • 如果不喜欢计算的同学也可以直接设置为keepalive=1000之类的,一般都OK的了。

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

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

相关文章

拼搏一周!刷了1000道Java高频面试题喜提阿里offer,定级P7

今年较往年相比面试要难的多,大环境也是对于程序员的要求越来越高,环境是我们无法改变的,我们能改变的只有自己,月初我一好友,努力拼搏一周,刷完了这份阿里P8大牛整理的这1000道Java高频面试题笔记&#xf…

GitHub配置SSH Keys步骤

Git配置SSH Keys步骤 许多 Git 服务器都使用 SSH 公钥进行认证。 为了向 Git 服务器提供 SSH 公钥,如果某系统用户尚未拥有密钥,必须事先为其生成一份。 生成步骤如下: 1. 设置用户名和邮箱 在git命令行中对git进行全局设置 git config --…

八、CANdelaStudio入门-Session

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的Session概念,欢迎各位朋友订阅、评论,…

微信小程序:用户基本信息的采集

写作背景 在开发商城小程序时需要显示用户头像、昵称、手机号等信息以便后续业务的实现,因此需要通过微信小程序的API采集用户数据,由此进行总结。 在微信小程序中获取用户信息可以通过这几种方式获取,getUserInfo、getUserProfile、open-da…

基于多目标遗传算法的IEEE14节点系统分布式电源选址定容matlab程序

基于多目标遗传算法的IEEE14节点系统分布式电源选址定容matlab程序 摘 要: 为更好地解决分布式电源选址定容问题,提出一种改进的多目标遗传算法。之后,考虑投资成本、网损以及电压稳定性三因素建立了一个三目标的数学模型,并采用上述多目标遗…

javaSE -运算符,注释,关键字(复习)

一、运算符 1.1、算术运算符 基本四则运算符 - * / %规则比较简单, 值得注意的是除法和取模 1.1.1、/ 除法 int / int 结果还是 int, 需要使用 double 来计算 public static void main(String[] args) {int a 1;int b 2;System.out.println(a / b);}要得到小数那就要使…

python>>numpy包

章节内容 什么是NumPy模块和NumPy数组 创建数组 基本数据类型 数据可视化 索引和切片 副本和视图 目录 什么是NumPy模块和NumPy数组? 创建数组 基本数据类型 数据可视化 索引和切片 副本和视图 什么是NumPy模块和NumPy数组? NumPy数组 python对象 …

pyhon项目中,使用pip安装第三方插件之后,明明使用pip list可以查到,但是在项目中import时仍然找不到怎么办?

认识pip:python中的pip是用来安装python第三方库的工具,是安装python的时候自带的。 1.安装方式:pip install 第三方库名,比如:pip install selenium 2.查看已安装的所有第三方库:pip list 或 pip3 list &…

Spring Cloud OpenFeign - - - > 日志级别配置

项目源码地址:https://download.csdn.net/download/weixin_42950079/87168704 OpenFeign 有 4 种日志级别: NONE: 不记录任何日志,是OpenFeign默认日志级别(性能最佳,适用于生产环境)。BASIC: 仅记录请求方…

五魔方、二阶五魔方

五魔方 五魔方是正十二面体魔方,其实和三阶魔方很像,用层先法就能复原,而且公式一模一样。 十二个面分为6个浅色面和6个深色面,所以浅色和深色各有一个中心面。 先复原浅色中心面这一层: 再复原浅色面的5个棱块&…

【GlobalMapper精品教程】030:栅格重采样案例教程(航测DSM)

本文讲解Globalmapper栅格重采样操作方法。数据为配套实验数据包中的data030.rar,航测内业生成的DSM,分辨率为0.04米,现在需要将其重采样为0.05米。 文章目录 一、重采样简介二、重采样操作一、重采样简介 栅格/影像数据进行配准或纠正、投影等几何变换后,像元中心位置通常…

超级记忆节目

一 问题描述 杰克逊被邀请参加电视节目“超强记忆”,参与者会玩一个记忆游戏。主持人先告诉参与者一个数字序列 {A1 , A2 , …, An },然后对该序列执行一系列操作或查询: ① ADD x y D ,表示对子序列 {Ax , …, Ay } 的每个数字…

Qt | Qt For Android、Qt5.14.2安卓开发环境搭建详细步骤

Qt | Qt For Android、Qt5.14.2安卓开发环境搭建详细步骤 目录Qt | Qt For Android、Qt5.14.2安卓开发环境搭建详细步骤1、简介2、软件下载1、Java SDK2、Android SDK3、Android NDK3、软件部署4、测试1、简介 搭建Qt For Android开发环境需要安装的软件有: JAVA …

第十四届蓝桥杯模拟赛(第二期)

写在前面 包含本次模拟赛的10道题题解能过样例,应该可以AC若有错误,欢迎评论区指出有疑问可私信我哈🫰🏻从2023开始暴力枚举每一个数,直到找到正确答案 start 2022def check(num) :t str(bin(num))if t[-6:] 0000…

核函数简介

文章目录基本概念概念1概念2:Kernel Func总结内积矩阵(Gram/Kernel Matrix)一些思考什么是有限正半定常用的Kernel FunctionsLinear KernelPolynomial KernelRBF(Gaussian) Kernel基本概念 概念1 高维空间存在可分的情况。 我们可以找一个映射函数送过…

【C++】vector的模拟实现

​🌠 作者:阿亮joy. 🎆专栏:《吃透西嘎嘎》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉前言&…

程序员5分钟,带你看完24岁60W年薪架构师的简历,上面竟然写着精通JVM

前言 近期,看了一份24岁60W年薪架构师简历,上面写着他的求职意向所掌握的技能....... 所掌握的技能大部分写的都是精通!我不禁想问,大佬都这么强吗?你敢在简历上把所有的技能都写精通吗? 简历 下面来带…

matlab学习笔记(六)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 matlab学习笔记(六)一、信号基本运算的MATLAB实现二、计算两信号的卷积积分卷积积分三、两序列的卷积和一、信号基本运算的MATLAB实现 信号基本运算是…

pdf编辑软件哪个好?编辑pdf的软件分享一款,像word一样好用!

编辑文档时,很多人习惯用word及pdf进行办公,而使用中,经常会发现word和pdf之间,总是无法满足我们的切换需要。如果掌握一款可以编辑pdf的软件,像word一样简单使用,又能满足word的各种功能所需,那…

代理,反射,AOP

这篇文章主要讲三个点 1.设计模式中的代理模式 2.JAVA中的反射,因为用到了动态代理,这里举一下JDK代理和GCLIB代理的例子 3.介绍一下spring的aop是怎么用到了代理 1.设计模式中的代理模式 代理模式解决的问题: 在直接访问对象时带来的问题&am…