Nginx热升级到1.23.4过程指导手册

一、问题描述

在这里插入图片描述

因环境内部安全扫描发现CVE-2021-23017、CVE-2022-41741、CVE-2022-41742、CVE-2019-20372漏洞,经分析后,需要将nginx升级到1.23.4版本;

现场环境:centos7.4 1708、nginx 1.20.1

资料:软件下载360安全编译参考官方文档连接数限制HTTP Keepalive 连接和 Web 性能Nginx性能优化

二、升级及加固处理

在这里插入图片描述
1)版本确认

nginx -V   //输出如下
nginx version: nginx/1.20.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --add-module=../nginx-rtmp-module-master --with-http_ssl_module --with-stream

2)备份

#如果数据量不大,就整包复制一份
cp -pr ./nginx ./nginx_20230622_1.20.1

3)介质下载及编译安装

wget no-check-certificate https://nginx.org/download/nginx-1.23.4.tar.gz
tar -xzf nginx-1.23.4.tar.gz
#源码包目录
.
├── auto            自动检测系统环境以及编译相关的脚本
│   ├── cc          关于编译器相关的编译选项的检测脚本
│   ├── lib         nginx编译所需要的一些库的检测脚本
│   ├── os          与平台相关的一些系统参数与系统调用相关的检测
│   └── types       与数据类型相关的一些辅助脚本
├── conf            存放默认配置文件,在make install后,会拷贝到安装目录中去
├── contrib         存放一些实用工具,如geo配置生成工具(geo2nginx.pl)
├── html            存放默认的网页文件,在make install后,会拷贝到安装目录中去
├── man             nginx的man手册
└── src             存放nginx的源代码
    ├── core        nginx的核心源代码,包括常用数据结构的定义,以及nginx初始化运行的核心代码如main函数
    ├── event       对系统事件处理机制的封装,以及定时器的实现相关代码
    │   └── modules 不同事件处理方式的模块化,如select、poll、epoll、kqueue等
    ├── http        nginx作为http服务器相关的代码
    │   └── modules 包含http的各种功能模块
    ├── mail        nginx作为邮件代理服务器相关的代码
    ├── misc        一些辅助代码,测试c++头的兼容性,以及对google_perftools的支持
    └── os          主要是对各种不同体系统结构所提供的系统函数的封装,对外提供统一的系统调用接口
cd nginx-1.23.4
./configure --prefix=/usr/local/nginx --add-module=/data/spms/nginx-rtmp-module-master --with-http_ssl_module --with-stream  //输出如下
……
checking for getaddrinfo() ... found
configuring additional modules
adding module in /data/spms/nginx-rtmp-module-master
 + ngx_rtmp_module was configured
checking for PCRE2 library ... not found
checking for PCRE library ... found
checking for PCRE JIT support ... found
checking for OpenSSL library ... found
checking for zlib library ... found
creating objs/Makefile

Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"
#编译
make -j4  //输出如下
……
objs/addon/nginx-rtmp-module-master/ngx_rtmp_proxy_protocol.o \
objs/addon/hls/ngx_rtmp_hls_module.o \
objs/addon/dash/ngx_rtmp_dash_module.o \
objs/addon/hls/ngx_rtmp_mpegts.o \
objs/addon/dash/ngx_rtmp_mp4.o \
objs/addon/nginx-rtmp-module-master/ngx_rtmp_stat_module.o \
objs/addon/nginx-rtmp-module-master/ngx_rtmp_control_module.o \
objs/ngx_modules.o \
-ldl -lpthread -lcrypt -lpcre -lssl -lcrypto -ldl -lpthread -lz \
-Wl,-E
make[1]: Leaving directory `/home/ygcg/nginx-1.23.4'

#验证
cd objs/
ls  //如下所示
addon         Makefile  nginx.8            ngx_auto_headers.h  ngx_modules.o
autoconf.err  nginx     ngx_auto_config.h  ngx_modules.c       src

在这里插入图片描述

4)热升级替换及验证

mv ./sbin/nginx ./sbin/nginx_1.20.1
cp -pr /home/ygcg/nginx-1.23.4/objs/nginx ./sbin/

#确认nginx.pid位置
find ./ -name nginx.pid
./logs/nginx.pid
cat ./logs/nginx.pid 
#热升级
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid `
ll /usr/local/nginx/logs/nginx.pid.oldbin  //输出如下
-rw-r--r-- 1 ygcg root 5 Sep 14  2022 /usr/local/nginx/logs/nginx.pid.oldbin

kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin` //优雅退出

ln -s /usr/local/nginx/sbin/nginx /bin/  #绝对路径

nginx -V #验证
nginx version: nginx/1.23.4
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --add-module=/data/spms/nginx-rtmp-module-master --with-http_ssl_module --with-stream

在这里插入图片描述
在这里插入图片描述

三、附录:

3.1、NGINX 常见模块

在这里插入图片描述

我们在nginx预编译过程中,可使用参数–add-module=PATH指定第三方模块路径来添加模块,我们常见的有:

1、nginx-module-vts 模块实现流量监控

git clone https://github.com/vozlt/nginx-module-vts.git
./configure --prefix=/apps/nginx --add-module=/usr/local/src/nginx-module-vts
配置参考:
http {

vhost_traffic_status_zone; #先填入模块

server {

location /status {
vhost_traffic_status_display; #开启模块
vhost_traffic_status_display_format html; #模块的页面
} ##编译新模块需要重启nginx才能访问测试,不支持reload,重启之后就可浏览器访问:http://<nginx_ip>/status

2、echo模块

git clone https://github.com.cnpmjs.org/openresty/echo-nginx-module.git
/configure
–prefix=/usr/local/nginx
–user=nginx --group=nginx
–with-http_ssl_module
–with-http_v2_module
–with-http_realip_module
–with-http_stub_status_module
–with-http_gzip_static_module
–with-pcre
–with-stream
–with-stream_ssl_module
–with-stream_realip_module
–with-http_perl_module
–add-module=/usr/local/modules/echo-nginx-module

2、开启目录索引

语法: autoindex on | off;
默认: autoindex off;
位置: http, server, location

3.格式化文件大小

语法: autoindex_exact_size on | off;
默认: autoindex_exact_size on;
位置: http, server, location

4.输出的格式

语法: autoindex_format html | xml | json | jsonp;
默认: autoindex_format html;
位置: http, server, location

5.使用时区

语法: autoindex_localtime on | off;
默认: autoindex_localtime off;
位置: http, server, location

6、http_auth_basic_module HTTP基本认证

用途:提供HTTP基本认证功能。
内置模块:是。
默认启用:是。如果需要禁用,编译Nginx时使用–without-http_auth_basic_module。
作用域:http, server, location, limit_except

server {
listen 80;
server_name test.com;

auth_basic “登录认证”;
auth_basic_user_file /etc/nginx-htpasswd;

root /mnt/html/www;
index index.html;
}

7、http_stub_status_module 状态信息
用途:该模块可以提供 Nginx 的状态信息。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_stub_status_module。
作用域:server, location
该模块仅有stub_status这一个指令。

location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}

8、http_gzip_module 压缩资源
用途:用于支持gzip on等指令,用来减轻服务器的带宽问题,经过gzip压缩后的页面大小可以变为原来的30%甚至更小。
内置模块:是。
默认启用:是。如果需要禁用,编译Nginx时使用–without-http_gzip_module。

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable “MSIE [1-6].”;

9、http_gzip_static_module 支持.gz资源
用途:允许发送以.gz作为文件扩展名的预压缩文件,以替代发送普通文件。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_gzip_static_module。

gzip_static on;

10、http_sub_module 字符串替换
用途:该模块用于实现响应内容固定字符串替换。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_sub_module。
作用域:http, server, location
该模块不支持正则替换,灵活性不够。支持正则匹配替换的第三方模块:

1、ngx_http_substitutions_filter_module:https://github.com/yaoweibin/ngx_http_substitutions_filter_module
2、replace-filter-nginx-module:https://github.com/agentzh/replace-filter-nginx-module
\

location / {
    sub_filter '<a href="http://127.0.0.1:8080/'  '<a href="https://$host/';
    sub_filter 'nginx.com' 'baidu.com';
    # 是否仅替换一次,如果为off,则全局替换
    sub_filter_once on;
    # 替换的响应类型,*表示替换所有类型
    sub_filter_types text/html;
    # 是否保留原始的Last-Modified。默认是on
    sub_filter_last_modified on;
}

11、http_addition_module 追加内容

用途:用于在响应之前或者之后追加文本内容,比如想在站点底部追加一个js或者css,可以使用这个模块来实现。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_addition_module。

location / {
        addition_types text/html;
        add_before_body /2013/10/header.html;
        add_after_body  /2013/10/footer.html;
    }
    
12、http_realip_module 获取实际IP

用途:用于配置REMOTE_ADDR实际IP。 通过这个模块允许我们改变客户端请求头中客户端IP地址值(例如,X-Real-IP 或 X-Forwarded-For)。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_realip_module。

一般是在客户端和服务端中间增加了代理服务器或者负载均衡,才需要使用这个模块,如果不使用,服务端获取的REMOTE_ADDR就不是客户端的真实IP。

location{
set_real_ip_from  192.168.1.0/24; #指定接收来自哪个前端发送的 IP head 可以是单个IP或者IP段
set_real_ip_from 192.168.2.1; 
real_ip_header X-Real-IP;  #IP head  的对应参数,默认即可。

13、http_ssl_module 支持HTTPS
用途:此模块为Nginx提供HTTPS支持。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_ssl_module。

14、http_image_filter_module 图片处理
用途:实现图片裁剪、缩放、旋转功能,支持jpg、gif、png格式。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_image_filter_module。依赖GD库:yum install gd-devel

15、http_geoip_module 支持GeoIP
用途:GeoIP支持,可以用于IP访问限制。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_geoip_module。

16、http_auth_request_module 第三方auth支持
用途:Nginx默认支持使用auth_basic进行本机验证,也可以使用该模块以支持第三方认证。提供auth_request指令,Nginx 服务器通过 header 的返回状态判断是否认证通过。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用--with-http_auth_request_module。

17、http_flv_module 流媒体点播

一般配合nginx-rtmp-module实现流媒体服务器。https://github.com/arut/nginx-rtmp-module,相关模块:

http_flv_module: 支持flv。内置模块。
http_mp4_module: 支持mp4。内置模块。
nginx_mod_h264_streaming: 使nginx支持h264编码的视频
nginx-rtmp-module: 支持rtmp协议
其中http_flv_module和http_mp4_module两个模块是nginx自带的, 可以在编译的时候加上相应的选项。
nginx_mod_h264_streaming的下载地址: http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-Nginx-Version2

./configure --add-module=$HOME/nginx_mod_h264_streaming-2.2.7 --sbin-path=/usr/local/sbin --with-debug

更多参看官网或外部博客,配置项模块参看nginx模块

3.2、nginx配置文件变量

1、日志格式变量

$remote_addr # 记录客户端IP地址
$remote_user # 记录客户端用户名
$time_local # 记录通用的本地时间
$time_iso8601 # 记录ISO8601标准格式下的本地时间
$request # 记录请求的方法以及请求的http协议
$status # 记录请求状态码(用于定位错误信息)
$body_bytes_sent # 发送给客户端的资源字节数,不包括响应头的大小
KaTeX parse error: Expected 'EOF', got '#' at position 12: bytes_sent #̲ 发送给客户端的总字节数msec # 日志写入时间。单位为秒,精度是毫秒。
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$http_x_forwarded_for #记录客户端IP地址
$request_length # 请求的长度(包括请求行,请求头和请求正文)。
$request_time # 请求花费的时间,单位为秒,精度毫秒

注:如果Nginx位于负载均衡器,nginx反向代理之后,web服务器无法直接获取到客 户端真实的IP地址。
$remote_addr获取的是反向代理的IP地址。 反向代理服务器在转发请求的http头信息中,
增加X-Forwarded-For信息,用来记录客户端IP地址和客户端请求的服务器地址

#日志格式定义示例
http {
log_format access_log_format  '$remote_addr - $remote_user [$time_local]
"$request" '
           '$status $body_bytes_sent "$http_referer" '
           '"$http_user_agent" "$http_x_forwarded_for"'
           '$server_name:$server_port';
 }
#Nginx 的默认访问日志记录内容相对比较单一,不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用ELK做日志收集,统计和分析。参考链接:http://json.cn/
http {
log_format access_json '{"@timestamp":"$time_iso8601",'
    '"host":"$server_addr",'
    '"clientip":"$remote_addr",'
    '"size":$body_bytes_sent,'
    '"responsetime":$request_time,' #总的处理时间
    '"upstreamtime":"$upstream_response_time",' #后端应用服务器处理时间
    '"upstreamhost":"$upstream_addr",' 
    '"http_host":"$host",'
    '"uri":"$uri",'
    '"xff":"$http_x_forwarded_for",'
    '"referer":"$http_referer",'
    '"tcp_xff":"$proxy_protocol_addr",'
    '"http_user_agent":"$http_user_agent",'
    '"status":"$status"}';
  access_log /usr/local/nginx/logs/access_json.log access_json;
}
#日志过滤
#比如请求favicon.ico时,不记录日志;是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错
location /favicon.ico {
log_not_found off;
access_log off;
return 200;
}
#当有人访问gif、png等资源时,将日志丢入空
location ~* .*\.(gif|jpg|png|css|js)$ {
 access_log /dev/null;
}

2、Nginx内置变量

$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP

$args;
#变量中存放了URL中的所有参数,例如:http://www.ehuo.org/main/index.do?
id=20190221&partner=search
#返回结果为: id=20190221&partner=search

$host;
#存放了请求的host名称

echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0

$remote_port;
#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口

$remote_user;
#已经经过Auth Basic Module验证的用户名

$request_body_file;
#做反向代理时发给后端服务器的本地资源的名称

$request_method;
#请求资源的方式,GET/PUT/DELETE等

$request_filename;
#当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径,

如:/apps/nginx/html/main/index.html

KaTeX parse error: Expected 'EOF', got '#' at position 14: request_uri; #̲包含请求参数的原始URI,不包…document_uri?$args,例如:/main/index.do?
id=20190221&partner=search

$scheme;
#请求的协议,例如:http,https,ftp等

$server_protocol;
#保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等

$server_addr;
#保存了服务器的IP地址

$server_name;
#请求的服务器的主机名

$server_port;
#请求的服务器的端口号

$http_user_agent;
#客户端浏览器的详细信息

$http_cookie;
#客户端的所有cookie信息

$cookie_
#name为任意请求报文首部字部cookie的key名

$http_
#name为任意请求报文首部字段,表示记录请求报文的首部字段,ame的对应的首部字段名需要为小写,如果有横线需要替换为下划线
arbitrary request header field; the last part of a variable name is the field
name converted to lower case with dashes replaced by underscores #用下划线代替横线

3.3、Nginx https 流程图

在这里插入图片描述

https://nginx.org/en/docs/http/ngx_http_ssl_module.html
To reduce the processor load it is recommended to
set the number of worker processes equal to the number of processors,
enable keep-alive connections,
enable the shared session cache,
disable the built-in session cache,
and possibly increase the session lifetime (by default, 5 minutes):
worker_processes auto;
http {
 ...
 server {
   listen        443 ssl;
   keepalive_timeout  70;
   ssl_protocols    TLSv1 TLSv1.1 TLSv1.2;
   ssl_ciphers     AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
   ssl_certificate   /usr/local/nginx/conf/cert.pem;
   ssl_certificate_key /usr/local/nginx/conf/cert.key;
   ssl_session_cache  shared:SSL:10m;
   ssl_session_timeout 10m;
   ...
 }
#自签名CA证书
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
#自制key和csr文件
openssl req -newkey rsa:4096 -nodes -sha256 -keyout server.key -out server.csr
#自签发crt证书
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
#查看证书内容
openssl x509 -in server.crt -noout -text

3.4、http强制https

server {
 listen 443 ssl;
 server_name www.ehuo.org;
 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
 location / {
   if ( $scheme = http ) {
    rewrite ^/(.*)$ https://www.ehuo.org/$1 redirect;   #主要实现       
            
   }

3.5、防盗链

#配置完成 后可使用curl -e参数指定refer测试
vim /usr/local/nginx/conf/conf.d/pc.conf  //如下所示
server {
 index index.html;
 valid_referers none blocked server_names *.blue.com *.blue.org 
~\.google\. ~\.baidu\. ~\.bing\. ~\.so\. ; #定义有效的referer
  if ($invalid_referer) { #假如是使用其他的无效的referer访问
  return 403 "Forbidden Access"; #返回状态码403
   #return 302 http:/blue.com/test.jpg;
   #rewrite ^(.*)$ /daolian.jpg break;#或者返回错误图片
 }
......
}
#语法说明
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
none:#请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信
息。
blocked:#请求报文有referer首部,但无有效值,比如为空。
server_names:#referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:#自定义指定字符串,但可使用*作通配符。示例: *.ehuo.org www.ehuo.*
regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:
~.*\.ehuo\.com

四、Nginx扩容

4.1、Nginx 由于业务扩张,请求数增加的扩容

在这里插入图片描述
上图这种web请求处理模式是非常低效的,特别是对于具有大量元素的复杂网页或当网络链接缓慢时。创建新的TCP连接需要“三向握手”,拆除它还需要双向关闭过程。重复创建和关闭TCP连接,每条消息就需要来一次这样一个过程,非常耗费系统资源,响应时间也令人不满。Nginx中使用 keepalive connections 参数可以来保持c和s之间的会话,当统一客户端新的事务处理时,就可直接分配重用之前的会话;
在这里插入图片描述
注意,这些web和应用服务器通常会为每个连接分配一个操作系统线程或进程。TCP连接(并发)是一个非常轻量级的OS对象,但线程或进程是非常重量级的,线程和进程需要内存,它们必须由操作系统主动管理,并且线程或进程之间的“上下文切换”会消耗CPU,为每个连接分配各自的线程或进程是非常低效的,从而导致下图的关系和“HTTP重载”现象:
在这里插入图片描述
进程是操作系统进行资源分配的最小单位,线程是CPU调度和分配的基本单位,大多数支持多核的操作系统上,都能实现把一个进程的多个线程放不同的核心上跑。线程的实现有两种方式,一种是内核调度的线程,可以运行在多个核上,还有一种是用户级线程,这个就没办法跑到多个核上了。内核级线程是指切换由内核控制的线程,当线程进行切换的时候,由用户态转化为内核,切换完毕要从内核态返回用户态。用户级线程是指不需要内核支持而在用户程序中实现的线程,它的内核的切换是由用户态程序自己控制内核的切换,不需要内核的干涉。但是它不能像内核级线程一样能更好的运用多核CPU。相比较,用户态线程的创建、调度和销毁都由应用程序自己负责,而内核态线程则由操作系统内核负责。

用户态线程的原理如下:

1、应用程序创建用户态线程:应用程序可以使用各种库函数来创建用户态线程,例如 POSIX 线程库中的 pthread_create() 函数。这些库函数会负责在用户空间中分配内存、初始化线程栈和寄存器,然后将新创建的线程加入到应用程序自己的线程队列中。

2、应用程序调度用户态线程:应用程序可以使用各种调度算法来调度用户态线程,例如时间片轮转算法、优先级算法等。应用程序会根据自己的需要选择合适的调度算法,然后由应用程序自己负责在用户态线程之间进行切换。

3、应用程序销毁用户态线程:当用户态线程执行完毕或不再需要时,应用程序可以使用库函数来销毁该线程,例如 POSIX 线程库中的 pthread_join() 函数。销毁线程时,应用程序需要回收线程占用的内存和资源。

用户态线程的主要优点是:

轻量级: 用户态线程的创建、销毁和切换都可以在用户空间中完成,不需要内核的参与,因此开销很小。
高效: 用户态线程的调度和管理完全由应用程序自己负责,因此可以根据应用程序的具体需求进行优化,从而提高线程的执行效率。
可移植性: 用户态线程的实现与操作系统内核无关,因此可以在不同的操作系统平台上移植使用。

用户态线程的主要缺点是:

无法访问内核资源: 用户态线程只能访问用户空间的资源,无法直接访问内核空间的资源,因此无法执行某些特权操作。
容易受到攻击: 用户态线程的安全性较低,容易受到各种攻击,例如缓冲区溢出攻击等。

一般来说,nginx 的最大并发处理量可以达到数十万甚至数百万个并发连接。业内一般认为单个nginx支持高达 5w 个并发连接数;然而,在实际应用中,nginx 的并发处理量通常受限于硬件资源和操作系统的限制,如 CPU、内存和网络带宽;如nginx 的配置:worker_processes、worker_connections 和 keepalive_timeout 等。如操作系统的文件描述符限制和内核参数有没有正确配置,有没有启用 TCP 快速打开等。除采用多核CPU、大容量内存、高速网络接口等硬件设备外,另外使用HTTP/2可以有效地提高页面加载速度和并发处理能力,通过在Nginx中启用HTTP/2,可以更好地处理大量并发请求。开启gzip压缩,减少网络带宽也能提高;扩展Nginx服务器+负载均衡也能横向扩展并发;如果需要使用SSL加密,可以使用Nginx的SSL加速功能,从而提高加密和解密速度,减少对服务器性能的影响,提高并发;Nginx使用异步非阻塞IO处理连接请求,当一个连接正在等待IO操作完成时,Nginx可以处理其他连接,这可以显著提高吞吐量。Nginx使用内存池来管理内存分配,可减少了内存碎片和内存分配的开销,从而也能提高并发。开启TCP_NODELAY和TCP_NOPUSH选项:这可以减少TCP连接的延迟和减少发送数据的次数,提高性能;使用Nginx的缓存功能可以大大减少后端应用程序的负载;

server端tcp连接4元组中只有remoteip(也就是clientip)和remote port(客户端port)是可变的,因此最大tcp连接为客户端ip数×客户端port数,对IPV4,不考虑ip地址分类等因素,最大tcp连接数约为2的32次方(ip数)×2的16次方(port数),也就是server端单机最大tcp连接数约为2的48次方,月281兆的连接数。实际环境中,受到因素的限制,特别是sever端,其最大并发tcp连接数远不能达到理论上限。相关经验表明:服务器的并发数并不是由TCP的65535个端口决定的,端口是可服用的,连接数可根据tcp的4元组来定,刨去一些协议已占用的端口,一般认为同一个ip访问同一个服务端能使用的端口就是4万个左右,其实真正影响TCP连接数量的,是服务器的内存以及允许单一进程同时打开文件的数量,因为每创建一个TCP连接都要创建一个socket句柄,每个socket句柄都占用一部分系统内存,当系统内存被占用殆尽,允许的TCP并发连接数也就到了上限。总之服务器同时能够承受的并发数是由带宽、硬件、程序设计等多方面因素决定的。对server端,通过增加内存、修改最大文件描述符个数等参数,单机最大并发TCP连接数超过10万,甚至上百万是没问题的。

1、ngx_stream_limit_conn_module module (1.9.3版本) is used to limit the number of connections per the defined key, in particular, the number of connections from a single IP address.

#当前启动的worker进程,官方建议是与系统核心数一致
worker_processes 2;
worker_connections 4096;    #每一个进程打开的最大连接数;它受 Linux 系统进程打开的最大文件数的限制,只有执行了 “ulimit -HSn 65535” 之后,worker_connections 才能生效
#或
worker_cpu_affinity auto;  #设置 worker 进程与 CPU 核之间的绑定关系,即会自动将 worker 进程绑定到不同的CPU 核上,更均匀地利用 CPU 资源减少 worker 进程之间的竞争,尽量将 worker 进程绑定到不同的 CPU 插槽和 NUMA 节点上,减少 worker 进程之间的内存访问延迟,提高 Nginx 的性能,提高 Nginx 的并发处理能力和性能。注:worker_cpu_affinity auto 的效果取决于 CPU 的拓扑结构。如果 CPU 的拓扑结构不合理,那么 worker_cpu_affinity auto 可能无法发挥出应有的效果。lscpu |grep "CPU(s)"查看;ps -eo pid,args,psr|grep [n]ginx查看 nginx worker 进程绑定⾄对应 cpu
worker_priority -20;   #设置nginx worker进程的静态优先级,尽可能让nginx⼀直使⽤cpu,默认值是0,设置为-20最高,减少cpu上下⽂切换的次数
#对 nginx 句柄的文件限制
worker_rlimit_nofile 35535;  #每个进程打开的最大的文件数,受限于操作系统,可根据ulimit -HSn值来配置,使用sysctl -a | grep fs.file查看linux系统文件描述符

events {
#使用epoll内核模型,采用epoll事件模型,处理效率高;另Nginx 使用 epoll 来实现 IO 多路复用。epoll 是 Linux 内核中的一种高效的 IO 多路复用机制,它可以同时监视多个文件描述符,并在一有事件发生时通知应用程序。Nginx 在启动时会创建一个 epoll 实例,并将需要监视的文件描述符(例如,监听的端口、已建立的连接等)添加到 epoll 实例中。然后,Nginx 会进入一个循环,在这个循环中,它会调用 epoll_wait() 函数来等待 epoll 事件发生。当 epoll_wait() 函数返回时,Nginx 会遍历所有发生的事件,并根据事件的类型(例如,有新的连接、有数据可读、连接断开等)调用相应的处理函数来处理这些事件。Nginx 使用 epoll 来实现 IO 多路复用,可以同时处理大量的并发连接,并高效地处理各种 IO 事件,从而提高服务器的性能和吞吐量。编译时可加入--with-poll_module;

user epoll;
#每一个进程可以处理多少个连接,如果是多核可以将连接数调高 worker_processes * 1024
worker_connections 10240;   #并发数;最大连接数=worker_processes*worker_connections
multi_accept on;  #nginx收到一个新连接通知后接受尽可能多的连接,默认是on,多个worker按串行方式来处理连接,也就是一个连接只有一个worker被唤醒,其他的处于休眠状态,设置为off后,多个worker按并行方式来处理连接,也就是多个连接唤醒全部的worker,直到连接分配完毕,没有取得连接的继续休眠。当你的服务器连接数不多时,on这个参数会让负载有一定的降低,但是当服务器的吞吐量很大时,为了效率,off这个参数。
accept_mutex on; #优化同一时刻只有一个请求而避免多个睡眠进程被唤醒的设置,on为防止被同时唤醒,默认为off
}
http {
gzip on; #文件压缩默认可以打开
gzip_disable "MSIE [1-6]\."; #对于有些浏览器不能识别压缩,需要过滤如ie6
gzip_http_version 1.1;
server_tokens off;     #隐藏版本号
#限制单个ip的连接;当 Nginx 接收到一个新的请求时,它会首先检查该请求的客户端 IP 地址是否已经在 addr 共享内存区域中。如果已经存在,则会检查该客户端的并发连接数是否超过了限制。如果超过了限制,则会拒绝该请求。注意的是,limit_conn_zone 配置项只能限制客户端的并发连接数,而不能限制客户端的总连接数。如果某个客户端不断地建立和断开连接,那么它仍然可以绕过 limit_conn_zone 的限制。要限制客户端的总连接数,可以使用 limit_req_zone 配置项

sendfile on;    #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等耗用磁盘IO重负载的应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off
send_timeout 60;  # 默认60s  此处有坑!! 系统中若有耗时操作,超过 send_timeout 会被强制断开连接。 注意:准备过程中,不是传输过程
tcp_nopush on;   #必须在sendfile开启模式才有效,减少网络报文段的数量(将响应头和正文的开始部分一起发送,而不一个接一个的发送。)防止网路阻塞

keepalive_timeout 60;              #客户端连接保持会话超时时间,单位s,即一个tcp连接总时长,超过之后 强制失效
keepalive_timeout  65 65; 			   #超过这个时间 没有活动,会让keepalive失效 
keepalive 32; 						   #Nginx到应⽤服务器的连接池⾥⾯最⼤的空闲长连接数。也就是最多有32个空闲的⻓连接
keepalive_requests 100000; 			   #一个tcp复用中 可以并发接收的请求个数,Nginx到应⽤应⽤服务器的⼀个长连接最多可承载处理的HTTP请求个数,允许通过同一连接发送最多10万个请求;超过后⾃动关闭该连接,有需要Nginx会再⽣成新的长连接
keepalive_time 60s;					  #keepalive_timeout超时,在60s时间内代理服务器的空闲keepalive连接将保持打开状态

  



tcp_nodelay on;						   #防止网络阻塞,和keepalived参数一起才有效
client_header_buffer_size 4k;		   #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过 1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得
open_file_cache max=102400 inactive=20s; #为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存
open_file_cache_valid 30s;			  #多长时间检查一次缓存的有效信息
open_file_cache_min_uses 1;			  #open_file_cache指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。
client_header_timeout 15;			  #请求头的超时时间。如果超过这个时间没有发送任何数据,nginx将返回request time out的错误。	
client_body_timeout 15;			     #请求体的超时时间
reset_timedout_connection on;        #nginx关闭不响应的客户端连接,这将会释放那个客户端所占有的内存空间。
send_timeout 15;					#响应客户端超时时间,这个超时时间仅限于两个活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx关闭连接
client_max_body_size 10m;			#上传文件大小限制

#Nginx中当用户发起的,如果是动态请求(如 PHP),那么 Nginx 就会把它通过 FastCGI 接口发送给 PHP 引擎服务(即 php-fpm)进行解析,如果这个动态请求要读取数据库数据,那么 PHP 就会继续请求 MySQL 数据库,以读取需要的数据,并最终通过 Nginx 服务把获取的数据返回给用户。在 Linux 中,FastCGI 接口即为 socket ,这个 socket 可以是文件 socket,也可以是 IP socket。

fastcgi_connect_timeout 240; # Nginx服务器和后端FastCGI服务器连接的超时时间
fastcgi_send_timeout 240; # Nginx允许FastCGI服务器返回数据的超时时间,即在规定时间内后端服务器必须传完所有的数据,否则Nginx将断开这个连接
fastcgi_read_timeout 240; # Nginx从FastCGI服务器读取响应信息的超时时间,表示连接建立成功后,Nginx等待后端服务器的响应时间
fastcgi_buffer_size 64k; # Nginx FastCGI 的缓冲区大小,用来读取从FastCGI服务器端收到的第一部分响应信息的缓冲区大小
fastcgi_buffers 4 64k; # 设定用来读取从FastCGI服务器端收到的响应信息的缓冲区大小和缓冲区数量
fastcgi_busy_buffers_size 128k; # 用于设置系统很忙时可以使用的 proxy_buffers 大小
fastcgi_temp_file_write_size 128k; # FastCGI 临时文件的大小
fastcti_temp_path /data/ngx_fcgi_tmp; # FastCGI 临时文件的存放路径
fastcgi_cache_path /data/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:512m inactive=1d max_size=40g; # 缓存目录




stream {
    limit_conn_zone $binary_remote_addr zone=addr:10m;  #设置一个远程ip的共享的内存zone:名称为addr,10M内存;使用 $binary_remote_addr 变量,表示要限制的客户端的二进制 IP 地址,IPv4地址为4字节,IPv6地址为16字节;连接状态值占32/64byte,一兆字节区域可以保持大约32000个32字节状态或大约16000个64字节状态。如果区域存储用尽,则连接也会被拒绝
    ...
    server {
        ...
        limit_conn           addr 1;   #每个IP地址一次只允许一个连接,可以指定多个limit_conn 
        limit_conn_log_level error;
        proxy_http_version 1.1;  #默认是1.0。只有http1.1后才增加了⻓连接的⽀持
        proxy_set_header Connection ""; #清除“connection”头字段,是清理从 Client过来的 http header,因为即使是 Client 和 NGINX 之间是短连接,NGINX 和 upstream 之间也是可以开启⻓连接的。这种情况下必须清理来⾃ Client 请求中的 “Connection” header
        proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m inactive=60m;
		proxy_cache_key	"$scheme $request_method $host$request_uri";
		proxy_cache_valid 200 60m;  #创建一个缓存目录,将缓存键设置为包括请求方法和 URI,并将状态代码为 200 的响应缓存60分钟

    }
}
# 限制客户端的总连接数
# 限制每个 IP 地址每秒的请求数,设置一个名为 cns的限流区域,该区域的存储空间为 10MB,每个 IP 地址每秒的请求速率限制为 5 个请求。
limit_req_zone $binary_remote_addr zone=cns:10m rate=5r/s;

# 对所有请求应用限流规则:每个 IP 地址每秒最多只能发送 5 个请求,超过此限制的请求将被拒绝。
limit_req zone=cns burst=5;

# 针对 /api/v1/endpoint 端点的请求应用限流规则
location /api/v1/endpoint {
    limit_req zone=cns burst=5;
}

# 针对 /images/* 端点的请求应用限流规则
location /images/* {
    limit_req zone=cns burst=10;
    limit_req_status 429;    #定义当请求被限流时返回的 HTTP 状态码429(太多请求)
}

location ~ .*.(php|php5)?$ {
 root html/www;
 fastcgi_pass 127.0.0.1:9000;
 fastcgi_index index.php;
 include fastcgi.conf;
 fastcgi_cache ngx_fcgi_cache; # 缓存FastCGI生成的内容,比如PHP生成的动态内容
 fastcgi_cache_valid 200 302 1h; # 指定http状态码的缓存时间,这里表示将200和302缓存1小时
 fastcgi_cache_valid 301 1d; # 指定http状态码的缓存时间,这里表示将301缓存1天
 fastcgi_cache_valid any 1m; # 指定http状态码的缓存时间,这里表示将其他状态码缓存1分钟
 fastcgi_cache_min_uses 1; # 设置请求几次之后响应被缓存,1表示一次即被缓存
 fastcgi_cache_use_stale error timeout invalid_header http_500; # 定义在哪些情况下使用过期缓存
 fastcgi_cache_key http://$host$request_uri; # 定义 fastcgi_cache 的 key
 }
#nginx的缓存功能有:proxy_cache / fastcgi_cache

#proxy_cache的作用是缓存后端服务器的内容,可能是任何内容,包括静态的和动态。fastcgi_cache的作用是缓存fastcgi生成的内容,很多情况是php生成的动态的内容。
#proxy_cache缓存减少了nginx与后端通信的次数,节省了传输时间和后端宽带。fastcgi_cache缓存减少了nginx与php的通信的次数,更减轻了php和数据库(mysql)的压力。

#开启缓存,expires可以降低网站购买的带宽,节约成本;同时提升用户访问体验;减轻服务的压力,节约服务器成本;缓存的时间不宜设置太长,被缓存的页面或数据更新了,用户看到的可能还是旧的内容,反而影响用户体验。
location ~* \.(ico|jpe?g|gif|png|bmp|swf|flv)$ {
expires 30d;    #主要针对于图片,css,js等元素更改机会比较少的情况下使用,特别是图片,占用带宽大,我们完全可以设置图片在浏览器本地缓存365d,css,js,html可以缓存30天
#log_not_found off;
#access_log off;
}
location ~* \.(js|css)$ {
expires 7d;
log_not_found off;
access_log off;
}
#开启防盗链:防止别人直接从你网站引用图片等链接,消耗了你的资源和网络流量,
#方式一
location ~ .*.(gif|jpg|jpeg|png|bm|swf|flv|rar|zip|gz|bz2)$ { # 指定需要使用防盗链的媒体资源
 access_log off; # 不记录日志
 expires 15d; # 设置缓存时间
 valid_referers none blocked *.test.com *.abc.com; # 表示仅允许这些域名访问上面的媒体资源
 if ($invalid_referer) { # 如果域名不是上面指定的地址就返回403
 return 403
 }
}
 
#方式二
location /images { 
 root /web/www/img;   #直接绑定资源
 vaild_referers none blocked *.blue.com *.blue.top;  #none意思是不存在的Referer头(表示空的,也就是直接访问,比如直接在浏览器打开一个图片);多个服务器的列表0.5.33版本以后可以在名称中使用“*”通配符
 if ($invalid_referer) {
 return 403;
 #return 302 http://www.blue.com/img/nolink.jpg
 #return 404;  
 #break;
 }
}

在这里插入图片描述
如上图示:当nginx接收到一个二进制http请求后首先会将它反序列化成一个可读的文本,处理完请求行之后才处理请求头和请求体;对于请求体的读取可以设置client_body_buffer_size缓冲区大小,大于设置值则写入临时文件。读取请求体的过程中可以通过proxy_request_buffering决定是否向上游发起请求,off即边读边发(异步);向上游服务器连接前,nginx首先会选择服务器(在upstream中),然后将http请求打包成标准的二进制请求报文,此时可以通过set_header往请求头添加想要发送给上游的信息,然后向epoll事件队列中注册回调函数,以便接收到返回数据后做处理。

内核优化:

sysctl -a | grep "nf_conntrack_max"     //查看当前系统默认最大连接数
sysctl -a | grep 'fs.file-max' //查看当前Linux最大连接数
cat /proc/sys/net/netfilter/nf_conntrack_count  //查看系统当前维持了多少个连接数
cat /proc/net/nf_conntrack | less
sysctl -w net.netfilter.nf_conntrack_max=1000000  //修改目前系统默认最大连接数为1000万
#hashsize是 Linux 内核中 nf_conntrack 模块的一个参数,用于设置连接跟踪哈希表的初始大小。连接跟踪哈希表用于存储和查找网络连接的状态信息。当启用连接跟踪时,内核会为每个连接创建一个哈希表项。哈希表项包含有关连接的信息,例如源 IP 地址、源端口、目标 IP 地址、目标端口、协议类型、连接状态等。连接跟踪哈希表的大小会影响连接跟踪的性能。哈希表越大,查找连接的状态就越快。但是,哈希表越大,使用的内存也就越多。
cat /sys/module/nf_conntrack/parameters/hashsize  //conntrackmax最好设置时遵循2的次幂这个规则,conntrackmax默认65536=2^16,经验取值:hashsize=conntrack max/4
echo "250000">/sys/module/nf_conntrack/parameters/hashsize  //调整连接跟踪哈希表的大小,太大会导致内存不足
cat /proc/sys/net/ipv4/ip_local_port_range  //该文件存储了Linux本地端口范围,端口号1024以下是系统保留的,从1024-65535是用户使用的,其中记录了最小连接数和最大连接数

# TCP 快速打开在 Linux 内核 3.7 中引入,因此你需要使用 3.7 或更高版本的内核;TCP 快速打开需要客户端和服务器都支持。如果你的应用程序同时扮演客户端和服务器的角色,那么你需要确保客户端和服务器都启用了 TCP 快速打开。CP 快速打开可能会带来安全风险。例如,攻击者可能会利用 TCP 快速打开来发起 SYN 泛洪攻击。
cat /proc/sys/net/ipv4/tcp_fastopen  //查询是否启用,输出为 3,则表示 TCP 快速打开已启用
echo 3 > /proc/sys/net/ipv4/tcp_fastopen   //启用

#获取当前socket连接状态统计信息
cat /proc/net/sockstat

#查看CLOSE_WAIT状态有哪些ip
netstat -a |grep "CLOSE_WAIT"|awk '{print $5}'|awk -F '.' '{print $1}' |sort | uniq -c | sort -nr

#timewait 的数量,默认是180000
net.ipv4.tcp_max_tw_buckets = 6000

#允许系统打开的端口范围
net.ipv4.ip_local_port_range = 1024 65000

#启用timewait 快速回收
net.ipv4.tcp_tw_recycle = 1

#开启重用。允许将TIME-WAIT sockets 重新用于新的TCP 连接
net.ipv4.tcp_tw_reuse = 1
#开启SYN Cookies,当出现SYN 等待队列溢出时,启用cookies 来处理
net.ipv4.tcp_syncookies = 1

#web 应用中listen 函数的backlog 默认会给我们内核参数的net.core.somaxconn 限制到128,而nginx 定义的NGX_LISTEN_BACKLOG 默认为511,可以要调整这个值
net.core.somaxconn = 262144

#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 262144

#系统中最多有多少个TCP 套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS 攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)
net.ipv4.tcp_max_orphans = 262144

#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M 内存的系统而言,缺省值是1024,小内存的系统则是128
net.ipv4.tcp_max_syn_backlog = 262144


#时间戳可以避免序列号的卷绕。一个1Gbps 的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉
net.ipv4.tcp_timestamps = 0

#为了打开对端的连接,内核需要发送一个SYN 并附带一个回应前面一个SYN 的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK 包的数量
net.ipv4.tcp_synack_retries = 1

#在内核放弃建立连接之前发送SYN 包的数量。
net.ipv4.tcp_syn_retries = 1

#如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2 状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60 秒。2.2 内核的通常值是180 秒,3你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB 服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比FIN-WAIT-1 要小,因为它最多只能吃掉1.5K 内存,但是它们的生存期长些
net.ipv4.tcp_fin_timeout = 1

#当keepalive 起用的时候,TCP 发送keepalive 消息的频度。缺省是2 小时
net.ipv4.tcp_keepalive_time = 30

#进程(比如一个worker进程)可以同时打开的最大句柄数,这个参数直线限制最大并发连接数,需根据实际情况配置。
fs.file-max =999999#操作系统允许TIME_WAIT套接字数量的最大值,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。该参数默认为180000,过多的TIME_WAIT套接字会使Web服务器变慢。注:主动关闭连接的服务端会产生TIME_WAIT状态的连接
net.ipv4.tcp_max_tw_buckets = 6000


net.ipv4.ip_local_port_range = 1024 65000 #允许系统打开的端口范围。
net.ipv4.tcp_tw_recycle = 1 #启用timewait快速回收。
net.ipv4.tcp_tw_reuse = 1 #开启重用。允许将TIME-WAITsockets重新用于新的TCP连接。这对于服务器来说很有意义,因为服务器上总会有大量TIME-WAIT状态的连接。
net.ipv4.tcp_keepalive_time =30 #这个参数表示当keepalive启用时,TCP发送keepalive消息的频度。默认是2小时,若将其设置的小一些,可以更快地清理无效的连接。
net.ipv4.tcp_syncookies = 1 #开启SYNCookies,当出现SYN等待队列溢出时,启用cookies来处理。
net.core.somaxconn = 40960 #web 应用中 listen 函数的 backlog 默认会给我们内核参数的。
net.core.somaxconn #限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。注:对于一个TCP连接,Server与Client需要通过三次握手来建立网络连接.当三次握手成功后,我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了.每一个处于监听(Listen)状态的端口,都有自己的监听队列.监听队列的长度与如somaxconn参数和使用该端口的程序中listen()函数有关。somaxconn定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为128,对于一个经常处理新连接的高负载web服务环境来说,默认的 128 太小了。大多数环境这个值建议增加到 1024 或者更多。大的侦听队列对防止拒绝服务 DoS攻击也会有所帮助。
net.core.netdev_max_backlog = 262144  #每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.ipv4.tcp_max_syn_backlog = 262144  #这个参数标示TCP三次握手建立阶段接受SYN请求队列的最大长度,默认为1024,将其设置得大一些可以使出现Nginx繁忙来不及accept新连接的情况时,Linux不至于丢失客户端发起的连接请求。
net.ipv4.tcp_rmem = 10240 87380 12582912  #这个参数定义了TCP接受缓存(用于TCP接受滑动窗口)的最小值、默认值、最大值。
net.ipv4.tcp_wmem = 10240 87380 12582912#这个参数定义了TCP发送缓存(用于TCP发送滑动窗口)的最小值、默认值、最大值。
net.core.rmem_default = 6291456#这个参数表示内核套接字接受缓存区默认的大小。
net.core.wmem_default = 6291456#这个参数表示内核套接字发送缓存区默认的大小。
net.core.rmem_max = 12582912#这个参数表示内核套接字接受缓存区的最大大小。
net.core.wmem_max = 12582912#这个参数表示内核套接字发送缓存区的最大大小。
net.ipv4.tcp_syncookies = 1#该参数与性能无关,用于解决TCP的SYN攻击。

#配置示例
fs.file-max = 999999
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 40960net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 30
net.ipv4.ip_local_port_range = 1024 65000

#其他

sysctl -w net.ipv4.tcp_syncookies=1 #防止一个套接字在有过多试图连接到达时引起过载
sysctl -w net.core.somaxconn=1024          #默认128,连接队列
sysctl -w net.ipv4.tcp_fin_timeout=10      #timewait的超时时间
sysctl -w net.ipv4.tcp_tw_reuse=1          #os直接使用timevait的连接
sysctl -w net.ipv4.tcp_tw_recycle=0        #回收禁用


#修改最大打开文件句柄数
ulimit -SHn 65535 #等效 ulimit -n 65535 ,-S 指soft ,-H 指har,只临时生效
#永久生效
echo "ulimit -SHn 65535" >>/etc/rc.loca
echo "ulimit -SHn 65535" >>/etc/profile #或
ulimit -SHn 1000000 >> /etc/rc.local
vim /etc/security/limits.conf #修改,*代表所有⽤户

*       soft    nofile         65535
*       hard    nofile         65535
*       soft    noproc         65535
*       hard    noproc         65535
修改/etc/pam.d/login文件,在文件中添加如下行:
session required /lib/security/pam_limits.so

#如果是64bit系统的话,应该为 :
session required /lib64/security/pam_limits.so

netstat -n | awk '/^tcp/ {++S[$NF]}END {for(a in S) print a, S[a]}'
ss -ant | awk 'NR>1 {a[$1]++} END {for (b in a) print b,a[b]}'  //查看当前连接情况,结果说明:
	LISTEN: 侦听来自远方的TCP端口的连接请求
    SYN-SENT: 再发送连接请求后等待匹配的连接请求
    SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
    ESTABLISHED: 代表一个打开的连接
    FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
    FIN-WAIT-2: 从远程TCP等待连接中断请求
    CLOSE-WAIT: 等待从本地用户发来的连接中断请求
    CLOSING: 等待远程TCP对连接中断的确认
    LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认
    TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
    CLOSED: 没有任何连接状态


cat /proc/sys/fs/file-nr  //输出结果,第一个数表已经分配的文件描述符数,第2个表已经分配但没有使用的文件描述符数,第2个是最大文件句柄数,可以通过在/etc/sysctl.conf里定义fs.file-max = 1000000 来调整最后一个值的大小;注:lsof所列出来的是每个进程所打开的文件,所以lsof的数值比file-nr要大,因为一个文件可被多个进程打开
cat /proc/sys/fs/file-max  /该值在kernel的文档里意思是file-max一般为内存大小(KB)的10%来计算,可借助grep -r MemTotal /proc/meminfo | awk '{printf("%d",$2/10)}'  计算出来的值作为参考
echo "fs.file-max = 1626760" >> /etc/sysctl.conf && sysctl -p

Nginx 使用 epoll 来处理连接请求的过程:

1、Nginx 启动时,创建一个 epoll 实例,并将监听的端口添加到 epoll 实例中。
2、Nginx 进入一个循环,在这个循环中,它会调用 epoll_wait() 函数来等待 epoll 事件发生。
3、当 epoll_wait() 函数返回时,Nginx 会遍历所有发生的事件,并根据事件的类型调用相应的处理函数来处理这些事件。
4、如果某个事件是新的连接请求,Nginx 会调用 accept() 函数来接受该连接,并将新建立的连接的套接字添加到 epoll 实例中。
5、然后,Nginx 会继续循环,等待下一个 epoll 事件发生。

4.2、压测工具

安装:yum install httpd-tools
参数:

-n 即requests,用于指定压力测试总共的执行次数。
-c 即concurrency,用于指定的并发数。
-t 即timelimit,等待响应的最大时间(单位:秒)。
-b 即windowsize,TCP发送/接收的缓冲大小(单位:字节)。
-p 即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数。
-u 即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数。
-T 即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain。
-v 即verbosity,指定打印帮助信息的冗余级别。
-w 以HTML表格形式打印结果。
-i 使用HEAD请求代替GET请求。
-x 插入字符串作为table标签的属性。
-y 插入字符串作为tr标签的属性。
-z 插入字符串作为td标签的属性。
-C 添加cookie信息,例如:“Apache=1234”(可以重复该参数选项以添加多个)。
-H 添加任意的请求头,例如:“Accept-Encoding: gzip”,请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。
-A 添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开。
-P 添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开。
-X 指定使用的和端口号,例如:“126.10.10.3:88”。
-V 打印版本号并退出。
-k 使用HTTP的KeepAlive特性。
-d 不显示百分比。
-S 不显示预估和警告信息。
-g 输出结果信息到gnuplot格式的文件中。
-e 输出结果信息到CSV格式的文件中。
-r 指定接收到错误信息时不退出程序。
-h 显示用法信息,其实就是ab -help。

示例:

ab -n 100000 -c 30 http://127.0.0.1/spms/   #模拟10万个请求,每个连接30 并发,也就是总共30万并发


#延时测试
curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" -d "number=16619272&sign=b8aaab58e4d73753430c473ba29756d3" http://127.0.0.1:9093/api/block/blockInfo

#说明:注意两个超时时间:一个是连接超时时间,另一个是数据传输的最大允许时间
-o:把curl 返回的html、js 写到垃圾回收站[ /dev/null]
-s:去掉所有状态
-w:按照后面的格式写出rt
time_namelookup:DNS 解析域名的时间
time_commect:client和server端建立TCP 连接的时间
time_starttransfer:从client发出请求;到web的server 响应第一个字节开始的时间;包括前面的2个时间
time_total:client发出请求;到web的server发送完所有的相应数据并关闭connect的的时间
speed_download:下载数据的速度 单位 byte/s

#模拟客户端超时时间:连接超时:1秒,响应超时5秒
curl --connect-timeout 1 -m 5 -d "number=16619272&sign=b8aaab58e4d73753430c473ba29756d3" http://127.0.0.1:9093/api/block/blockInfo   #如果超时的话,报错如下
curl: (7) Failed connect to 127.0.0.1:9093; Connection refused
#数据传输的最大允许时间超时的话,出错如下:
curl: (28) Operation timed out after 30001 milliseconds with 0 out of -1 bytes received

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羌俊恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值