跳至主要內容

nginx核心配置

知识库集成配置NginxNginx大约 16 分钟

代理服务器:

  • Nginx 的特点:高并发 / 低消耗 / 热部署 / 高可用 / 高扩展
  • 正向代理:隐藏 / 翻墙 / 提速 / 缓存 / 授权
  • 反向代理:保护隐藏 / 分布式路由 / 负载均衡 / 动静分离 / 数据缓存

快速获取 NGINX 的配置

配置高性能、安全、稳定的 NGINX 服务器的最简单方法。open in new window

请求定位

优先级由低到高依次是:普通匹配 < 长路径匹配 < 正则匹配 < 短路匹配 < 精确匹配

  • 普通匹配
location /a {}
  • 长路径匹配
location /a/b/c {}
  • 正则匹配
# ~表示这里是正则表达式,默认匹配是区分大小写
# ~后跟上*号,表示这是不区分大小写的正则表达式
location ~/a {}
location ~*/a {}
  • 短路匹配
# 以^~开头的匹配路径称为短路匹配,表示只要匹配上,就不再匹配其它的了。
location ^~/a/b {}
  • 精确匹配
# 以等号(=)开头的匹配称为精确匹配,其是优先级最高的匹配。
location =/a/b {}

全局模块

  • worker_processes 1
    可选参数:auto,数值

    Nginx 的工作进程数量,其数值一般设置为 CPU 内核数量,或内核数量的整数倍。

    不过需要注意,该值不仅仅取决于 CPU 内核数量,还与硬盘数量及负载均衡模式相关。在不确定时可以指定其值为 auto。
  • worker_cpu_affinity

    worker 进程与具体的内核进行绑定。不过,若指定 worker_processes 的值为 auto,则无法设置 worker_cpu_affinity。

    该值设置是通过二进制进行的。每个内核使用一个二进制位表示,0 代表内核关闭,1 代表内核开启。也就是说,有几个内核,就需要使用几个二进制位。
内核数量worker_processesworker_cpu_affinity说明
2201 10每个进程各使用一个内核
2401 10 01 10每个进程交替使用各自的内核
440001 0010 0100 1000每个进程使用各自的一个内核
420101 1010每个进程使用两个内核。应用于 CPU 进行大量的运算
  • worker_rlimit_nofile

    其默认值与当前 Linux 系统可以打开的最大文件描述符数量相同
# 查看Linux 系统可以打开的最大文件
ulimit -n
# 设置Linux 系统可以打开的最大文件为65535
ulimit -n 65535

events 模块

  • worker_connections 1024

    设置每一个 worker 进程可以并发处理的最大连接数。该值不能超过 worker_rlimit_nofile 的值。
  • accept_mutex on
    • on:默认值,表示当一个新连接到达时,那些没有处于工作状态的 worker 将以串行方式来处理;
    • off:表示当一个新连接到达时,所有的 worker 都会被唤醒,不过只有一个 worker 能获取新连接,其它的 worker 会重新进入阻塞状态,这就是“惊群”现象。
  • accept_mutex_delay 500ms

    设置队首 worker 会尝试获取互斥锁的时间间隔。默认值为 500 毫秒。
  • multi_accept on
    • off:系统会逐个拿出新连接按照负载均衡策略,将其分配给当前处理连接个数最少的 worker。
    • on:系统会实时的统计出各个 worker 当前正在处理的连接个数,然后会按照“缺编”最多的 worker 的“缺编”数量,一次性将这么多的新连接分配给该 worker。
  • use epoll

    设置 worker 与客户端连接的处理方式。Nginx 会自动选择适合当前系统的最高效的方式。

    当然,也可以使用 use 指令明确指定所要使用的连接处理方式。
    user 的取值有以下几种
user 的取值有以下几种:select | poll | epoll | rtsig | kqueue | /dev/poll
select:数组
poll:链表,可处理高并发
epoll:默认使用
kqueue:应用在 BSD 系统上的 epoll。
/dev/poll:UNIX 系统上使用的 poll。

:::

