1. Nginx 是什么

Nginx 是一款高性能的 Web 服务器软件,主要用于提供网上信息浏览服务,为高并发网站的应用场景而设计,可以部署在 Linux、MacOS 和 Windows 等操作系统中,它的优点包括性能高、稳定性好、结构模块化、配置简单以及资源消耗非常低等。拥有 HTTPS 访问、gzip 压缩、虚拟主机和 URL 重写等功能,不但可以搭配 FastCGI 程序处理动态请求,还可以用于代理、反向代理、负载均衡和缓存服务等功能。

2. Nginx 主要功能

2.1 反向代理与负载均衡

  • 正向代理
    一个位于客户端和目标服务器之间的代理服务器,客户端将发送的请求和指定的目标服务器提交给代理服务器,然后代理服务器向目标服务器发起请求,并将获得的响应结果返回给客户端。
  • 反向代理
    反向代理对于客户端而言就是目标服务器,客户端反向代理服务器发送请求后,反向代理服务器将该请求转发给内部网络上的后端服务器,并从后端服务器上得到的响应结果返回给客户端。
  • 负载均衡
    负载均衡是基于反向代理实现的,也就是将负载分摊到多个操作单元上执行,从而提高服务 的可用性和响应速度,给用户更好的体验。
    目前负载均衡有 4 中典型的配置方式,分别为轮询、权重、ip_hash 和利用第三方模块的方式。

配置方式

说明

轮询方式

负载均衡默认的设置方式,每个请求按照时间顺序逐一分配到不同的后端服务器进行处理,如果服务器宕机,会自动剔除。

权重方式

利用 weight 指定轮询的权重比率,与访问率成正比,用于后端服务器性能不均的情况。

ip_hash方式

每个请求按访问 IP 的 hash 结果分配,这样可以使每个访客固定访问一个后端服务器,可以解决 session 共享的问题。

第三方模块

第三方模块采用 fair 时,按每台服务器的响应时间进行分配请求,响应时间短的优先分配;若第三方模块采用 url_hash 时,按照访问 url 的 hash 值来分配请求。

1. 轮询方式

负载均衡默认的设置方式,每个请求按照时间顺序逐一分配到不同的后端服务器进行处理,如果服务器宕机,会自动剔除。

upstream test1 {
  server localhost:8080;
  server localhost:8081;
}

server {
  listen    80;
  server_name localhost;
  client_max_body_size 1024M;
  location / {
      proxy_pass http://test1;
      proxy_set_header Host $host:$server_port;
  }
}
2.权重方式

利用 weight 指定轮询的权重比率,与访问率成正比,用于后端服务器性能不均的情况。

upstream test2 {
  server localhost:8080 weight=9;
  server localhost:8081 weight=1;
}

server {
  listen    80;
  server_name localhost;
  client_max_body_size 1024M;
  location / {
      proxy_pass http://test2;
      proxy_set_header Host $host:$server_port;
  }
}
3.ip_hash 方式

每个请求按访问 IP 的 hash 结果分配,这样可以使每个访客固定访问一个后端服务器,可以解决 session 共享的问题。

upstream test3 {
  ip_hash;
  server localhost:8080;
  server localhost:8081;  
}
server {
  listen    80;
  server_name localhost;
  client_max_body_size 1024M;
  location / {
      proxy_pass http://test3;
      proxy_set_header Host $host:$server_port;
  }
}
4.第三方模块

第三方模块采用 fair 时,按每台服务器的响应时间进行分配请求,响应时间短的优先分配;若第三方模块采用 url_hash 时,按照访问 url 的 hash 值来分配请求。

upstream test4upstream test4 {
  fair;
  server localhost:8080;
  server localhost:8081;
}
server {
  listen 80;
  server_name localhost;
  client_max_body_size 1024M;
  location / {
      proxy_pass http://test4;
      proxy_set_header Host $host:$server_port;
  }
}

2.2 动静分离

Nginx 提供的动静分离是指把动态请求和静态请求分开,合适的服务器处理响应的请求,是整个系统的性能、效率更高。

Nginx 可以根据配置对不同的请求进行不同转发,这是动静分离的基础。静态请求对应的静态资源可以直接放在 Nginx 上做缓冲,更好的做法是放在响应的缓冲服务器上。动态请求由响应的后端服务器处理。

upstream test {
    server localhost:8080;
    server localhost:8081;
}

server {
    listen    80;
    server_name localhost;
    client_max_body_size 1024M;
    location / {
        root    /usr/local/html/;
        index   index.html;
    }
    # 所有静态请求都由 Nginx 处理
    location ~ \.(git|jpg|png|css|js)$ {
        root    /usr/local/html/;
    }
    
    location ~ \.(jsp|do)$ {
        root    /usr/local/html/;
    }
    
    error_page 500 502 503 504  /50x/html;
    location = /50x.html {
        root    /usr/local/html/;
    }
}

