nginx

Table of Contents

1 NGINX

NGNIX 是著名的Web服务器,常常还被用作“反向代理”、“负载均衡”和“HTTP缓存”服务器。

nginx由一个主进程(master process)和一个或多个工作进程(worker processe)组成。主进程负责读取配置文件和管理工作进程,而工作进程负责处理请求。nginx采用事件驱动模型(如select,poll,epoll,kqueue等)来实现高性能。

参考:
NGINX documentation

1.1 启动、停止、重新加载配置

要启动nginx,执行nginx可执行程序即可。当nginx启动后,可通过 -s 参数来停止它或者让其重新加载配置。

Table 1: nginx命令行参数
命令行参数 含义
-?, -h Print help.
-v Print version.
-V Print NGINX version, compiler version and configure parameters.
-t Don’t run, just test the configuration file. NGINX checks configuration for correct syntax and then try to open files referred in configuration.
-q Suppress non-error messages during configuration testing.
-s signal Send signal to a master process: stop, quit, reopen, reload. (version >= 0.7.53)
-p prefix Set prefix path (default: “/usr/local/nginx/”). (version >= 0.7.53)
-c filename Specify which configuration file NGINX should use instead of the default.
-g directives Set global directives. (version >= 0.7.4)

下面是 nginx -g 参数的实例:

$ nginx -g "pid /var/run/nginx.pid; worker_processes `sysctl -n hw.ncpu`;"

nginx -s 参数的含义如表 2 所示。

Table 2: nginx支持的信号及其含义
命令 含义
nginx -s stop fast shutdown
nginx -s quit graceful shutdown
nginx -s reload reloading the configuration file
nginx -s reopen reopening the log files

参考:NGINX Command-line parameters

2 NGINX配置文件

NGIINX默认的配置文件名为“nginx.conf”,默认查找配置文件的目录为“/usr/local/nginx/conf/”、“/etc/nginx/”或者“/usr/local/etc/nginx/”。

2.1 配置文件基本格式

NGINX的配置文件由多个“section”组成,每个“section”的基本格式为:

<section> {
    <directive1> <parameters1>;
    <directive2> <parameters2>;
}

说明1:全局的设置一般放在所有其它“section”的前面(即配置文件开始位置),且不用 {} 包围,后面将介绍。
说明2:相同的指令可以出现在不同的section中(如 include 指令可以出现在任何section中)。在官方文档中,每个指令的“Context”属性说明了当前指令可用在哪些section中。如 error_log 指令可以出现在“main/http/mail/stream/server/location”section中:

Syntax: error_log file [level];
Default: error_log logs/error.log error;
Context: main, http, mail, stream, server, location

参考:
NGINX所有指令说明:Alphabetical index of directives

2.1.1 nginx.conf实例

下面是nginx.conf的一个实例:

user  www www;

worker_processes  2;

pid /var/run/nginx.pid;

#                          [ debug | info | notice | warn | error | crit ]

error_log  /var/log/nginx.error_log  info;

events {
    worker_connections   2000;

    # use [ kqueue | epoll | /dev/poll | select | poll ];
    use kqueue;
}

http {

    include       conf/mime.types;
    default_type  application/octet-stream;


    log_format main      '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         '"$gzip_ratio"';

    log_format download  '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         '"$http_range" "$sent_http_content_range"';

    client_header_timeout  3m;
    client_body_timeout    3m;
    send_timeout           3m;

    client_header_buffer_size    1k;
    large_client_header_buffers  4 4k;

    gzip on;
    gzip_min_length  1100;
    gzip_buffers     4 8k;
    gzip_types       text/plain;

    output_buffers   1 32k;
    postpone_output  1460;

    sendfile         on;
    tcp_nopush       on;
    tcp_nodelay      on;
    send_lowat       12000;

    keepalive_timeout  75 20;

    #lingering_time     30;
    #lingering_timeout  10;
    #reset_timedout_connection  on;


    server {
        listen        one.example.com;
        server_name   one.example.com  www.one.example.com;

        access_log   /var/log/nginx.access_log  main;

        location / {
            proxy_pass         http://127.0.0.1/;
            proxy_redirect     off;

            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            #proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

            client_max_body_size       10m;
            client_body_buffer_size    128k;

            client_body_temp_path      /var/nginx/client_body_temp;

            proxy_connect_timeout      70;
            proxy_send_timeout         90;
            proxy_read_timeout         90;
            proxy_send_lowat           12000;

            proxy_buffer_size          4k;
            proxy_buffers              4 32k;
            proxy_busy_buffers_size    64k;
            proxy_temp_file_write_size 64k;

            proxy_temp_path            /var/nginx/proxy_temp;

            charset  koi8-r;
        }

        error_page  404  /404.html;

        location /404.html {
            root  /spool/www;
        }

        location /old_stuff/ {
            rewrite   ^/old_stuff/(.*)$  /new_stuff/$1  permanent;
        }

        location /download/ {

            valid_referers  none  blocked  server_names  *.example.com;

            if ($invalid_referer) {
                #rewrite   ^/   http://www.example.com/;
                return   403;
            }

            #rewrite_log  on;

            # rewrite /download/*/mp3/*.any_ext to /download/*/mp3/*.mp3
            rewrite ^/(download/.*)/mp3/(.*)\..*$
                    /$1/mp3/$2.mp3                   break;

            root         /spool/www;
            #autoindex    on;
            access_log   /var/log/nginx-download.access_log  download;
        }

        location ~* \.(jpg|jpeg|gif)$ {
            root         /spool/www;
            access_log   off;
            expires      30d;
        }
    }
}

