Nginx对客户端和server端长连接控制keepalive(转)



原文:https://blog.csdn.net/qq_34556414/article/details/106116889

作者:富士康质检员张全蛋

nginx长连接-keepalive

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

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

Nginx对客户端和server端长连接控制keepalive(转)

worker_connections

Syntax: worker_connections&#xA0;<code><em>number</em></code>;

Default:

worker_connections 512;

Context: events

Sets the maximum number of simultaneous connections that can be opened by a worker process.

It should be kept in mind that this number includes all connections (e.g. connections with proxied servers, among others), not only connections with clients. Another consideration is that the actual number of simultaneous connections cannot exceed the current limit on the maximum number of open files, which can be changed by worker_rlimit_nofile.

这个默认的512是非常小的,因为nginx处理都是以万来计算,所以我们是要去修改的。同时也写的很清楚,这个连接不仅仅用于客户端的连接还用于面向服务器的,所以做反向代理的时候每个客户端会消耗2个connection。当配置了更大的worker connection时候,也就意味着Nginx使用了更大的内存。同时每个worker connection都对应着读事件和写事件

Syntax: worker_rlimit_nofile&#xA0;<code><em>number</em></code>;

Default: — Context: main

Changes the limit on the maximum number of open files (RLIMIT_NOFILE) for worker processes. Used to increase the limit without restarting the main process.

保持和client的长连接

默认情况下,nginx已经自动开启了对client连接的keep alive支持(同时client发送的HTTP请求要求keep alive)。一般场景可以直接使用,但是对于一些比较特殊的场景,还是有必要调整个别参数(keepalive_timeout和keepalive_requests)。

http {
   keepalive_timeout  60s;
   keepalive_requests 10000;
}

1) keepalive_timeout:

语法:keepalive_timeout timeout [header_timeout];

第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接;

第二个参数:可选、在响应的header域中设置一个值”Keep-Alive: timeout=time”;通常可以不用设置;

注:keepalive_timeout默认75s,一般情况下也够用,对于一些请求比较大的内部服务器通讯的场景,适当加大为120s或者300s;

2)keepalive_requests:

keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。默认是100。这个参数的真实含义,是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。

大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,默认的100就显得太低。
简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。

保持和server的长连接

为了让nginx和后端server(nginx称为upstream)之间保持长连接,典型设置如下:(默认nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接)

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 "";
       }
   }
}

1)location中有两个参数需要设置:

http {
   server {
       location /  {
           proxy_http_version 1.1; // 这两个最好也设置
           proxy_set_header Connection "";
       }
   }
}

HTTP协议中对长连接的支持是从1.1版本之后才有的,因此最好通过proxy_http_version指令设置为”1.1″;
而”Connection” header应该被清理。清理的意思,我的理解,是清理从client过来的http header,因为即使是client和nginx之间是短连接,nginx和upstream之间也是可以开启长连接的。这种情况下必须清理来自client请求中的”Connection” header。

2)upstream中的keepalive设置:

此处keepalive的含义不是开启、关闭长连接的开关;也不是用来设置超时的timeout;更不是设置长连接池最大连接数。官方解释:

  1. The connections parameter sets the maximum number of idle keepalive connections to upstream servers connections(设置到upstream服务器的空闲keepalive连接的最大数量)

  2. When this number is exceeded, the least recently used connections are closed. (当这个数量被突破时,最近使用最少的连接将被关闭)

  3. It should be particularly noted that the keepalive directive does not limit the total number of connections to upstream servers that an nginx worker process can open.(特别提醒:keepalive指令不会限制一个nginx worker进程到upstream服务器连接的总数量)

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

A、假设请求和响应是均匀而平稳的,那么这1000条连接应该都是一放回连接池就立即被后续请求申请使用,线程池中的idle线程会非常的少,趋进于零,不会造成连接数量反复震荡。

B、显示中请求和响应不可能平稳,我们以10毫秒为一个单位,来看连接的情况(注意场景是1000个线程+100毫秒响应时间,每秒有10000个请求完成),我们假设应答始终都是平稳的,只是请求不平稳,第一个10毫秒只有50,第二个10毫秒有150:

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

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

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

C、同样,如果假设相应不均衡也会出现上面的连接数波动情况。

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

总结

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