3. Nginx 配置详解

Nginx 的配置都写在 nginx.conf 的文件里,从 Nginx 的配置指令作用域来讲,分为 5 个作用于块,分别是:

  • 全局作用于块
  • event 作用域块
  • http 指令作用域块
  • server 指令作用域块
  • location 指令作用域块

3.1 全局作用域块

全局作用域块中配置通用的 Nginx 配置,比如 Nginx 的用户组信息, Nginx 的并发进程数,日志存放位置等。

  • Nginx 的用户组信息配置,用来控制启动 Nginx 的权限;
  • 服务并发一般情况下是越多越好,但当超过硬件的承受范围时会适得其反,所以一般我们会配置为 auto,这样 Nginx 会去检查硬件的信息,启用适当的进程数量。
# Nginx 用户及组: 用户 组。 windows 下不指定
user nginx nginx;

# 工作进程:数目。根据硬件调整,通常等于 CPU 数量或者 2 倍与 CPU。
worker_processes 8;

# 错误日志:存放路径
error_log logs/error.log
error_log logs/error.log notice;
error_log logs/error.log info;

# pid (进程标识符):存放路径
pid logs/nginx.pid;

3.2 event 作用域块

event 作用域块设置 Nginx 处理连接请求,在 event 模块通常会配置进程的连接数量,就是每一个 worker 进程能并发处理的最大连接数。

server 指令作用域块我们可以进行独立项目的代理配置。

events {
    # 每个工作进程的最大连接数量。根据硬件调整,和前面工作进程配合使用,在不使得 CPU 满载(100%)情况下尽可能的大。每个进程允许的最多连接数,理论上每台 Nginx 服务器最大连接数为:worker_processes * worker_connctions
    worker_connections 204800;
    
    # 客户端请求头部的缓冲区大小。这个可以根据系统分页大小来设置,一般一个请求头的大小不会超过 1K,不过由于一般系统分页都要大于 1K,所以这里设置为分页大小。
    # 分页大小可以用命令 getconf PAGESIZE 取得。假设从命令行得到的分页大小为 4096。
    # 当 client_header_buffer_size 超过 4K 的情况,可以将该值设置为 4K 的整数倍数。
    client_header_buffer_size 4K;
    
    # 将为文件制定缓存,默认是没有启用,max 制定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没有被请求后删除缓存。
    open_file_cache max=65535 inactive=60s;
    
    # 多长时间检查一次缓存的有效信息
    open_file_cache_valid 80s;
    
    # 在 inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的。如果文件在 inactive 时间内一次都没有被使用过,则将其从缓存中移除。
    open_file_cache_min_uses 1;
}

3.3 http 指令作用域块

Nginx 的 http 指令作用域块 用于控制 Nginx 的 HTTP 进程。

日志格式设置:

  • remote_addr 与 $http_x_forwarded_for:记录客户端的 ip 地址;
  • $remote_user:记录客户端的用户名称;
  • $time_local:记录访问时间与时区;
  • $request:记录请求的 url 与 http 协议;
  • $status:记录请求状态,成功是200;
  • $body_bytes_sent:记录发送给客户端文件主题内容大小;
  • $http_referer:记录从哪个页面链接访问过来的;
  • $http_user_agent:记录客户浏览器的相关信息;

通常 web 服务器放在反向代理的后面,这样就不能获取到客户端的 IP 地址,通过 $remote_addr 拿到的 IP 地址是反向代理服务器的 IP 地址。反向代理服务器在转发请求的 http 头信息中,可以增加 x_forwarded_for 信息,用以记录原有客户端的 IP 地址和原来客户端请求的服务器地址。