http 模块

  • sendfile on

    设置为 on 则开启 Linux 系统的零拷贝机制,否则不启用零拷贝。

    当然,开启后是否起作用,要看所使用的系统版本。CentOS6 及其以上版本支持 sendfile 零拷贝。
  • tcp_nopush on
    • on:以单独的数据包形式发送 Nginx 的响应头信息,而真正的响应体数据会再以数据包的形式发送,这个数据包中就不再包含响应头信息了。
    • off:默认值,响应头信息包含在每一个响应体数据包中。
  • tcp_nodelay on
    • on:不设置数据发送缓存,即不推迟发送,适合于传输小数据,无需缓存。
    • off:开启发送缓存。若传输的数据是图片等大数据量文件,则建议设置为 off。
  • keepalive_timeout 60

    设置客户端与 Nginx 间所建立的长连接的生命超时时间,时间到达,则连接将自动关闭。单位秒。
  • keepalive_requests 10000

    设置一个长连接最多可以发送的请求数。该值需要在真实环境下测试。
  • client_body_timeout 10

    设置客户端获取 Nginx 响应的超时时限,即一个请求从客户端发出到接收到 Nginx 的响应的最长时间间隔。若超时,则认为本次请求失败。

nginx 缓存配置

Nginx 具有很强大的缓存功能,可以对请求的 response 进行缓存,起到类似 CDN 的作用,甚至有比 CDN 更强大的功能。同时,Nginx 缓存还可以用来“数据托底”,即当后台 web 服务器挂掉的时候,Nginx 可以直接将缓存中的托底数据返回给用户。此功能就是 Nginx 实现“服务降级”的体现。
Nginx 缓存功能的配置由两部分构成:全局定义与局部定义。

  • http{}模块的缓存全局定义

    • proxy_cache_path

      用于指定 Nginx 缓存的存放路径及相关配置。

      proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m inactive=2h max_size=5g use_temp_path=off;
      
          proxy_cache_path 缓存文件路径
          levels 设置缓存文件目录层次;levels=1:2 表示两级目录
          keys_zone 设置缓存名字和共享内存大小
          inactive 在指定时间内没人访问则被删除
          max_size 最大缓存空间,如果缓存空间满,默认覆盖掉缓存时间最长的资源。
          use_temp_path=off 直接写入到缓存文件
          ```
      
      
    • proxy_temp_path

      指定 Nginx 缓存的临时存放目录。若 proxy_cache_path 中的 use_temp_path 设置为了 off,则该属性可以不指定。

  • location{}模块的缓存局部定义

    • proxy_cache mycache

      指定用于存放缓存 key 内存区域名称。其值为 http{}模块中 proxy_cache_path 中的 keys_zone 的值。
    • proxy_cache_key hostrequest_uri$arg_age

      指定 Nginx 生成的缓存的 key 的组成。
    • proxy_cache_bypass $arg_age

      指定是否越过缓存。
    • proxy_cache_methods GET HEAD

      指定客户端请求的哪些提交方法将被缓存,默认为 GET 与 HEAD,但不缓存 POST。
    • proxy_no_cache $aaa $bbb $ccc

      指定对本次请求是否不做缓存。只要有一个不为 0,就不对该请求结果缓存。
    • proxy_cache_purge $ddd $eee $fff

      指定是否清除缓存 key。
    • proxy_cache_lock on

      指定是否采用互斥方式回源。
    • proxy_cache_lock_timeout 5s

      指定再次生成回源互斥锁的时限。
    • proxy_cache_valid 5s

      对指定的 HTTP 状态码的响应数据进行缓存,并指定缓存时间。默认指定的状态码为 200,301,302。
    • proxy_cache_use_stale http_404 http_500

      设置启用托底缓存的条件。而一旦这里指定了相应的状态码,则前面 proxy_cache_calid 中指定的相应状态码所生成的缓存就变为了“托底缓存”。
    • expires 3m

      为请求的静态资源开启浏览器端的缓存。
http{
  # 设置缓存的目录,并且内存中缓存区名为hot_cache,大小为128m,
  # 三天未被访问过的缓存自动清楚,磁盘中缓存的最大容量为2GB。
  proxy_cache_path /soft/nginx/cache levels=1:2 keys_zone=hot_cache:128m inactive=3d max_size=2g;

  server{
    location / {
      # 使用名为nginx_cache的缓存空间
      proxy_cache hot_cache;
      # 对于200、206、304、301、302状态码的数据缓存1天
      proxy_cache_valid 200 206 304 301 302 1d;
      # 对于其他状态的数据缓存30分钟
      proxy_cache_valid any 30m;
      # 定义生成缓存键的规则(请求的url+参数作为key)
      proxy_cache_key $host$uri$is_args$args;
      # 资源至少被重复访问三次后再加入缓存
      proxy_cache_min_uses 3;
      # 出现重复请求时,只让一个去后端读数据,其他的从缓存中读取
      proxy_cache_lock on;
      # 上面的锁超时时间为3s,超过3s未获取数据,其他请求直接去后端
      proxy_cache_lock_timeout 3s;
      # 对于请求参数或cookie中声明了不缓存的数据,不再加入缓存
      proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
      # 在响应头中添加一个缓存是否命中的状态(便于调试)
      add_header Cache-status $upstream_cache_status;
    }
  }
}

缓存清理

当缓存过多时,如果不及时清理会导致磁盘空间被“吃光”,因此我们需要一套完善的缓存清理机制去删除缓存,在之前的 proxy_cache_path 参数中有 purger 相关的选项,开启后可以帮我们自动清理缓存,但遗憾的是:purger 系列参数只有商业版的 NginxPlus 才能使用,因此需要付费才可使用。

不过天无绝人之路,我们可以通过强大的第三方模块 ngx_cache_purge 来替代,先来安装一下该插件:

mkdir -p ~/app/cache_purge && cd ~/app/cache_purge
wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
tar -xvzf 2.3.tar.gz
cd ~/app/nginx
./configure --prefix=/user/local/nginx/ --add-module=~/app/cache_purge/ngx_cache_purge-2.3/
make

第三方缓存清除模块 ngx_cache_purge 就安装完成了,接下来稍微修改一下 nginx.conf 配置,再添加一条 location 规则:

location ~ /purge(/.*) {
  # 配置可以执行清除操作的IP(线上可以配置成内网机器)
  # allow 127.0.0.1; # 代表本机
  allow all; # 代表允许任意IP清除缓存
  proxy_cache_purge $host$1$is_args$args;
}

然后再重启 Nginx,接下来即可通过http:127.0.0.1:80//xxx/purge/xx的方式清除缓存。

Nginx 变量

  • 自定义变量
set $aaa "hello";
set $bbb 0;
  • 内置变量
$args                   请求中的参数;
$binary_remote_addr     远程地址的二进制表示
$body_bytes_sent        已发送的消息体字节数
$content_length         HTTP 请求信息里的"Content-Length"
$content_type           请求信息里的"Content-Type"
$document_root          针对当前请求的根路径设置值
$document_uri           与$uri 相同
$host                   请求信息中的"Host",如果请求中没有 Host 行,则等于设置的服务器名;
$http_cookie            cookie 信息
$http_referer           来源地址
$http_user_agent        客户端代理信息
$http_via               最后一个访问服务器的 Ip 地址
$http_x_forwarded_for   相当于网络访问路径。
$limit_rate             对连接速率的限制
$remote_addr            客户端地址
$remote_port            客户端端口号
$remote_user            客户端用户名,认证用
$request                用户请求信息
$request_body           用户请求主体
$request_body_file      发往后端的本地文件名称
$request_filename       当前请求的文件路径名
$request_method         请求的方法,比如"GET"、"POST"等
$request_uri            请求的 URI,带参数
$server_addr            服务器地址,如果没有用 listen 指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费)
$server_name            请求到达的服务器名
$server_port            请求到达的服务器端口号
$server_protocol        请求的协议版本,"HTTP/1.0"或"HTTP/1.1"
$uri                    请求的 URI,可能和最初的值有不同,比如经过重定向之类的

反向代理

  • client_max_body_size 100k;

    Nginx 允许客户端请求的单文件最大大小,单位字节。
  • client_body_buffer_size 80k;

    Nginx 为客户端请求设置的缓存大小。
  • proxy_buffering on

    开启从后端被代理服务器的响应内容缓冲区。默认值 on。
  • proxy_buffers 4 8k;

    该指令用于设置缓冲区的数量与大小。从被代理的后端服务器取得的响应内容,会缓
    存到这里。
  • proxy_busy_buffers_size 16k;

    高负荷下缓存大小,其默认值为一般为单个 proxy_buffers 的 2 倍。
  • proxy_connect_timeout 60s;

    Nginx 跟后端服务器连接超时时间。默认 60 秒。
  • proxy_read_timeout 60s;

    Nginx 发出请求后等待后端服务器响应的最长时限。默认 60 秒。

负载均衡

  • 轮询

    默认的负载均衡策略,其是按照各个主机的权重比例依次进行请求分配的。
upstream backserver {
    server 192.16.18.101 weight=1 fail_timeout=20 max_fails=3;
    server 192.16.18.102 weight=2 fail_timeout=20 max_fails=3;
    server 192.16.18.103 backup;
    server 192.16.18.104 down;
}
# backup:表示当前服务器为备用服务器。
# down:表示当前服务器永久停机。
# fail_timeout:表示当前主机被 Nginx 认定为停机的最长失联时间,默认为 10 秒。常与max_fails 联合使用。
# max_fails:表示在 fail_timeout 时间内最多允许的失败次数。
 
 
 
 
 
 




  • ip_hash

    指定负载均衡器按照基于客户端 IP 的分配方式
upstream backserver {
    ip_hash;
    server 192.16.18.101 weight=1 fail_timeout=20 max_fails=3;
    server 192.16.18.102 weight=2 fail_timeout=20 max_fails=3;
}

# 对于该策略需要注意以下几点:
# 在 nginx1.3.1 版本之前,该策略中不能指定 weight 属性。
# 该策略不能与 backup 同时使用。
# 此策略适合有状态服务,比如 session。
# 当有服务器宕机,必须手动指定 down 属性,否则请求仍是会落到该服务器。
 
 
 
 
 






  • least_conn

    把请求转发给连接数最少的服务器
upstream backserver {
    least_conn;
    server 192.16.18.101 weight=1 fail_timeout=20 max_fails=3;
    server 192.16.18.102 weight=2 fail_timeout=20 max_fails=3;
}
 
 
 
 
 
  • fair(第三方)

    按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
    fair;
    server localhost:8080;
    server localhost:8081;
}

 



  • url_hash(第三方)

    按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,后端服务器为缓存时比较有效。
upstream backend {
    hash $request_uri;
    hash_method crc32;
    server localhost:8080;
    server localhost:8081;
}

 
 



虚拟主机配置

upstreams.conf
cat >> /usr/local/software/nginx/conf/upstreams.conf <<EOF
upstream www.68.com {
  server tomcatOS:8081 weight=1;
  server tomcatOS:8082 weight=1;
}
upstream bj.68.com {
  server tomcatOS:8083 weight=1;
  server tomcatOS:8084 weight=1;
}
upstream sh.68.com {
  server tomcatOS:8085 weight=1;
  server tomcatOS:8086 weight=1;
}
EOF
vhosts.conf
cat >> /usr/local/software/nginx/conf/vhosts.conf <<EOF
server {
    listen 80;
    server_name www.68.com;
    location / {
        proxy_pass http://www.68.com
    }
}
server {
    listen 80;
    server_name bj.68.com;
    location / {
        proxy_pass http://bj.68.com
    }
}
server {
    listen 80;
    server_name sh.68.com;
    location / {
        proxy_pass http://sh.68.com
    }
}
EOF
  worker_processes  1;
  events {
      worker_connections  1024;
  }
  http {
      include /usr/local/software/nginx/conf/upstreams.conf;
      include /usr/local/software/nginx/conf/vhosts.conf;
      server {
          ...
      }
  }





 
 





Nginx 性能调优
## 零拷贝(Zero Copy)
- 传统的拷贝方式
- Gather Copy DMA 零拷贝方式
- mmap 零拷贝
## 多路复用器 select|poll|epoll
- select<br/>
select 多路复用器是采用轮询的方式,一直在轮询所有的相关内核进程,查看它们的进程状态。若已经就绪,则马上将该内核进程放入到就绪队列。否则,继续查看下一个内核进程状态。在处理内核进程事务之前,app 进程首先会从内核空间中将用户连接请求相关数据复制到用户空间。<br/>
该多路复用器的缺陷有以下几点:
  - 对所有内核进程采用轮询方式效率会很低。因为对于大多数情况下,内核进程都不属于
就绪状态,只有少部分才会是就绪态。所以这种轮询结果大多数都是无意义的。
  - 由于就绪队列底层由数组实现,所以其所能处理的内核进程数量是有限制的,即其能够
处理的最大并发连接数量是有限制的。
  - 从内核空间到用户空间的复制,系统开销大。
- poll<br/>
poll 多路复用器的工作原理与 select 几乎相同,不同的是,由于其就绪队列由链表实现,所以,其对于要处理的内核进程数量理论上是没有限制的,即其能够处理的最大并发连接数量是没有限制的(当然,要受限于当前系统中进程可以打开的最大文件描述符数 ulimit,后面会讲到)。
- epoll<br/>
epoll 多路复用是对 select 与 poll 的增强与改进。其不再采用轮询方式了,而是采用回调方式实现对内核进程状态的获取:一旦内核进程就绪,其就会回调 epoll 多路复用器,进入到多路复用器的就绪队列(由链表实现)。所以 epoll 多路复用模型也称为 epoll 事件驱动模型。<br/>
另外,应用程序所使用的数据,也不再从内核空间复制到用户空间了,而是使用 mmap零拷贝机制,大大降低了系统开销。<br/>
当内核进程就绪信息通知了 epoll 多路复用器后,多路复用器就会马上对其进行处理,将其马上存放到就绪队列吗?不是的。根据处理方式的不同,可以分为两种处理模式:LT模式与 ET 模式。
  - LT (Level Triggered)<br/>
水平触发模式。<br/>即只要内核进程的就绪通知由于某种原因暂时没有被 epoll 处理,则该内核进程就会定时将其就绪信息通知 epoll。直到 epoll 将其写入到就绪队列,或由于某种原因该内核进程又不再就绪而不再通知。其支持两种通讯方式:BIO 与
NIO。
  - ET (Edge Triggered)<br/>
边缘触发模式。其仅支持 NIO 的通讯方式。<br/>当内核进程的就绪信息仅会通知一次 epoll,无论 epoll 是否处理该通知。明显该方式的效率要高于 LT 模式,但其有可能会出现就绪通知被忽视的情况,即连接请求丢失的情况。

## Nginx 的并发处理机制
一般情况下并发处理机制有三种:多进程、多线程,与异步机制。<br/>
Nginx 对于并发的处理同时采用了三种机制。当然,其异步机制使用的是异步非阻塞方式。<br/>
我们知道 Nginx 的进程分为两类:master 进程与 worker 进程。每个 master 进程可以生成多个 worker 进程,所以其是多进程的。每个 worker 进程可以同时处理多个用户请求,每个用户请求会由一个线程来处理,所以其是多线程的。<br/>
那么,如何解释其“异步非阻塞”并发处理机制呢?<br/>
worker 进程采用的就是 epoll 多路复用机制来对后端服务器进行处理的。当后端服务器返回结果后,后端服务器就会回调 epoll 多路复用器,由多路复用器对相应的 worker 进程进行通知。此时,worker 进程就会挂起当前正在处理的事务,拿 IO 返回结果去响应客户端请求。响应完毕后,会再继续执行挂起的事务。这个过程就是“异步非阻塞”的。

跨域问题

## 前端网站地址:http://localhost:8080
## 服务端网址:http://localhost:59200
server {
  listen       22222;
  server_name  localhost;
  location  / {
    # 允许跨域的请求,可以自定义变量$http_origin,* 表示所有
    add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
    # 允许请求时携带的头部信息,*表示所有
    add_header Access-Control-Allow-Headers '*';
    # 允许跨域请求的方法:GET,POST,OPTIONS,PUT
    # add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS,PUT';
    add_header Access-Control-Allow-Methods '*';
    # 允许携带cookie请求
    add_header Access-Control-Allow-Credentials 'true';
    # 允许发送按段获取资源的请求
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain; charset=utf-8';
      add_header 'Content-Length' 0;
      # 对于Options方式的请求返回204,表示接受跨域请求
      return 204;
    }
    proxy_pass  http://localhost:59200; 
  }
}