P
u
r
v
i
s

Nginx 介绍、部署及性能优化

本文主要内容:

1、Nginx 简介

2、Nginx 搭建及生产环境配置

3、Nginx 性能调优

 

一、Nginx 简介

正向代理和反向代理

正向代理: 客户端非常明确要访问的服务器地址,它代理客户 端,替客户端发出请求。比如:FQ (警告⚠️:FQ操作违反相关法律规定,本篇文章仅供 学习参考,切勿盲目FQ)。

 

反向代理: 均衡分工,控制流量,避免出现局部节点负载过大。 反向代理隐藏了服务器的信息,它代理的是服务器端, 代其接收请求。 换句话说,反向代理的过程中,客户端并不知道具体是 哪台服务器处理了自己的请求。如此一来,既提高了访 问速度,又为安全性提供了保证。

什么是 Nginx ?

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好。

注:Nginx 实际代表的是 engine-x,其音标为:/'endʒɪneks/ 

Nginx 与Apache性能对比

160 million 个站点在 NGINX 上运行

51% 前 10,000 个访问量最大的网站Nginx 占比

36% 的亚马逊网络服务运行着Nginx

 

二、Nginx 搭建及生产环境配置

Nginx 编译安装

$ yum -y install gcc gcc-c++                              # 下载gcc编译器
$ yum -y install pcre-devel openssl-devel                 # 下载PCRE
$ wget http://nginx.org/download/nginx-1.21.1.zip         # 下载nginx,官方网站是 http://nginx.org ,自己
                                                          # 找到需要的版本,右键复制下载链接
$ tar -zxvf nginx-1.19.2.tar.gz                           # 解压
$ cd nginx-1.19.2
$ ./configure --prefix=/opt/nginx \                       # 生成makefile
    --with-http_stub_status_module \                      # 使用./configure --help查看各个模块的使用情况
    --with-http_ssl_module                                # 使用--with-http_perl_modules方式安装需要的模块
$ make && make install                                    # 编译安装
$ cd /opt/nginx                                           # 进入到安装目录
$ ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/      # 将 /usr/local/nginx/sbin/nginx 软连接
                                                          # 到 /usr/local/sbin 下,就可以在任意地方使用nginx命令

Nginx 系统服务配置

cat > /usr/lib/systemd/system/nginx.service << NGINX_CONF
[Unit]
Description=The NGINX HTTP and reverse proxy server
Documentation=http://nginx.org/en/docs/
Wants=network-online.target

[Service]
Type=forking
PIDFile=${nginx_dir}/logs/nginx.pid
ExecStartPre=${nginx_dir}/sbin/nginx -t
ExecStart=${nginx_dir}/sbin/nginx
ExecReload=${nginx_dir}/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT \$MAINPID

[Install]
WantedBy=multi-user.target
NGINX_CONF
# Nginx system 配置
$ systemctl daemon
-reload $ systemctl enable nginx $ systemctl stop nginx $ systemctl start nginx $ systemctl reload nginx

Nginx 动态负载配置

Nginx 动态负载及高可用

Nginx高并发处理原理

进程模型采用Master/Worker 方式。当 nginx 启动的时候,会创建一个 Master 进程,Master进程会根据nginx.conf配置文件中相应的配置项来fork出多个worker子进程去处理请求(怎么处理也是根据配置文件中相应的配置文件)。

​ Master进程负责管理Worker进程的生命周期、处理网络事件、接收外界信号等。由于Master进程可以fork出多个Worker进程,所以说Nginx是多进程的。

 

 

 

 

 

 

 

 

 



 

 

     

 

 

 

 

   

        异步处理模式是指nginx处理请求的时候是采用I/O多路复用技术(select | poll | epoll 模型),即多个 I/O 可以复用一个进程。当 worker 进程接收到客户端的请求后,会调用服务端对其请求进行处理,如果没有立即得到响应结果, worker 进程没有阻塞,而是去处理其他请求,知道有请求被服务端处理完成并返回响应结果。