# 设定 http 服务器,利用它的反向代理功能提供负载均衡支持
http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$htto_x_forwarded_for"';
    log_format log404 '$status [$time_local] $remote_addr $host$request_uri $sent_http_location';

    # 用了 log_format 指令设置了日志格式之后,需要用 access_log 指令指定日志文件的存放路径;
    access_log logs/host.access.log main;
    access_log logs/host.access.404.log log404;

    # 客户端请求头部的缓冲区大小。可以参见 event 作用域块中的说明。
    client_header_buffer_size 4k;

    # 客户端请求头最大缓冲大小和数量。Nginx 默认会用 client_header_buffer_size 这个 buffer 来读取 header 值,如果 header 过大,则会使用 large_client_header_buffers 来读取。
    large_client_header_buffers 8 128k;

    # 指定缓存是否启用。
    open_file_cache max=102400 inactive=20s;

    # 何时需要检查 open_file_cache 中缓存项目的有效信息
    open_file_cache_valid 30s;

    # 在缓存参数 inactive 时间内文件使用的最少次数,若使用次数大于该值,则文件描述符在缓存中处于打开状态。
    open_file_cache_min_uses 2;

    # 指定是否在搜索一个文件时记录 cache 错误 [open_file_cache_errors on | off]
    open_file_cache_errors on;

    # 设定通过 Nginx 上传文件的大小
    client_max_body_size 300m;

    # 指定 Nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为 on。如果用来进行下载等应用磁盘 IO 重负载应用,可设置为 off,以平衡磁盘与网络 IO 处理速度,降低系统 uptime。
    sendfile on;
    # 此选项允许或禁止使用 socket 的 TCP_CORK 的选项,此选项仅在 sendfile 的时候使用
    tcp_nopush on;

    # 后端服务器连接的超时时间(发起握手等候响应超时时间)
    proxy_read_timeout 180;

    # 后端服务器数据回传时间(在规定时间之内后端服务器必须传完所有的数据)
    proxy_send_timeout 180;

    # 设置从被代理服务器读取的第一部分应答的缓冲区大小
    proxy_buffer_size 256k;

    # 设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,默认情况也为分页大小
    proxy_buffer 4 256k;
    proxy_busy_buffer_size 256k;

    # 设置在写入 proxy_temp_path 时数据的大小,预防一个工作进程在传递文件时阻塞太长
    proxy_temp_file-write_size 256k;

    # proxy_temp_path 和 proxy_cache_path 指定路径必须在同一分区
    proxy_temp_path /data0/proxy_temp_dir;
    # 设置内存缓存空间大小为 200MB,1天没有被访问的内容自动清除,硬盘缓存空间大小为 30GB
    proxy_cache_path /data0/proxy_cache_dir levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=30g;

    # 客户端请求服务器的最大允许大小
    client_body_buffer_size 512k;

    # 表示 Nginx 阻止 HTTP 应答代码为 400 或者更高的应答。
    proxy_intercept_errors on;

    # 负载均衡
    upstream backend {
        server server1;
        server server2;
    }
}

3.4 server 指令作用域块和 location 指令作用域块

# 配置虚拟机
server {
    # 配置监听端口
    listen 80;
    
    # 配置访问域名
    server_name image.***.com;
    
    # 对以 mp3/exe 结尾的地址进行负载均衡
    location ~* \.(mp3|exe)$ {
        # 设置被代理服务器的端口或套接字,以及 URL
        proxy_pass http://img_relay$request_uri;
        
        # 将代理服务器收到的用户信息传到真实的服务器上
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    location /face {
        if($http_user_agent ~* "xnp") {
            rewrite ^(.*)$ http://127.0.0.1:8080/face.jpg redirect;
        }
        # 将代理服务器收到的用户信息传到真实的服务器上
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        error_page 404 502 = @fetch;
    }
    
    location @fetch {
        access_log /data/logs/face.log log404;
        rewrite ^(.*)$ http://127.0.0.1:8080/face.jpg redirect;
    }
    
    location /image {
        if($http_user_agent ~* "xnp") {
            rewrite ^(.*)$ http://127.0.0.1:8080/face.jpg redirect;
        }
        proxy_pass http://img_relay$request_uri;
        
        # 将代理服务器收到的用户信息传到真实的服务器上
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        error_page 404 502 = @fetch;
    }
}

location 匹配规则说明:

  • ~:表示执行一个正则匹配,区分大小写
  • ~*:表示执行一个正则匹配,不区分大小写
  • ^~:表示普通字符串匹配,如果该选项匹配,只匹配该选项,不匹配别的选项(一般用来匹配目录)
  • @:定义一个命名的 location,在内部定向时使用,例如 error_page,try_files

优先级顺序: 精确匹配 > 正则匹配 > 部分匹配 > 通用匹配

(location = ) > (location 完整路径) > (location ^~ 路径) > (location ~ | ~* 正则匹配) > (location 部分起始路径) > (location /)

# location =
location = / {
    # 精确匹配 /,主机名后面不能带任何字符串
    [ configuration A ]
}

# location /
location / {
    # 所有地址都是以 / 开头,因此匹配所有请求
    [ configuration B ]
}

# location 部分起始路径
location /documents/ {
    # 匹配任何以 /documents/ 开头的地址
    [ configuration C ]
}

#location ^~ 路径
location ^~ /images/ {
    # 匹配任何以 /images/ 开头的地址
    [ configuration D ]
}

#location ~ 正则匹配
location ~ /documents/Abc {
    # 匹配包含 /documents/Abc 的地址(区分大小写)
    [ configuration CC ]
}

# location ~* 正则匹配
location ~* \.(gif|jpg|jpeg)$ {
    # 匹配所有以 gif,jpg或jpeg 结尾的请求(不区分大小写)
    [ configuration E ]
}

location /images/ {
    [ configuration F ]
}

location /images/abc {
    [ configuration G ]
}

# location ~* 正则匹配
location ~* /js/.*\.js {
    # 匹配 /js/[anychars].js (不区分大小写)
    [ configuration H ]
}