参考:http://nginx.org/en/docs/example.html

2.2 main模块和events模块

main模块和events模块都是全局有效的。下面是配置例子:

user  nginx;                               # 运行Nginx的用户
worker_processes  4;                       # nginx工作进程数,建议设置为CPU总核心数

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;             # pid文件路径

events {
    use epoll;                             # 指定事件模型,select|poll|kqueue|epoll|/dev/poll,参考http://nginx.org/en/docs/events.html
    worker_connections  1024;              # 1个工作进程最大的连接数
}

参考:http://nginx.org/en/docs/ngx_core_module.html

2.3 负载均衡策略

负载均衡模块用于从“upstream”指令定义的后端服务器列表中选取一台服务器。

Nginx默认支持下面负载均衡策略:
1、加权轮询(默认),依次把请求发送给不同服务器,每个服务器的权值值默认为1(weight=1)。
2、ip_hash,按客户端ip的hash结果分配服务器,来自同一个ip的客户端固定访问一个后端服务器,这可以解决动态网页存在的session共享问题。
3、hash:基于用户定义键的哈希。
4、least_conn,最少活动连接,该机制把请求转发给连接数较少的后端服务器。
5、least_time,最少平均响应时间。

2.3.1 Http反向代理实例(加权轮询策略)

下面是Http反向代理实例,它采用默认的“加权轮询”策略,所有Http请求会依次发送给“192.168.0.101:8080, 192.168.0.102:8080, 192.168.0.103:8080”三台服务器,但“192.168.0.101:8080”具有更高的优先级(它的weight值为2)。

user  nginx;
worker_processes  4;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    upstream app {
        ## 把下行取消注释即可使用 ip_hash 负载均衡策略
        ## ip_hash;
        ## 把下行取消注释即可使用 least_conn 负载均衡策略
        ## least_conn;
        server 192.168.0.101:8080   weight=2;
        server 192.168.0.102:8080;
        server 192.168.0.103:8080;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://app;
        }
    }
}

2.4 限流(ngx_http_limit_req_module)

每个API都有访问上限,为了防止过大的访问频率导致系统不可用,我们往往需要对API访问进行限流。常见的限流算法有漏桶算法(Leaky Bucket)和令牌桶算法(Token Bucket)。

NGINX的模块 ngx_http_limit_req_module 实现了“漏桶算法”,可以用来对API访问进行限流。

2.4.1 限流实例

下面是对“/search/”访问进行限流的例子:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    ...

    server {

        ...

        location /search/ {
            limit_req zone=one burst=5;
        }
...

限流主要由指令limit_req_zone和limit_req进行配置,它有两个重要配置(rate和burst),后面将对其进行说明。

2.4.1.1 limit_req_zone

limit_req_zone 的语法为:

limit_req_zone $variable zone=name:size rate=rate;

它的作用是设置一块共享内存域(NGINX所有工作进程可访问的内存区域)用来保存键值的状态参数。特别是保存了当前超出请求的数量。键值就是指定的变量“$variable”。如:

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

例子中,键值是客户端IP;区域的名称为one(名称可以随便改,使用指令limit_req时需要指定区域名称),内存区域大小为10m,平均处理的请求频率不能超过每秒一次。

注1:使用$binary_remote_addr变量(而不是变量$remote_addr变量)作为键值,可以将每条状态记录的大小减少到64个字节,这样10m内存可以保存更多的记录。
注2:rate可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,如果你需要指定每秒处理少于1个请求,如2秒处理一个请求,可以写为“30r/m”。

2.4.1.2 limit_req

limit_req 的语法为:

limit_req zone=name [burst=number] [nodelay];

参数zone用于设置使用哪个配置区域来做限制,与上面limit_req_zone里的name对应。
参数burst(爆发)的意思是设置一个大小为number的缓冲区当有大量请求过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
参数nodelay,如果设置上,超过访问频次而且缓冲区也满了的时候就会马上返回503,而不会等待;如果不设置,则所有请求会等待排队。

假设limit_req_zone中,配置了rate=1r/s,则配置:

limit_req zone=one;

表示每秒钟严格地只能通过一个请求,多余的请求会等待。

而配置:

limit_req zone=one burst=5;

表示可以支持的最大爆发数为5(每秒钟平均还是只能通过一个请求)。比如,某一秒钟突然来了5个请求,则这5个请求都可以被通过,但后面的4秒钟不会再通过请求了(有请求的话,会等待)。


Author: cig01

Created: <2017-06-24 六 00:00>

Last updated: <2018-11-01 四 16:55>

Creator: Emacs 25.3.1 (Org mode 9.1.4)