​        这里的 worker 进程默认就是采用 epoll 多路复用机制来对服务端进行处理的。当服务端返回响应结果时,回调 epoll 多路复用器,epoll 告知 worker 进程,worker 会挂起当前正在处理的线程,去获取响应结果返回客户端,完成后再去执行被挂起的线程。整个过程中不会出现等待的情况,所以理论上Ngnix的一个进程就可以处理无限数量的连接,而且无需轮询。

​注:worker 进程接收客户端请求不是采用的 epoll 模型,而是互斥锁机制;只有对服务端的请求和响应采用的是 epoll 模型。

Nginx的特点 – 高并发

$ ulimit –a                             # 查看当前会话中的linux核心配置,只需要关注open file
$ ulimit –n                             # 查看系统的“进程最大可打开文件数的设置”,默认时1024
vim /etc/security/limit.conf            # 修改“进程最大可打开文件数的设置”
#添加下面两行
    soft nofile 65535                   # 应用软件级别限制的最大可打开文件数的限制
    hard nofile 65535                   # 操作系统级别限制的最大可打开文件数的限制
$ ulimit -n 65535                       # 文件保存后不会马上生效,所以还得更改当前会话级别的配置
# 修改nginx配置文件(下面两行) 
$ vim /src/local/nginx/conf/nginx.conf
worker_rlimit_nofile 65535;             # 这行,看这里看这里
events {
    use epoll;
    worker_connections 65535;           # 这行,看这里看这里
}
$ nginx -s reload                       # 热部署重新加载配置文件

要知道,在linux的世界里,一切皆文件.因此要实现大的并发量的第一步,修改linux系统的文件标识符限制数,,也就是文件打开数量的限制

Nginx的特点 – 热部署

$ nginx -s reload

1、当上面的命令一执行,如果发现配置文件已更改,会创建一个新的主进程
2、当前所有的worker进程不会再接收新的请求并把当前正在处理的请求执行完就关闭
3、master主进程会创建新的worker进程来接收并处理新的请求

Nginx的特点 – 模块化

$ git clone https://github.com/agentzh/echo-nginx-module 
#放入指定位置
$ mv echo-nginx-module-master /opt/nginx/echo-nginx-module
$ ./configure                                                   #就用这个命令生成新的makefile
    --prefix=/opt/nginx \
    --with-http_stub_status_module \
    --with-http_ssl_module \
    --add-module=/opt/nginx/echo-nginx-module
$ make                                                          # 编译(这里只需要make,一定不要执行make install,
                                                                # 不然会被覆盖)
$ cp /opt/nginx/sbin/nginx /opt/nginx/sbin/nginx.bak            #备份原文件
$ cp /opt/nginx/objs/nginx /opt/nginx/sbin/nginx
$ ln -s /opt/nginx/sbin/nginx /opt/bin/nginx                    #重新建立软连接,检测配置文件并平滑启动
$ nginx -t
$ nginx -s reload

Nginx的特点

 

低消耗

一万个非活跃性链接,消耗内存仅暂用2.5M

高可用

woker都一个一个的进程,就算其中某个进程挂掉了,也对其他的进程没得影响,而且其他的进程会接替出问题的进程。

Nginx 的整体结构

 

 

 

 

 

  

全局块

配置影响nginx的全局指令。包括:

  • 配置运行nginx的服务器用户组
  • worker process数
  • nginx进程
  • pid存放路径
  • 错误日志存放路径
  • 配置文件的引入

events块

配置影响nginx服务器或与用户的网络连接。包括:

  • 设置网络连接的序列化(惊群)
  • 是否允许同时接收多个网络连接
  • 选择事件驱动模型
  • 设置最大连接数

http块

可以嵌套多个server模块,配置代理、缓存、日志定义等和第三方模块的配置。包括:

  • 定义MIMI-Type
  • 自定义服务日志格式
  • 允许sendfile方式传输文件
  • 连接超时时间
  • 单连接请求数上限

server块

配置虚拟主机相关参数。包括:

  • 配置网络监听
  • 配置基于名称的虚拟主机
  • 配置基于IP的虚拟主机

location块

配置请求的路由,以及页面和其他静态资源的处理。包括:

  • Location配置
  • 请求根目录配置更改
  • URL
  • 网站默认首页配置

Nginx Location 匹配

 

 

匹配顺序:

1. 首先精确匹配 =

2. 其次最佳匹配 ^~