综上,出现大量TIME_WAIT的情况
1)导致 nginx端出现大量TIME_WAIT的情况有两种:

  • keepalive_requests设置比较小,高并发下超过此值后nginx会强制关闭和客户端保持的keepalive长连接;(主动关闭连接后导致nginx出现TIME_WAIT)
  • keepalive设置的比较小(空闲数太小),导致高并发下nginx会频繁出现连接数震荡(超过该值会关闭连接),不停的关闭、开启和后端server保持的keepalive长连接;

2)导致后端server端出现大量TIME_WAIT的情况:
nginx没有打开和后端的长连接,即:没有设置proxy_http_version 1.1;和proxy_set_header Connection “”;从而导致后端server每次关闭连接,高并发下就会出现server端出现大量TIME_WAIT

Original: https://www.cnblogs.com/ajianbeyourself/p/15028192.html
Author: 奋斗终生
Title: Nginx对客户端和server端长连接控制keepalive(转)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/543622/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Java并发编程 | 从进程、线程到并发问题实例解决

    计划写几篇文章讲述下Java并发编程,帮助一些初学者成体系的理解并发编程并实际使用,而不只是碎片化的了解一些Synchronized、ReentrantLock等技术点。在讲述的过…

    Java 2023年6月15日
    019
  • Java 可变参数

    Java 可变参数 可变参数即:成员方法支持最少 0个或多个同类型的参数 在我们不确定形参的数量时就可以使用可变参数 可变参数的语法 class VarParameter { pu…

    Java 2023年6月5日
    022
  • Spring Cloud Alibaba 之 Sentinel 限流规则和控制台实例

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年9月22日
    0197
  • Java 断点下载(下载续传)服务端及客户端(Android)代码

    最近在研究断点下载(下载续传)的功能,此功能需要服务端和客户端进行对接编写,本篇也是记录一下关于贴上关于实现服务端(Spring Boot)与客户端(Android)是如何实现下载…

    Java 2023年6月13日
    028
  • 归并排序求解逆序对

    cpp;gutter:true;</p> <h1>include</h1> <h1>include</h1> <h…

    Java 2023年6月5日
    025
  • 概率神经网络 (PNN) 应用的简单DEMO

    概率神经网络的全称是Probabilistic neural network,它主要用于模式分类,是基于贝叶斯策略前馈神经网络。它有着坚实的数学理论基础,当然本文并不打算从数学符号…

    Java 2023年6月15日
    021
  • JDK1.8 API 中文文档

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年10月25日
    0200
  • spring boot打包成war包的页面该放到哪里?

    背景 经常有朋友问我,平时都是使用spring mvc,打包成war包发布到tomcat上,如何快速到切换到spring boot的war或者jar包上? 先来看看传统的war包样…

    Java 2023年5月30日
    019
  • spring多数据源配置笔记

    本文阐述使用多数据源的额场景,以及如何使用springboot的配置多数据源。 关于后者,主要是直接引用其它博文:https://blog.csdn.net/u012060033/…

    Java 2023年6月9日
    020
  • Linux操作系统–定时任务

    最近在学习Linux操作系统。学到了关于定时任务的章节,作为一个总结写下这篇文章。在Linux中,我们可以将耗时大的任务如复制大文件,压缩、解压缩大文件等放进定时任务中(深夜执行,…

    Java 2023年6月14日
    0134
  • APS实现的要点与难点

    在前一篇关于文章中讨论了不同层级、粒度的生产计划,在各行业中受重视程度的差异问题。 承蒙大家热烈讨论。本文则在收集各方高见的基础上,对于供应链上各个环节的运营、生产计划再作稍微深入…

    Java 2023年6月16日
    023
  • Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年9月22日
    0203
  • 6、接口调试工具

    下面模拟手机微信 向公众号发信息 测试结果: Original: https://www.cnblogs.com/weiapro/p/7732113.htmlAuthor: 天涯越…

    Java 2023年6月13日
    018
  • 记一次 .NET 某工控数据采集平台 线程数 爆高分析

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年9月22日
    0150
  • JPA 入门实战(2)–简单使用

    本文主要介绍 JPA 的实际使用,相关的环境及软件信息如下:JPA 2.2(eclipselink 2.7.10、hibernate-entitymanager 5.6.10.Fi…

    Java 2023年6月16日
    020
  • Java虚拟机之内存区域

    相对于C/C++C程序员,Java程序员会相对轻松一些,因为Java虚拟机的内存管理机制会管理内存,不需要开发人员手动进行内存管理,也不容易出现内存泄露和内存溢出的。但如果不了解虚…

    Java 2023年5月29日
    018
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球