3. 其次是按文件中顺序的正则匹配

4. 然后匹配不带任何修饰的前缀匹配

5. 最后是交给 / 通用匹配

6. 当有匹配成功时候,停止匹配,按当前匹配规则处理请求

注意:前缀匹配,如果有包含关系时,按最大匹配原则进行匹配。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

访问根目录 /,比如 http://localhost/ 将匹配 规则A

访问 http://localhost/login 将匹配 规则B,http://localhost/register 则匹配 规则F

访问 http://localhost/static/a.html 将匹配 规则C

访问 http://localhost/static/files/a.exe 将匹配 规则X,虽然 规则C 也能匹配到,但因为最大匹配原则,最终选中了 规则X。你可以测试下,去掉规则 X ,则当前 URL 会匹配上 规则C。

访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配 规则D 和 规则 E ,但是 规则 D 顺序优先,规则 E 不起作用,而 http://localhost/static/c.png 则优先匹配到 规则 C

访问 http://localhost/a.PNG 则匹配 规则 E ,而不会匹配 规则 D ,因为 规则 E 不区分大小写。

访问 http://localhost/img/a.gif 会匹配上 规则D,虽然 规则Y 也可以匹配上,但是因为正则匹配优先,而忽略了 规则Y。

访问 http://localhost/img/a.tiff 会匹配上 规则Y。

访问 http://localhost/category/id/1111 则最终匹配到规则 F ,因为以上规则都不匹配,这个时候应该是 Nginx 转发请求给后端应用服务器,比如 FastCGI(php),tomcat(jsp),Nginx 作为反向代理服务器存在。

 

三、Nginx 性能调优

全局模块下的 调优

max_clients = worker_processes * worker_connections;

$ vim /opt/nginx/conf/nginx.conf

worker_processes auto;              # 设置进程数
worker_cpu_affinity 01 10;          # 设置内核数量以及进程使用内核情况
worker_rlimit_nofile 65535;         # 可打开最大文件数

worker_processes
​worker的进程数,该值一般设置为CPU内核数,或者内核的整倍数。不仅仅取决于CPU内核数,也与磁盘数量和负载均衡模式有关系,在不知道怎么做的时候可以设置为auto。
worker_cpu_affinity
​将worker进程与cpu内核进行绑定,该配置是以多位二进制数进行设置。
worker_rlimit_nofile
设置一个worker进程最大能打开的文件数。默认值与当前linux系统的设置的最大能打开的文件描述符一致。

events模块下的调优

I/O 多路复用

select vs. poll vs. epoll/kqueue

其中select和poll都是标准的工作模式,

kqueue和epoll是高效的工作模式,
不同的是epoll用在Linux平台上,kqueue用在BSD系统中。

对于Linux系统Linux2.6+的内核,推荐选择epoll工作模式,这是高性能高并发的设置

https://programmer.help/blogs/introduction-to-select-poll-epoll-i-o-multiplexing.html
https://nima101.github.io/io_multiplexing

$ vim /opt/nginx/conf/nginx.conf
events {
    use epoll;                          # 设置worker进程与客户端的连接方式(事件驱动模型)
    worker_connections  1024;           # 设置worker进程最大的连接数,默认为512
    accept_mutex on;                    # 设置网路连接序列化,防止惊群现象发生,默认为on
    accept_mutex_delay 500ms;
    multi_accept on;                    # 设置一个进程是否同时接受多个网络连接,默认为off
}

https 模块下的调优

http {
    ...
    sendfile    on;                      # 开启高效文件传输模式
    tcp_nopush     on;                   # 防止网络阻塞
    tcp_nodelay     on;                  # 设置数据发送缓存
    client_max_body_size 10m;            # 最大允许上传的文件大小根据业务需求来设置
    keepalive_timeout  65;               # 设置客户端与Nginx间所建立的长连接
                                         # 的生命超时时间,时间到达,
                                         # 则连接将自动关闭。单位秒
    keepalive_requests  2000;            # 设置一个长连接发出最多的请求数
    ...
}

Sendfile
参数用于开启文件的高效传输模式。同时将tcp_nopush和tcp_nodelay两个指令设置为on,可防止网络及磁盘I/O阻塞,提升Nginx工作效率。
tcp_nopush
设置是否将nginx的响应头单独发送,如果开启:则会以单独的形式发送nginx的响应头,而真实的响应体数据会在单独以数据包的形式发送;如果关闭:则会将nginx的响应头和真实的响应体数据一起发送,每个响应都会包含。
tcp_nodelay
设置数据发送缓存,如果开启:不设置数据发送缓存,适合传输小数据;如果关闭:开启数据发送缓存,如果传输图片等大文件,建议设置为 off。
client_body_timeout
设置客户端获取响应的超时时间。如果超时了 ,则认为请求失败。可根据此值得设置来做接口的简单小压测,并且 可设置一个合理的值,保证请求响应的最优。
keepalive_timeout
设置连接活跃时间,如果超时则断开连接。若设置为0,则表示禁止keepalive连接。如果传输的数据量小,且系统运算量很小,则可以将该值设置小一些;反之。
keepalive_requests
​设置一个长连接发送请求的最大数。如果当前系统并发量大,而如果 该值 设置很小,则会导致keepalive_timeout 时间还未到,但是keepalive_requests上限已经到了。故我们需要根据真实系统并发量和连接活跃时间来设置该值。

 

http {
    ...
    # 将当前目录(conf 目录)中的 mime.types 文件包含进来
    include       mime.types;
    include /opt/nginx/vhost.d/*.conf;
    server {
        ...
        include /opt/nginx/upstream/*.conf;
        ...
        upstream {
            ...
            include /opt/nginx/upstream/xxx.1hai.cn.conf;
            ...
        }
        ...
    }
http {
    ...

    charset utf-8;      # 设置请求与响应的字符编码

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    log_format  postdata  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                                          ' $request_body'
                      '"$http_user_agent" "$http_x_forwarded_for"';
    # 开启访问日志,存放路径为logs/access.log,以log_format  main格式存放
    access_log  logs/access.log  main;
    ...
}

Nginx 日志切割

$ cat /etc/logrotate-daily
/opt/nginx/logs/*.log
{
    rotate 4
    daily
    dateext
    dateformat .%Y%m%d
    compress
    missingok
    notifempty
    copytruncate
    sharedscripts
}

为什么要做日志切割?

因为随时系统访问量的增长,访问日志里会出现越来越多的数据,如果不去按照时间去做合理的日志切割,访问日志里的数据多到无法打开的地步,所以需要做日志切割。

logrotate的行为也是受crontab控制,在/etc/cron.daily目录下。

而crontab任务是受anacron控制,在/etc/anacron文件中配置。

Nginx Gzip 压缩

http {
    ...
    gzip  on;     # 开启gzip压缩
    # 用来指定压缩的类型
    gzip_types application/atom+xml
        application/javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rss+xml
        xxx...;

    gzip_comp_level 2;
    ...
}

gzip_comp_level

压缩比率。
用来指定gzip压缩比,1压缩比最小,处理速度最快;
9压缩比最大,传输速度快,但处理最慢,也比较消耗CPU资源

Nginx gzip压缩功能介绍
Nginx gzip压缩模块提供了压缩文件内容的功能,用户请求的内容在发送到用户客户端之前,Nginx服务器会根据一些具体的策略实施压缩策略,以节约网站出口带宽,同时加快数据传输效率,来提升用户访问体验。
Nginx gzip压缩的优点
提升网站用户体验:发送给用户的内容小了,用户访问单位大小的页面就加快了,用户体验提升了,网站口碑就好了
节约网站带宽成本:数据是压缩传输的,因此节省了网站的带宽流量成本,不过压缩时会稍微消耗一些CPU资源,这个一般可以忽略不计
需要和不需要压缩的对象
纯文本内容压缩比很高,因此,纯文本的内容最好进行压缩,例如:html、css、js、xml、shtml等格式的文件
被压缩的纯文本文件必须大于1KB,由于压缩算法的特殊原因,极小的文件压缩后可能反而变大
图片、视频(流媒体)等文件尽量不要压缩,因为这些文件大多都是经过压缩的,如果再压缩很可能不会减小或减小很少,或者可能增大,同事压缩时还会消耗大量的CPU、内存资源

Nginx 提供两种限流方式

一、是控制速率

http {
    ...
    limit_req_zone $binary_remote_addr 
                            zone=myRateLimit:10m rate=10r/s;
    server {
        location / {
            limit_req zone=myRateLimit;
            proxy_pass http://my_upstream;
        }
    }
    ...
}

key:定义限流对象,binary_remote_addr 是一种key,表示基于 remote_addr(客户端IP) 来做限流,binary_ 的目的是压缩内存占用量。
zone:定义共享内存区来存储访问信息, myRateLimit:10m 表示一个大小为10M,名字为myRateLimit的内存区域。1M能存储16000 IP地址的访问信息,10M可以存储16W IP地址访问信息。
rate:用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理一个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。

http {
    ...
    limit_req_zone $binary_remote_addr 
                            zone=myRateLimit:10m rate=10r/s;
    server {
        location / {
            # limit_req zone=myRateLimit burst=20;
            limit_req zone=myRateLimit burst=20 nodelay;
            proxy_pass http://my_upstream;
        }
    }
    ...
}

burst 译为突发、爆发,表示在超过设定的处理速率后能额外处理的请求数。当 rate=10r/s 时,将1s拆成10份,即每100ms可处理1个请求。
此处,burst=20 ,若同时有21个请求到达,Nginx 会处理第一个请求,剩余20个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于21,将拒绝处理多余的请求,直接返回503.
不过,单独使用 burst 参数并不实用。假设 burst=50 ,rate依然为10r/s,排队中的50个请求虽然每100ms会处理一个,但第50个请求却需要等待 50 * 100ms即 5s,这么长的处理时间自然难以接受。
nodelay 针对的是 burst 参数,burst=20 nodelay 表示这20个请求立马处理,不能延迟,相当于特事特办。不过,即使这20个突发请求立马处理结束,后续来了请求也不会立马处理。burst=20 相当于缓存队列中占了20个坑,即使请求被处理了,这20个位置这只能按 100ms一个来释放。
这就达到了速率稳定,但突然流量也能正常处理的效果。

二、是控制并发连接数

http {
    ...
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;

    server {
        ...
        limit_conn perip 10;
        limit_conn perserver 100;
    }
    ...
}

设置白名单

http {
    ...
    geo $limit {
        default 1;
        10.0.0.0/8 0;
        192.168.0.0/24 0;
        172.20.0.35 0;
    }
    map $limit $limit_key {
        0 "";
        1 $binary_remote_addr;
    }
    limit_req_zone $limit_key zone=myRateLimit:10m rate=10r/s;
    ...
}

geo 对于白名单(子网或IP都可以) 将返回0,其他IP将返回1。

map 将 $limit 转换为 $limit_key,如果是 $limit 是0(白名单),则返回空字符串;如果是1,则返回客户端实际IP。

limit_req_zone 限流的key不再使用 $binary_remote_addr,而是 $limit_key 来动态获取值。
如果是白名单,limit_req_zone 的限流key则为空字符串,将不会限流;
若不是白名单,将会对客户端真实IP进行限流。

设置黑名单

$ cat blockip.conf
deny 165.91.122.67;
deny 180.169.22.135;                     #在nginx的安装目录下面,新建屏蔽ip文件,命名为blockip.conf
deny 219.220.141.2;
$ vim nginx.conf
http{
    ...
    include blocksip.conf;               #nginx.conf文件将该配置加入http{}标签末尾
    ...
}
$ nginx -s reload
$ cat blockip.conf                       #如果你想实现这样的应用,除了几个IP外,其他全部拒绝,那需要你在blockip.conf中这样写
allow 1.1.1.1;
allow 1.1.1.2;
deny all;

限制数据传输速度

http {
    ...
    location /flv/ {
        flv;
        limit_rate_after 20m;
        limit_rate       100k;
    }
    ...
}

除限流外,ngx_http_core_module 还提供了限制数据传输速度的能力(即常说的下载速度)。

这个限制是针对每个请求的,
表示客户端下载前20M时不限速,后续限制100kb/s。

posted @ 2022-08-21 22:29  兰purvis  阅读(496)  评论(0编辑  收藏  举报