Nginx(三) 配置文件详解 - 基础模块(超详细)

        声明:写这篇博文一是为了加深自己对Nginx 的配置理解,二是为了方便粉丝们工作需要。部分配置我也没有使用过,用过的配置我都会在下面贴入测试结果,未使用过的配置可能会解释错误,如有错误希望大家及时留言,以后还会根据自己对Nginx的理解不断更新这部分内容。博主扣字翻译整理不易,希望大家鼓励点赞,感谢感谢。

        本来想在一篇文章中介绍完所有配置用法,但写着写着发现文章篇幅越来越长,码字时都开始卡顿了,电脑不行吖,所以只能拆分开来写。本篇文章仅介绍Nginx的基本配置用法,proxy、upstream和其它指令我们再专门写博文介绍。下面开始正片内容,Nginx.conf 配置文件分为三部分,分别为main块、events块、http块(http块又包含server块和location块),如下图。

第一部分:main块(全局块)

        官方说明 Core functionality

        main块主要是配置一些影响Nginx服务器整体运行的指令,其中包括:配置运行Nginx服务的用户(组)user、允许生成的 worker process数,进程PID存放路径、日志存放路径、类型以及配置文件的引入等。

# 配置nginx进程运行用户(组),nobody也是一个Linux用户,一般用于启动程序,没有密码
#user  nobody; # 用户组

# 确定nginx是否以守护进程方式运行,主要用于开发期间
# daemon on | off
# daemon on; # 默认值

# 并发处理进程数量,通常等于cpu数量或者2倍cpu数量。
# 也可以将其设置为auto。这样Nginx自动根据核心数生成对应数量的worker进程
# worker_processes  number | auto;
# worker_processes auto;
# worker_processes  1;  #默认值为1,意味着Nginx只运行一个worker process
worker_processes  2;

# worker process绑定cpu
worker_cpu_affinity 01 10;

# nginx进程pid存放路径
#pid        logs/nginx.pid;

# 存储错误日志
# error_log file [level]
error_log  /usr/logs/nginx/error.log; # 绝对路径
#error_log  logs/error.log error;  # 默认配置。相对路径,nginx安装目录下

# 线程池
# thread_pool name threads=number [max_queue=number];
# thread_pool default threads=32 max_queue=65536; #默认值
thread_pool r_admin threads=32 max_queue=65536;
thread_pool r_api threads=32 max_queue=65536;

# nginx worker能打开的最多文件数量
worker_rlimit_nofile 65535

# 加载动态模块
# load_module modules/ngx_mail_module.so;

1.1 user 用户(组)

Syntax:     user user [group];
Default:     user nobody nobody;
Context:    main 

        给Nginx工作进程分配用户(组),如果省略group,则用户组的名称与user相同。

1.2 error_log 日志

        Nginx error日志可通过内置指令进行配置,既可以输出到本地,也可以输出给rsyslog或内存缓存区(通常用于调试),甚至可以发送给另一台服务器的rsyslog应用进行处理。

        Nginx从1.5.2版本开始支持在同一域/块中配置多个日志。当main域中未配置error_log时,Nginx会把日志写入默认文件中。我们还可以在不同域中分别定义error_log,主要用于将不同请求的error日志分类储存,方便管理。如果在多个域中都配置了error_log,将以最低级别设置的为准。

# main块
# 注意:main块无论如何定义error_log,Nginx都会自动创建一个error.log,该文件是在编译Nginx时设置的默认日志输出位置。
error_log  logs/error_main_info.log info;
error_log  logs/error_main_notice.log notice;

# http块
http {
    error_log  logs/error_http.log notice; # 该配置无效
    server {
        error_log  logs/error_server.log info;

        location /reader/ {
            error_log  logs/error_server_reader.log info;
        }
        location /admin/ {
            error_log  logs/error_server_admin.log info;
        }
        location /app/ {
            error_log  logs/error_server_app.log info;
        }
        location / {
            error_log  logs/error_server_main.log info;
        }
    }
}

        格式:error_log + 存储路径 + 错误级别(如果不定义,默认级别是error)

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

        存储路径分三类,本机存储、发送给rsyslog、本机memory

1.2.1 存储路径 - 本机存储 /path

        注意配置的存储路径,nginx需要有读写权限,否则日志创建失败。

error_log  /usr/logs/nginx/error.log; # 绝对路径
error_log  logs/error.log notice;  # 默认配置。相对路径,nginx安装目录下

1.2.2 存储路径 - syslog

        参考官方说明 Logging to syslog

        该配置方式是将nginx error日志发送给本机或另一台服务器的rsyslog服务进行处理。

error_log syslog:server=47.77.88.999 debug;

# 或者是自定义
error_log syslog:server=47.77.88.999:515,facility=local1,severity=warn,tag=nginx_client warn;

        server:指定syslog服务器的IP和端口。如未指定端口,则用UDP端口514。IP也可以写成域名,如果域名解析为多个IP地址,则使用第一个解析的地址。

        facility:指定发送给syslog需要提供的实体/机构/服务器名称,默认是local7。可选择项有 “kern”, “user”, “mail”, “daemon”, “auth”, “intern”, “lpr”, “news”, “uucp”, “clock”, “authpriv”, “ftp”, “ntp”, “audit”, “alert”, “cron”, “local0”…“local7”。

        severity:指定事件/日志级别。这里指的并不是nginx的错误日志级别,而是发送给rsyslog需要记录的日志级别。默认是info。

        tag:标签/标识,也可以理解为是发送者/应用身份的标识。默认是nginx。

        warn:这个warn是nginx的错误级别。指定要将什么级别的日志发送个rsyslog server。默认是error。

        总结:哪台机器(facility)要将由谁(tag)产生的何类日志(nginx错误日志级别)发送给谁(server),并记录成什么级别(severity)

1.2.3 存储路径 - memory

        1.7.11版本开始支持。主要用于调试期间使用,将日志记录到内存缓冲区。

1.2.4 错误级别

        nginx的错误级别分为 debug | info | notice | warn | error | crit | alert | emerg ,从左到右,级别从低到高。我们其他的各种编译器输出日志的逻辑差不多。级别越低输出的错误日志就会越多。生产环境建议设置在warn及以上。否则会有大量的IO请求,耗费系统资源。

1.3 worker_processes 工作进程数(性能调优)

Syntax:     worker_processes number | auto;
Default:     worker_processes 1;
Context:    main 

        worker_processes 配置,是 Nginx 服务器并发处理服务的进程数量,该值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的约束,通常等于cpu数量或者2倍cpu数量。也可以配置成auto。最大值不要超过8,大于8时性能提升不明显且nginx稳定性也会变低。

# 我这里配置的 worker_process=2,可以看到nginx开启了1个主线进程和2个工作进程

[root@reader ~]# nginx -T
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
# configuration file /usr/local/nginx/conf/nginx.conf:

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


······

[root@reader ~]# 
[root@reader ~]# 
[root@reader ~]# ps -ef | grep nginx
root      7462     1  0 Nov04 ?        00:00:00 nginx: master process nginx
nobody    7463  7462  0 Nov04 ?        00:00:00 nginx: worker process
nobody    7464  7462  0 Nov04 ?        00:00:00 nginx: worker process
root     10477 10455  0 21:33 pts/0    00:00:00 grep --color=auto nginx
[root@reader ~]# 

[root@reader ~]# ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep '(nginx|PID)'
  PID  PPID USER     %CPU    VSZ WCHAN  COMMAND
19838     1 root      0.0  48336 -      nginx: master process nginx
19839 19838 nobody    0.0 339112 do_epo nginx: worker process
19840 19838 nobody    0.0 339112 do_epo nginx: worker process
20182 18871 root      0.0  12112 -      grep -E --color=auto (nginx|PID)
[root@reader ~]# 

        main process 和 worker process的区别,下面是nginx的官方说明:

        nginx has one master process and several worker processes. The main purpose of the master process is to read and evaluate configuration, and maintain worker processes. Worker processes do actual processing of requests. nginx employs event-based model and OS-dependent mechanisms to efficiently distribute requests among worker processes. The number of worker processes is defined in the configuration file and may be fixed for a given configuration or automatically adjusted to the number of available CPU cores (see worker_processes).

        nginx有一个主进程和几个工作进程。主进程的主要目的是读取和评估/监测配置文件,并维护工作进程。工作进程实际处理请求。nginx采用基于事件的模型和依赖于操作系统的机制来有效地在工作进程之间分配请求。工作进程的数量在配置文件中定义,对于给定的配置可以是固定的,也可以根据可用CPU内核的数量自动调整(请参见worker_processes)。

1.4 worker_cpu_affinity 进程绑定cpu(性能调优)

Syntax:        worker_cpu_affinity cpumask ...;
                    worker_cpu_affinity auto [cpumask];
Default:        —
Context:       main


# Binds worker processes to the sets of CPUs. Each CPU set is represented by a bitmask of allowed CPUs. There should be a separate set defined for each of the worker processes. By default, worker processes are not bound to any specific CPUs.
# 将工作进程绑定到CPU集。每个CPU集由允许的CPU的位掩码表示。应该为每个工作进程定义一个单独的集合。默认情况下,工作进程不绑定到任何特定的CPU。

        仅适用于FreeBSD和Linux系统,目的是将工作进程与CPU进行绑定,将process与CPU绑定并不意味着一个worker process独占一个CPU,而是该进程只能在已绑定的CPU上处理请求。

        Nginx默认情况下,工作进程不绑定任何特别的CPU。使用worker_cpu_affinity指令可以充分发挥多核性能,提高每个CPU的利用率,从而在内核调度策略上实现了完全并发。另外,将worker process与CPU绑定,避免了worker process处理请求时在不同cpu间的来回跳转,减少cpu对进程的资源分配、回收和内存管理等,这样也可以有效提升nginx服务器的性能。

# 示例1:2个CPU,2个进程,每个进程绑定一个CPU
worker_processes  2;
worker_cpu_affinity 01 10;

# 示例2:2个CPU,4个进程,第1、3个进程绑定CPU0,第2、4个进程绑定CPU1
worker_processes  4;
worker_cpu_affinity 01 10 01 10;

# 示例3:2个CPU,8个进程,第1、3、5、7个进程绑定CPU0,第2、4、6、8个进程绑定CPU1(不推荐)
worker_processes  8;
worker_cpu_affinity 01 10 01 10 01 10 01 10;


# 示例4:4个CPU,2个进程,第1个进程绑定CPU0、CPU2,第2个进程绑定CPU1、CPU3
worker_processes  2;
worker_cpu_affinity 0101 1010;

# 示例5:4个CPU,4个进程,每个进程绑定一个CPU
worker_processes  4;
worker_cpu_affinity 0001 0010 0100 1000;

# 示例6:4个CPU,8个进程,第1、5个进程绑定CPU0,第2、6个进程绑定CPU1,第3、6个进程绑定CPU2,第4、8个进程绑定CPU3
worker_processes  8;
worker_cpu_affinity 0001 0010 0100 1000 0001 0010 0100 1000;


# 示例7:8个CPU,2个进程,第1个进程绑定CPU0、CPU2、CPU4、CPU6,第2个进程绑定CPU1、CPU3、CPU5、CPU7
worker_processes  2;
worker_cpu_affinity 01010101 10101010;

# 示例8:8个CPU,4个进程,第1个进程绑定CPU0、CPU4,第2个进程绑定CPU1、CPU5,第3个进程绑定CPU2、CPU6,第4个进程绑定CPU3、CPU7
worker_processes  4;
worker_cpu_affinity 00010001 00100010 01000100 10001000;

# 示例9:8个CPU,8个进程,每个进程绑定一个CPU
worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000


# 示例10:将进程自动绑定到可用CPU(Nginx 1.9.10版本开始支持)
worker_processes auto;
worker_cpu_affinity auto;

# 示例11:8个CPU,N个进程,将每个进程自动分配到可选范围内的CPU0、CPU2、CPU4、CPU6上
worker_processes number | auto;
worker_cpu_affinity auto 01010101;

ps axo pid,cmd,psr | grep nginx 

ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep '(nginx|PID)'

测试未配置worker_cpu_affinity时,nginx进程与CPU的关系,结果如下:

# 服务器为2核CPU,worker_processes=2
# 未配置worker_cpu_affinity,查询nginx进行及对应的CPU

[root@reader conf]# nginx -T
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
# configuration file /usr/local/nginx/conf/nginx.conf:

#user  nobody;
worker_processes  2; #工作进程:数目。根据硬件调整,通常等于cpu数量或者2倍cpu数量。
#worker_cpu_affinity 01 10;

······


[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   0
16776 nginx: worker process         0
16777 nginx: worker process         0
16843 grep --color=auto nginx       1
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
16845 nginx: worker process         0
16846 nginx: worker process         1
16912 grep --color=auto nginx       0
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
16914 nginx: worker process         0
16915 nginx: worker process         1
16981 grep --color=auto nginx       1
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
16983 nginx: worker process         0
16984 nginx: worker process         1
17050 grep --color=auto nginx       0
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
17052 nginx: worker process         0
17053 nginx: worker process         0
17119 grep --color=auto nginx       1
[root@reader conf]# 


每次热重启后,两个进程会在两个CPU间来回切换,并没有绑定专门的cpu

 测试配置worker_cpu_affinity=01 10时,nginx进程与CPU的关系,结果如下:

[root@reader conf]# nginx -s reload 
[root@reader conf]# nginx -T
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
# configuration file /usr/local/nginx/conf/nginx.conf:

#user  nobody;
worker_processes  2; #工作进程:数目。根据硬件调整,通常等于cpu数量或者2倍cpu数量。
worker_cpu_affinity 01 10;

······


[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
17194 nginx: worker process         0
17195 nginx: worker process         1
17261 grep --color=auto nginx       0
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
17263 nginx: worker process         0
17264 nginx: worker process         1
17330 grep --color=auto nginx       0
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
17332 nginx: worker process         0
17333 nginx: worker process         1
17399 grep --color=auto nginx       1
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   0
17401 nginx: worker process         0
17402 nginx: worker process         1
17468 grep --color=auto nginx       1
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   0
17470 nginx: worker process         0
17471 nginx: worker process         1
17537 grep --color=auto nginx       1
[root@reader conf]# nginx -s reload 
[root@reader conf]# ps axo pid,cmd,psr | grep nginx
13417 nginx: master process nginx   1
17539 nginx: worker process         0
17540 nginx: worker process         1
17606 grep --color=auto nginx       1
[root@reader conf]# 


每次热重启后,重新开启的进程中,进程1绑定CPU0,进程2绑定CPU1

1.5 thread_pool 线程池(性能调优)

        该指令用于定义线程池线程数量和最多等待请求数量。

        Nginx默认未构建threads模块,如需使用thread_pool功能,需在预编译nginx时安装--with-threads模块如未安装请重新编译Nginx(参考博文)

Syntax:      thread_pool name threads=number [max_queue=number];
Default:     thread_pool default threads=32 max_queue=65536;
Context:    main

# This directive appeared in version 1.7.11. # 1.7.11版本开始支持该指令

# in the 'main' context
thread_pool default threads=32 max_queue=65536; 
 
# in the 'http', 'server', or 'location' context
aio threads=default; 

aio threads; # 如省略池名称,则使用名称为“ default”的线程池

aio threads=pool$disk; # 线程池名称也可以使用变量

thread_pool default threads=32 max_queue=65536;# max_queue可省,默认值是65536 

        上面这行代码定义了一个名为“default”,包含32个线程,任务队列最多支持65536个请求的线程池。如果线程池中的所有线程都忙,则新任务将在队列中等待。max_queue 参数限制了允许在队列中等待的任务数量。默认情况下,队列中最多可等待 65536 个任务。当队列溢出时,任务完成后会出现如下错误:

thread pool "NAME" queue overflow: N tasks waiting 

        如果出现上述错误,说明线程池的负载很高,可以尝试通过增加线程数来解决这个问题。一个进程最多不要超过50线程,可根据自己机器的压测结果进行调整。

        最后要说明的是,可以配置多个相互独立的线程池,并在配置文件的不同位置使用它们来满足不同的用途:

# in the 'main' context
thread_pool one threads=1024 max_queue=3000;
thread_pool two threads=512 max_queue=3000;
thread_pool three threads=256 max_queue=3000;
 
http {
    server {
        location /one {
            aio threads=one;
        }
        location /two {
            aio threads=two;
        }
        location /three {
            aio threads=three;
        }
 
    }
    #...
}

1.6 worker_rlimit_nofile 最大可打开文件数量(性能调优)

Syntax:       worker_rlimit_nofile number;
Default:      —
Context:    main

        设置所有工作进程可打开的文件数量上限,也可以理解为最大可建立的连接数量。linux一切皆文件,用户每发起一次请求,系统都会生成一个文件句柄,理论上这个值应该是最多打开文件数(ulimit -n)与nginx工作进程数相除,但是nginx分配请求并不是均匀的,所以这里与最好与ulimit -n 或者limits.conf的值保持一致。

        查看系统设置的最大打开文件数量值,使用ulimit -n 或ulimit -a命令。

[root@reader ~]# ulimit -n
65535                                            # 我这里已经设置过了
[root@reader ~]# ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 14445
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535        # 最大打开文件数量
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 14445
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

         设置系统最大文件打开数量值。在/etc/security/limits.conf配置文件最后增加如下两行代码。

* soft nofile 65535
* hard nofile 65535

1.7 worker_priority 进程优先级(性能调优)

Syntax:      worker_priority number;
Default:      worker_priority 0;
Context:    main

# worker_priority -2;

         定义工作进程的nice值,以调整工作进程的调度优先级,默认为0。优先级由静态优先级和内核根据进程执行情况所做的动态调整(目前只有±5的调整)共同决定。nice值是进程的静态优先级,允许取值范围是-20 ~ +19,–20是最高优先级,+19是最低优先级。因此,如果用户希望Nginx占有更多的系统资源,那么可以把nice值配置得更小一些,但不建议比内核进程的nice值(通常为–5)还要小。

1.8 load_module 加载动态模块

Syntax:      load_module file;
Default:      —
Context:    main


This directive appeared in version 1.9.11. # 1.9.11版本开始加入该指令。

# 该指令主要是加载动态模块。
load_module modules/ngx_mail_module.so;

1.9 include 引入文件

Syntax:      include file | mask;
Default:      —
Context:    any

# 举例
include mime.types;
include vhosts/*.conf;

         引入另一个文件或与指定掩码(mask)匹配的文件。包含的文件应包含语法正确的指令和块。

1.10 worker_shutdown_timeout 退出超时时间

Syntax:     worker_shutdown_timeout time;
Default:     —
Context:    main


This directive appeared in version 1.11.11.

# worker_shutdown_timeout 5s;

        指定worker process优雅退出时的超时时间。当时间到期时,nginx会尝试关闭当前打开的所有连接,以方便关闭Nginx。

        worker_shutdown_timeout 类似于给worker process设置了一个关闭定时器。当我们执行nginx -s quit 或 nginx -s reload命令时,Nginx需要优雅(平滑)的关闭旧工作进程,旧进程在接收到主进程发送的QUIT信号后,会在处理完请求后关闭进程。如果旧进程因阻塞或其他原因而无法退出关闭时,等时间到了worker_shutdown_timeout 定时器设定的时间后,旧进程会立即强制退出。

1.11 pcre_jit 即时编译

        PCRE JIT 主要用于加快正则表达式的处理速度。开启正则表达式“即时编译”功能时,需要用到--with-pcre-jit模块。

Syntax:     pcre_jit on | off;
Default:     pcre_jit off;
Context:    main
This directive appeared in version 1.1.12. # 1.1.12版本开始加入该指令 

        Enables or disables the use of “just-in-time compilation” (PCRE JIT) for the regular expressions known by the time of configuration parsing.
        对配置解析时已知的正则表达式启用或禁用 "即时编译"(PCRE JIT)

1.12 working_directory 工作进程工作目录

Syntax:        working_directory directory;
Default:        —
Context:       main

#Defines the current working directory for a worker process.
#It is primarily used when writing a core-file, 
#in which case a worker process should have write permission for the specified directory.

        指定工作进程的当前工作目录,主要用于在该目录下写入core文件。linux系统中,nginx的工作进程是以nobody用户运行的,所以只有这样,工作进程才具有该目录的写入权限。

        如果工作进程出现问题,工作进程会在工作目录下记录core文件,working_directory 指令是用来定义core文件的存放路径,而worker_rlimit_core 指令是用来限制core文件的大小。

1.13 worker_rlimit_core 限制core文件大小

Syntax:       worker_rlimit_core size;
Default:      —
Context:     main

# worker_rlimit_core 50M;

          该指令主要是用来限制core文件的大小。worker_rlimit_core 指令可以在不重启主进程的情况下通过修改配置文件来修改core文件大小限制。

1.14 ssl_engine(了解)

Syntax:      ssl_engine device;
Default:      —
Context:     main

定义硬件 SSL 加速器的名称

1.15 timer_resolution(了解)

Syntax:      timer_resolution interval;
Default:      —
Context:    main

# timer_resolution 100ms;

         降低工作进程中的定时器分辨率,从而减少系统调用 gettimeofday() 的次数。默认情况下,每次收到内核事件时都会调用 gettimeofday()。在降低定时器分辨率的情况下,gettimeofday() 只会在每个指定时间间隔被调用一次。

第二部分:events 块

Syntax:      events { ... }
Default:      —
Context:    main

        events块负责事件配置,主要是配置一些能影响Nginx服务器与用户网络连接的指令。如配置每个工作进程的最大网络连接数(worker_connections),是否开启对多工作进程下的网络连接序列化(accept_mutex),是否允许同一工作进程同时接收多个网络连接(multi_accept),选用哪种事件驱动模型处理连接请求(use)。这部分配置对 Nginx 的性能影响较大,在实际工作中应灵活配置。

events {
    worker_connections 1024; # 每个工作进程的最大网络连接数为1024
    accept_mutex on; #开启网路连接序列化,防止惊群现象发生
    multi_accept on; #开启每个进程可同时接收多个网络连接
    #use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
    
    client_header_buffer_size 4k;
    open_file_cache max=2000 inactive=60s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 1
}

网络连接相关指令

keepalive_time time;                        //设置一个长连接允许处理请求的最长时间。
keepalive_timeout timeout [header_timeout]; //HTTP长连接的超时时长,单位是秒,默认值是75s。
keepalive_requests number;                  //一个HTTP长连接允许处理的最大请求数,默认是1000次。
keepalive_disable [msie6|safari|none];      //为指定类型的UserAgent禁用长连接
tcp_nodelay on|off;                         //有响应数据就立即发送,仅在开启Keep-Alive时有效,追求响应“实时性”,提升用户体验,通常设为on。
tcp_mopush on|off;                          //响应数据达到一定长度时再响应,仅在开启sendfile时有效,可减少网络报文段的数量,追求响应“有效性”。
client_header_timeout number;               //读取http请求头的超时时长
client_body_timeout number;                 //读取http请求体的超时时长
send_timeout number;                        //发送响应报文的超时时长
lingering_close on|off|always;              //控制连接延迟关闭方式
lingering_time time;                        //连接关闭总延迟时间
lingering_timeout time;                     //连接关闭单次延迟时间

2.1 worker_connections 最大并发连接数

Syntax:      worker_connections number;
Default:      worker_connections 512;
Context:     events

         设置每个工作进程可处理的最大并发连接数。需要注意的是,这个数字包括所有连接(例如与代理服务器的连接等),而不仅仅是与客户端的连接。另一个注意事项是,实际同时连接数不能超过当前最大打开文件数限制,即不能超过worker_rlimit_nofile设置的数量上限。

2.2 accept_mutex 互斥锁

Syntax:       accept_mutex on | off;
Default:      accept_mutex off;
Context:     events

# 多进程模式下且网络吞吐量不大时建议开启
accept_mutex  on;

# 在1.11.3版本之前,默认值为on
Prior to version 1.11.3, the default value was on.

         该指令只对开启了多工作进程(worker_processes>1)的Nginx有效,是Nginx的负载均衡锁Nginx如果以多进程的模式运行,当一个网络连接到来时,多个工作进程会被同时唤醒,但最终只有一个工作进程负责处理连接,其它进程会重新进入休眠状态(“惊群”现象),如果新的网络连接数量较低,就会造成系统资源的浪费,影响系统性能。

        开启网络连接序列化后(accept_mutex=on),工作进程会被逐一唤醒,只有拿到互斥锁的进程才允许接收新的网络连接,各进程轮流获取新的网络连接,当一个工作进程正在接收网络连接时,下一工作进程需等待一段时间后才会允许接收网络连接(最长等待时间由accept_mutex_delay设定,默认是500ms),这样就可以避免资源浪费。

        启用互斥锁后,同一时间内只有一个工作进程能取到accept锁。这个accept锁不是堵塞锁,如果取不到会立刻返回。如果一个工作进程试图取锁而未取到,它至少要等待accept_mutex_delay定义的时间才能再次试图取锁。

        注意:当服务器新的网络连接数量很多,服务器吞吐量很大时,如果还开启互斥锁,反而会降低网络连接处理效率,影响用户体验。吞吐量较高的服务器,建议关闭互斥锁,虽然在一定程度上会出现惊群现象,服务器负载会上升,但是处理效率能有效提升。当然最终还要看实际应用场景、服务器性能和其它因素,没有绝对的说要开启还是关闭互斥锁,根据实际情况灵活配置。

2.3 accept_mutex_delay 互斥锁等待时间

Syntax:      accept_mutex_delay time;
Default:     accept_mutex_delay  500ms;
Context:    events


If accept_mutex is enabled, specifies the maximum time during which a worker process will try to restart accepting new connections if another worker process is currently accepting new connections.
如果启用 accept_mutex,则指定当另一个工作进程正在接受新连接时,工作进程尝试重新开始接受新连接的最长时间。

         accept_mutex_delay表示使用accept锁后到真正建立连接之间的延迟时间,默认500ms。主要是设置工作进程尝试取得accept锁的最短等待时间,如果一个工作进程在尝试获取accept锁失败后,它至少要等待accept_mutex_delay定义的时间后才能再次尝试取锁。在使用accept锁后,同一时间内只有一个工作进程能够取到accept锁。accept锁不是堵塞锁,如果取不到会立刻返回。

2.4 multi_accept 开启多网络连接

Syntax:      multi_accept on | off
Default:     multi_accept off;
Context:    events

# 建议开启
multi_accept on;

        设置是否允许一个工作进程同时接收多个网络连接。该功能默认是关闭,一个工作进程一次只能接收一个新的网络连接,开启后(multi_accept=on),一个工作进程可同时接收多个请求。

2.5 use

Syntax:      use method;
Default:      —
Context:     events

         设置选用哪种事件驱动模型处理连接请求。通常情况下不需要专门指定,因为 nginx 默认会使用最有效连接处理方式。连接处理方式有 select | poll | kqueue | epoll | /dev/poll | eventport,对各种处理方式的说明和使用请参考官方说明Connection processing methods

2.6 worker_aio_requests 

Syntax:     worker_aio_requests number;
Default:     worker_aio_requests 32;
Context:    events
This directive appeared in versions 1.1.4 and 1.0.7.

 当使用 aio 配合 epoll 连接处理方式时,设置单个工作进程未完成的异步 I/O 操作的最大数量。

2.7 debug_connection 

Syntax:     debug_connection address | CIDR | unix:;
Default:     —
Context:    events

For this directive to work, nginx needs to be built with --with-debug

        对特定的客户端连接启用debug调试日志。其他客户端仍旧由 error_log 指令设置的日志记录级别。使用该指令时,Nginx需要安装 --with-debug模块。

第三部分:http块

        http块中可以配置多个server块,且每个server块中可以配置多个location块。

3.1 listen 

Syntax:     listen address[:port] [default_server] [ssl] [http2 | quic] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
                 listen port [default_server] [ssl] [http2 | quic] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
                 listen unix:path [default_server] [ssl] [http2 | quic] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
Default:     listen *:80 | *:8000;
Context:    server 

        address和port可以同时都指定,也可以单独指定一个。如果只指定address,则使用80端口。 

        [default_server]:该参数用于给address、port或address:port设置是否默认服务器。listen address:port default_server 配置生效优先级最高。如果Nginx中配置了多个listen port值相同、server_name值不同的server,当请求头host跟所有server_name都不匹配时,Nginx会将请求分配给默认服务器,若未设置默认服务器,则分配给第一个server进行处理(因为此时没有配置listen address:port的server)。

        针对同一port或address最多只能设置一个默认服务器,当所有server都未配置default_server时,配置listen address:port的server会是默认服务器,否则会取配置顺序最靠前的server(注意有listen前提条件)处理请求。

        [ssl]:允许https协议请求。允许指定该端口上接受的所有连接均应以 SSL 模式运行。这样为处理HTTP和HTTPS请求的服务器提供了更紧凑的配置。

        [proxy_protocol]:启用代理协议,用于传递真实的请求头信息。

        [fastopen=number]设置是否开启TCP Fast Open,并限制尚未完成三次握手的连接队列(半连接队列)的最大长度。

        [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]:用于设置TCP连接保活机制,详细配置解释见3.18章节。

        [backlog=number]:设置调用 listen( int sockfd, int backlog ) 函数时的backlog参数值,该参数限制了TCP全连接队列/accept队列的最大长度,默认值是511。

listen 127.0.0.1 default_server accept_filter=dataready backlog=1024;

        [rcvbuf=size]:设置socket接收缓冲区范围,对应socket的SO_RCVBUF选项。

        [sndbuf=size]:设置socket发送缓冲区范围,对应socket的SO_SNDBUF选项。

​3.2 server_name 

3.2.1 server_name 

Syntax:     server_name name ...;
Default:     server_name "";
Context:    server

        该指令用于设置虚拟服务器名称。 默认配置是空字符串。

        服务器名称可以设置多个,中间用空格隔开。如有多个,第一个名称将作为主名称。

server {
    server_name example.com www.example.com;
}

        可以用星号("*")代替名称的第一部分或最后一部分,称之为通配符名称。 

server {
    server_name example.com *.example.com www.example.*;

    # server_name example.com *.example.com
    # server_name .example.com                # 此行配置等同于上面一行配置

}

        也可以用正则表达式来配置server_name,例如:

server {
    server_name www.example.com ~^www\d+\.example\.com$;
}
常用正则表达式
.匹配除换行符以外的任意字符
?重复次数不超1次
+重复次数不少于1次
*最小链接数
^匹配字符串的开头
$匹配字符串的结尾
{n}重复n次
{n,}至少重复n次
{a}匹配字符a
{a-z}匹配a-z间的任意小写字母

当有多个server时,匹配优先级如下:

        1.先根据名称精确匹配;

        2.再根据左侧通配符匹配,例如“ *.example.com”;

        3.再根据右侧通配符匹配,例如“ mail.*”;

        4.再根据正则表达式匹配(按正则表达式的配置顺序);

        5.最后再去listen 指令中的default_server去选择(如有配置)。

        上面5项中任意一项匹配成功,就会立即停止匹配。

3.2.2 server_names_hash_bucket_size

Syntax:     server_names_hash_bucket_size size;
Default:     server_names_hash_bucket_size 32|64|128;
Context:    http

        设置服务器名称哈希表的存储桶大小。默认值取决于处理器的缓存行的大小。

3.2.3 server_names_hash_max_size 

Syntax:     server_names_hash_max_size size;
Default:     server_names_hash_max_size 512;
Context:    http

        设置服务器名称哈希表的最大size。

3.2.4 server_tokens

Syntax:     server_tokens on | off | build | string;
Default:     server_tokens on;
Context:    http, server, location

        启用或禁用在错误页面和 "服务器 "响应头中显示 nginx 版本。

3.3 location 

Syntax:     location [ = | ~ | ~* | ^~ ] uri { ... }
                 location @name { ... }
Default:     —
Context:    server, location

         该指令用来匹配URI。

# "="表示精确匹配,此配置用来匹配 "/" 请求
location = / {
    [ configuration A ]
}

# 通用匹配,匹配指定根目录下的静态文件,如匹配"/index.html"
location / {
    [ configuration B ]
}


# 注意,下面这两个location是冲突的,二者只能存其一。
location /test {
    ···
}
location ^~ /test {
    ···
}
修饰符匹配规则备注举例
=精确匹配匹配成功立刻结束匹配

location = /test {}

location = / {}

^~

以指定的字符串开头

(非正则匹配)

匹配成功后继续完成所有匹配,寻找最长匹配(最长匹配策略)。

location ^~ /tes {}

location ^~ /test/ {}

~区分大小写的正则匹配匹配成功立刻结束匹配

location ~ /tes {}

location ~ ^/test$ {}

~*不区分大小写的正则匹配匹配成功立刻结束匹配

location ~* \.(gif|jpg|jpeg)$ {}

~* /js/.*/\.js

/通用匹配最长匹配策略
@通用匹配定义一个命名的 location,不用于处理常规请求,而是用于内部请求重定向,例如 error_page, try_files

       关于location的匹配顺序和匹配规则优先级论述,请参阅另一篇文章 Nginx(六) Nginx location 匹配顺序及优先级深究(亲测有效)

3.4 default_type & types MIME类型

指令default_typetypes
语法Syntax:    default_type mime-type;
Default:    default_type text/plain;
Context:   http, server, location
Syntax:    types { ... }
Default:    types {
                     text/html  html;
                     image/gif  gif;
                     image/jpeg jpg;
                 }
Context:    http, server, location
功能

指定默认的MIME类型。可以使用types指令将文件扩展名映射到 MIME 类型。

该指令用于将文件扩展名映射到响应 MIME 类型。

扩展名不区分大小写。

一个类型可映射多个扩展名。

nginx自带有一个mime.types文件(conf/mime.types),该文件基本涵盖了所有常有的mime类型,所以可以在http中使用include指令将mime.types引入配置并使用。

http {
    include       mime.types;
    default_type  application/octet-stream;
}

3.5 日志管理

        涉及模块:ngx_http_core_module、ngx_http_log_module。

3.5.1 Nginx什么时候记录日志?

        如果是短连接,Nginx是在TCP连接关闭后记录access日志;

        如果是长连接且keepalive未失效,Nginx是在处理完请求后记录access日志;

        如果是长连接且keepalive已失效,Nginx是在TCP连接关闭后才记录access日志。

        所以,不管是长连接还是短连接,Nginx记录日志的过程都不会影响客户端请求过程。

3.5.2 log_format access日志格式化

log_forma指令一定要在access_log之前设置,不然会出现如下错误:

nginx: [emerg] unknown log format "main" in /usr/local/nginx/conf/nginx.conf:34

Syntax:     log_format name [escape=default|json|none] string ...;
Default:     log_format combined "...";
Context:    http    # 只能在http域设置

The escape parameter (1.11.8) allows setting json or default characters escaping in variables, by default, default escaping is used. The none value (1.13.10) disables escaping.

默认配置:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

access_log  logs/access.log  combined;

上面一行是在http全局定义的access_log配置,未定义combined时,日志记录如下:

14.145.163.156 - - [13/Nov/2023:23:47:09 +0800] "POST /s HTTP/1.1" 301 169 "-" "PostmanRuntime/7.35.0"

这个指令很好理解,就是设置access_log的格式化格式,重在使用。

name:自定义一个名字,配置access_log时使用;

escape:对访问日志特殊字符进行转义,可用参数有default、json、none,默认是default。1.11.8版本开始支持该参数

指令defaultjsonnone

官方

说明

For default escaping, characters “"”, “\”, and other characters with values less than 32 (0.7.0) or above 126 (1.1.6) are escaped as “\xXX”. If the variable value is not found, a hyphen (“-”) will be logged.For json escaping, all characters not allowed in JSON strings will be escaped: characters “"” and “\” are escaped as “\"” and “\\”, characters with values less than 32 are escaped as “\n”, “\r”, “\t”, “\b”, “\f”, or “\u00XX”.The none value (1.13.10) disables escaping.

蹩脚

翻译

对于default转义,字符“ "”,“ \”以及其他值小于 32(0.7.0)或大于 126(1.1.6)的字符将转义为“ \xXX”。如果找不到变量值,将记录连字符(“ -”)对于json转义,将转义 JSON strings中不允许的所有字符:字符“ "”和“ \”转义为“ \"”和“ \\”,值小于 32 的字符转义为“ \n”,“ \r” ,“ \t”,“ \b”,“ \f”或“ \u00XX

禁止转义。

1.13.10版本开始支持

个人

理解

首先,我一直无法理解这里的32和126是什么意思,对应ASCII码表里的十进制32和126?如果是这样的话,我这边测试了好几次,转义结果都跟上面说的不太不匹配。

default是将大部分特殊字符转义为ASCII十六进制,\xXX格式;

json    是将大部分特殊字符转义为Unicode码,\00XX格式。

试了多次,log_formate escape=json string ··· 这种方法无法解决Nginx中文转十六进制问题,如有解决成功的请指教。

        Nginx定义的参数/变量比较多,这里只介绍一些记录access日志时比较常用的变量,全部变量请参考官网 Alphabetical index of variables

$host客户端发起的请求地址Host
$http_host客户端发起的请求地址Host+port
$remote_addr客户端IP或域名
$http_x_forwarded_for客户端IP地址,通过代理服务器来记录客户端的 IP
$remote_user客户端用户名
$request_uri请求URI
$uri请求URI
$time_iso8601ISO8601标准格式下的本地时间
$time_local通用日志格式的本地时间
$request请求方法+请求地址+请求的http协议
$request_method用户请求方法
$request_length请求的长度(包括请求行,请求头和请求正文)
$request_time请求处理时长,单位为s,精度是ms。从接受到请求数据的第一个字节开始到发送完响应的最后一个字节之间的时间。
$status响应状态码
$http_referer请求是从哪个页面链接访问过来的
$user_agent客户端浏览器相关信息
$http_user_agent客户端浏览器相关信息
$bytes_sent发给客户端的总字节数
$body_bytes_sent发给客户端的字节数,不含响应头大小,该变量与Apache模块mod_log_config里的“%B”参数兼容。
$connection网络连接序列号
$connection_requests当前连接的请求数量
$msec日志写入时间。单位为秒,精度是毫秒
$pipe如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
$ssl_protocolSSL协议版本,TLSv1
$ssl_cipher交换数据中的算法    RC4-SHA
$upstream_statusupstream状态码
$upstream_addr后台upstream的地址,即真正提供服务的主机地
$upstream_response_time请求过程中,upstream响应时间

         单独说下$http_ 这个参数,$http_后面可以跟请求头中的key,用于获取该key对应的value值,类似于$http_user_agent,详见下面的例子,可以通过这种方法获取请求头中的关键参数值

# format格式
log_format format2 escape=json '{'
				'"host":"$host",'
				'"http_host":"$http_host",'
				'"remote_addr":"$remote_addr",'
				'"remote_user":"$remote_user",'
				'"x-forwarded-for":"$http_x_forwarded_for",'
				'"time_iso8601":"$time_iso8601",'
				'"time_local":"$time_local",'
				'"request":"$request",'
				'"http_referer":"$http_referer",'
				'"request_time":"$request_time",'
				'"request_length":"$request_length",'
				'"status":"$status",'
				'"bytes_sent":"$bytes_sent",'
				'"body_bytes_sent":"$body_bytes_sent",'
				'"user_agent":"$http_user_agent",'
				'"http_user_agent":"$http_user_agent",'
				'"request_body":"$request_body",'
				'"id":"$http_id",'
				'"name":"$http_name",'
			      '}';

# 日志记录内容 
{
	"host":"www.read*******.cn",
	"http_host":"www.read*******.cn:8688",
	"remote_addr":"14.145.163.156",
	"remote_user":"-",
	"x-forwarded-for":"-",
	"time_iso8601":"2023-11-14T00:10:46+08:00",
	"time_local":"14/Nov/2023:00:10:46 +0800",
	"request":"POST /s HTTP/1.1",
	"http_referer":"-",
	"request_time":"0.000",
	"request_length":"278",
	"status":"301",
	"bytes_sent":"354",
	"body_bytes_sent":"169",
	"user_agent":"PostmanRuntime/7.35.0",
	"http_user_agent":"PostmanRuntime/7.35.0",
	"request_body":"-",
	"id":"-",
	"name":"hello nginx",
}

{
	"host":"www.read*******.cn",
	"http_host":"www.read*******.cn:8688",
	"remote_addr":"14.145.163.156",
	"remote_user":"-",
	"x-forwarded-for":"-",
	"time_iso8601":"2023-11-14T00:10:46+08:00",
	"time_local":"14/Nov/2023:00:10:46 +0800",
	"request":"GET /test.html HTTP/1.1",
	"http_referer":"http://www.read*******.cn:8688/s",
	"request_time":"0.000",
	"request_length":"283",
	"status":"200",
	"bytes_sent":"482",
	"body_bytes_sent":"226",
	"user_agent":"PostmanRuntime/7.35.0",
	"http_user_agent":"PostmanRuntime/7.35.0",
	"request_body":"-",
	"id":"-",
	"name":"hello nginx",
}

3.5.3 access_log 访问日志

Syntax:      access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
                  access_log off;
Default:     access_log logs/access.log combined;
Context:    http, server, location, if in location, limit_except

        该指令用于设置访问日志存储位置、格式、缓冲区大小、数据压缩和刷新时间等,可以在同一配置级别上指定多个access_log,但是针对同一日志文件带buffer、flush等缓存参数的配置却只能出现一次,也就是说同一日志文件的缓存压缩策略只能配置一次

access_log off 表示禁止记录当前配置层级的所有访问日志。

  • path:同error_log path,参考章节1.2.1和1.2.2。
  • format:取3.5.1章节log_format 的name,如未指定则使用预定义是combined。

如果使用了buffer或gzip参数,日志内容会先写入缓冲再写入path对应的文件。

  • buffer:设置日志文件缓冲区大小。当缓冲区日志数据超出该值时,缓冲区日志数据会被写到磁盘文件。默认缓冲区大小为 64KB。buffer值不得超过磁盘剩余空间。对于FreeBSD系统,buffer大小无限制。
access_log /spool/logs/nginx-access.log compression buffer=32k;
  • gzip:设置缓冲区数据的压缩级别。如果启用gzip,缓冲数据在写入文件前将被压缩。level=[1,9],数值越大压缩比越高,压缩速度越慢,系统资源消耗也越大。默认是1。使用gzip默认就开启了buffer,启用buffer或gzip任一参数,日志在写入前都将被缓存;
access_log /path/to/log.gz combined gzip flush=5m;

#For gzip compression to work, nginx must be built with the zlib library.
#为保证gzip压缩工作,nginx必须同 zlib 库一同安装。
  • flush设置日志缓冲区刷新的时间间隔,缓冲区日志的保护时间超过这个设定值时,缓冲区日志数据会被清空并写入磁盘文件access.log。
  • if:其它条件判断。如果指定条件求值为“0”或空字符串,那么该请求记录不会写入日志。
# 响应状态码为2XX和3XX的请求将不会记录日志
map $status $loggable {
    ~^[23]  0;
    default 1;
}

access_log /path/to/access.log combined if=$loggable;

日志缓存目的和优缺点讨论

        目的:在不设置缓存时,每次日志写入文件时都要打开和关闭文件,当访问量较高时,磁盘I/O(直接I/O)较高,影响服务器性能。开启缓存后,当日志累计到一定量后再写入文件,这样可以有效降低磁盘I/O,提升服务器性能。

        优点:降低磁盘I/O,提升服务器性能。

        缺点:CPU和内存开销较大。所以这里我们需要合理控制buffer和flush的值,不能太大也不能太小,根据服务配置灵活控制。

        在高并发场景下,建议开启日志缓存,在一定程度上CPU和内存开销虽大,但网站服务性能会有所提升,可以提高用户体验。 

注意1:当启用buffer时,符合以下情况的日志将会直接写入文件

        ①.下一行日志无法放入缓冲区;

        ②.缓冲数据的时间超过了 flush 参数的指定时间;

        ③.当工作进程重新打开日志文件(-s reopen)或关闭时;

注意2:当/path路径包含Nginx变量(0.7.6+)时,这些日志会有以下限制条件:

        ①.工作进程的运行用户(user指令设置的用户)要有在/path目录下创建文件的权限;

        ②.日志将不再被缓存

        ③.每次日志写入都要打开和关闭文件。但是,由于常用文件的描述符可以存储在缓存区,因此在 open_log_file_cache 指定的有效时间([valid=time])内,可以继续写入旧文件。

        ④.在每次写日志时,都会检查请求的根目录是否存在,如果不存在,就不会创建日志。因此,最好在同一配置层同时指定 root 和 access_log。

server {
    root       /spool/vhost/data/$host;
    access_log /spool/vhost/logs/$host;
    ...
}

注意3:同一个日志文件只能配置一次缓存压缩策略,最好先在高级配置级别(http域)设置缓存压缩参数,再在低级配置级别指定format。否则会因参数冲突而出现如下错误:

nginx: [emerg] access_log "logs/access.log" already defined with conflicting parameters in /usr/local/nginx/conf/nginx.conf:119
# 正确配置方式
http {

    log_format format1 ···;
    log_format format2 ···;
    access_log  logs/access.log  combined  buffer=32k  flush=10s;
    
    server {
        listen 8688;
        server_name localhost;
        access_log  logs/access.log  format1;
        location / {
            index  index.html index.htm;
        }
    }
    
    server {
        listen 8080;
        server_name localhost;
        access_log  logs/access.log  format2;
        location / {
            index  index.html index.htm;
        }
    }

}

3.5.4 open_log_file_cache 打开日志缓存(文件描述符缓存)

Syntax:    open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
                open_log_file_cache off;
Default:    open_log_file_cache off;
Context:   http, server, location

        默认配置下,Nginx 每次将缓冲区日志数据写入磁盘文件前,都需要先打开文件并获得文件描述符,然后再向该文件描述符的文件中写入日志数据,最后关闭该文件描述符的文件。该指令把打开文件的文件描述符(文件句柄)存储在缓存中,进而提升写入日志的效率;

        当access_log /path路径包含Nginx变量(0.7.6+)时,通过设置buffer、flush这样的方式设置日志缓存将不再生效,此时,我们可以使用open_log_file_cache指令来设置日志缓存。

        定义一个缓存,用于存储(文件路径包含变量的)常用日志的文件描述符。该指令有以下参数:

  • max:设置缓存中存储的文件描述符的最大数量,如果超过该值,则使用LRU算法来关闭文件描述符。
  • inactive:设置缓存描述符关闭的时间(如果在此期间没有被访问),可以理解成文件描述符在缓存区的存活时间,超时会被清理掉。默认是10秒。
  • min_uses:设置在inactive定义的时间内文件描述符的最小使用次数,以便让描述符在缓存中保持开放。如果≥min_uses,则将该日志文件的描述符记入缓存,否则会被清理掉。默认是1。
  • valid:设置检查同名文件是否仍然存在的时间,缓存检查频率。默认是60秒。
open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
  • off关闭打开日志缓存的功能

3.5.5 log_not_found 记录文件不存在错误日志

Syntax:     log_not_found on | off;
Default:     log_not_found on;
Context:    http, server, location

Enables or disables logging of errors about not found files into error_log.

是否要将“未找到文件/文件不存在”的错误日志记录到error_log中。默认开启。

        如下面的代码片段,这是在error.log日志中记录的 “No such file or directory”错误日志,如果不需要这类错误日志,可以直接在http或server全局设置log_not_found off,也可单独在location域下设置log_not_found off,甚至可以自定义location块,比如自定义一个/favicon.ico 域,并在该域下设置log_not_found off。这样设置后,["/usr/local/nginx/html/favicon.ico" failed (2: No such file or directory),] 这类错误日志不再记录到error.log中,同时我们也将该请求下的access日志也禁用。

2023/11/08 16:13:44 [error] 22202#22202: *437 open() "/usr/local/nginx/html/admindd" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /admindd HTTP/1.1", host: "47.**.**.80"
2023/11/08 16:13:50 [error] 22202#22202: *437 open() "/usr/local/nginx/html/adfg" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /adfg HTTP/1.1", host: "47.**.**.80"
2023/11/08 16:13:57 [error] 22202#22202: *437 open() "/usr/local/nginx/html/wwd" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /wwd HTTP/1.1", host: "47.**.**.80"
2023/11/08 16:14:00 [error] 22202#22202: *437 open() "/usr/local/nginx/html/favicon.ico" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /favicon.ico HTTP/1.1", host: "47.**.**.80"
2023/11/08 16:14:23 [error] 22202#22202: *437 open() "/usr/local/nginx/html/favicon.ico" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /favicon.ico HTTP/1.1", host: "47.**.**.80"
2023/11/08 16:14:25 [error] 22202#22202: *437 open() "/usr/local/nginx/html/favicon.ico" failed (2: No such file or directory), client: 14.145.133.137, server: www.reade******.cn, request: "GET /favicon.ico HTTP/1.1", host: "47.**.**.80"

	location = /favicon.ico {
	    log_not_found  off;	# 禁止记录“文件不存在/文件未找到”错误日志到error.log
	    access_log off; # 禁止记录access日志
	}

3.5.6 log_subrequest  子请求日志

Syntax:    log_subrequest on | off;
Default:    log_subrequest off;
Context:   http, server, location

Enables or disables logging of subrequests into access_log.

是否将子请求日志记录到access_log。默认关闭。

         nginx在处理客户端请求时,会根据自身逻辑需要而在内部建立新的请求,这个新的内部请求就叫子请求,子请求只在Nginx内部进行处理,不与客户端进行交互。log_subrequest配置将影响子请求记录是否要记录到access.log中,默认关闭。

关于子请求的说明请参考其它博主文章

深入理解NGINX-子请求:(5)subrequest执行过程中的主要场景

nginx子请求并发处理_nginx 子请求-CSDN博客

3.6 absolute_redirectserver_name_in_redirect & port_in_redirect请求重定向 

        在Nginx处理请求重定向(Nginx 30X状态码)时,这三个参数值将共同影响Response Headers中的Location值。absolute_redirect的优先级要比其它两个指令的高,因为只有absolute_redirect设为on时,其它两个指令才会生效。

指令absolute_redirect server_name_in_redirect port_in_redirect
语法Syntax:   absolute_redirect on | off;
Default:   absolute_redirect on;
Context:  http, server, location
Syntax:   server_name_in_redirect on | off;
Default:   server_name_in_redirect off;
Context:  http, server, location
Syntax:   port_in_redirect on | off;
Default:   port_in_redirect on;
Context:  http, server, location
模块ngx_http_core_module

官方解释

If disabled, redirects issued by nginx will be relative.

This directive appeared in version 1.11.8.

Enables or disables the use of the primary server name, specified by the server_name directive, in absolute redirects issued by nginx. When the use of the primary server name is disabled, the name from the “Host” request header field is used. If this field is not present, the IP address of the server is used.Enables or disables specifying the port in absolute redirects issued by nginx.
功能

设置Nginx是否以绝对重定向的方式来处理请求重定向。

on:绝对重定向。返回的Location就是完整路径。

off:相对重定向。返回的Location是相对于源始请求的路径,客户端接收到Location后,基于scheme、host、port自动拼接完整请求路径。

设置Nginx处理绝对重定向时是否要用server_name替换原始请求的Host。

on:用server_name替换Host

off:保持原始请求host

设置Nginx处理绝对重定时是否添加nginx监听的端口号。

80和443端口除外

on:Host后添加port(监听)

off:Host不添加port

        为了不占用本文篇幅,这三个指令的组合测试结果请参阅另一篇文章 Nginx(四) absolute_redirect、server_name_in_redirect、port_in_redirect 请求重定向指令组合测试

        Nginx共有六种重定向结果。更详细的讲解请参考这篇文章

3.7 break & return & rewriteif & set 中断、返回、重写

对应模块:ngx_http_rewrite_module,该模块用于使用 PCRE 正则表达式更改请求 URI、返回重定向和有条件地选择配置。

The breakifreturnrewrite, and set directives are processed in the following order:

  • the directives of this module specified on the server level are executed sequentially;
  • repeatedly:
    • location is searched based on a request URI;
    • the directives of this module specified inside the found location are executed sequentially;
    • the loop is repeated if a request URI was rewritten, but not more than 10 times. # 循环过程不能超过10次,并不是rewrite不能超过10次

重要知识点

break,if,return,rewrite和set这5个指令的执行顺序说明如下:

        第一步:按序执行。server层按照配置循序依次执行,请求该重写重写,且无次数限制。server层指令按序执行完毕后进入第二步,根据URI匹配location,开始请求重写循环。如果server层执行了return指令,请求处理过程立刻终止并将指定code和URI或正文返回给客户端;如果server层执行了break或rewrite regex /xxx break/last指令,立即结束第一步,根据URI匹配location,开始请求重写循环。

        第二步:循环执行。根据第一步确认的URI去匹配location,匹配到location后,进入到对应的location中按序执行该模块下的指令。如果请求又被重写,则再匹配location,循环执行上述任务(循环过程不能超过10次),直到找到最终URI。最后再根据最终URI处理请求并将结果返回给客户端。在此过程中,如果执行了return指令,请求处理过程立刻终止并将指定code和URI或正文返回给客户端;如果执行了break或rewrite regex /xxx break指令,循环终止,根据最后一次重写的URI处理请求并将结果返回给客户端;如果执行了rewrite regex /xxx last指令,会立即开始匹配下一个location,当前location下的其它指令不再被执行。

           break,if,return,rewrite和set指令执行顺序请移步另一篇文章 Nginx(五) break,if,return,rewrite和set指令的执行顺序深究

        经过实际测试(详见上文测试10),虽然Nginx在循环重写过程中最多是可以执行11次循环,但在第11次循环中执行rewrite后会抛500异常(如下),所以严格一点的说,Nginx循环重写过程还是不能超过10次。

2023/11/14 23:01:49 [error] 29909#29909: *960 rewrite or internal redirection cycle while processing "/xxx11"
​
The loop is repeated if a request URI was rewritten, but not more than 10 times. 
# 循环过程不能超过10次,并不是rewrite不能超过10次

#下面这种设置方式,原始请求虽被rewrite了11次,但请求仍然成功。
location /one {
    rewrite /one /qqq1;
    rewrite /qqq1 /www2;
    rewrite /www2 /eee3;
    rewrite /eee3 /rrr4;
    rewrite /rrr4 /ttt5;
    rewrite /ttt5 /aaa6;
    rewrite /aaa6 /sss7;
    rewrite /sss7 /ddd8;
    rewrite /ddd8 /fff9;
    rewrite /fff9 /zzz10;
    rewrite /zzz10 /xxx11;
    rewrite /xxx11 /two;
}
location /two {
    rewrite /two /test.html;
}

3.7.1 return 终止并返回

Syntax:     return code [text];
                 return code URL;
                 return URL;
Default:    —
Context:   server, location, if

         该指令用于终止请求处理并将指定的code、重定向URL、响应正文文本返回给客户端。非标准代码 444 关闭连接而不发送响应头。重定向URL和响应正文可以包含变量。当重定向URL不含($scheme)信息(即本地URI)时,absolute_redirect、server_name_in_redirect、port_in_redirect这三个参数将共同影响重定向URL。

3.7.2 break 中断

Syntax:    break;
Default:    —
Context:   server, location, if

        该指令只用于终止当前配置层级的 ngx_http_rewrite_module 指令集。

        当break在server层被执行后,server层其它ngx_http_rewrite_module指令集不再被执行,但不影响location层ngx_http_rewrite_module指令集的执行。

        当break在location层被执行后,请求处理过程不会被终止,只是当前server中所有ngx_http_rewrite_module指令集不再被执行,请求不再被重写,最终URI被确认,Nginx接下来会根据最终URI处理请求并将结果返回给客户端。

# break的最小作用域是Location,如下面这行配置,
# 即使break是在if模块中,但此时的请求重写指令仍然不会被执行。
location /one {
    set $t 1;
    if ($t = 1) {
        break;
    }
    rewrite /one /test.html
}

3.7.3 rewrite 重写

Syntax:    rewrite regex replacement [flag];
Default:    —
Context:   server, location, if

        该指令用于URI的重写和重定向,根据匹配结果修改URI或执行重定向。

        如果请求URI与正则表达式regex匹配,则URI将被字符串replacement替换。rewrite 指令按照它们在配置文件中出现的顺序依次执行。使用flag可以终止对指令的进一步处理。如果replacement“http://”、“https://”或“$scheme”开头,则处理会停止,返回客户端重定向URL。

flag可选参数如下:

        last:停止处理当前层级(如Location级)下的ngx_http_rewrite_module指令集,并用更改后的 URI 重新开始匹配Location。这时如果rewrite指令行下面还有指令,这些指令都不会被执行。内部重定向。

        break:与3.7.2章节的break类似,该指令被执行后,当前server中ngx_http_rewrite_module指令集不再被执行,请求不再被重写,最终URI被确认,Nginx接下来会根据最终URI处理请求并将结果返回给客户端。内部重定向。

        redirect:返回带有 302 代码的临时重定向;此时replacement 不能以"http://"、"https://" 或 "$scheme "开头。客户端地址栏显示的是重定向后的地址,属于外部重定向。

        permanent:返回带有 301 代码的永久重定向。客户端地址栏显示的是重定向后的地址,属于外部重定向。

        如未指定flag参数,Nginx执行完rewrite后,还会继续往下按序执行下面的指令(如return、break等等)。

 3.7.4 rewrite_log 重写结果日志

Syntax:    rewrite_log on | off;
Default:    rewrite_log off;
Context:   http, server, location, if

       设置是否将请求重写结果日志记录到error_log中,日志级别是notice。 默认关闭调试请求重写规则时建议将该指令设置为on。

        注意:配置的error_log 日志级别不能高于notice,否则无法记录rewrite log

error_log  logs/error.log  notice;	# 将error_log日志级别修改为notice,否则rewrite log无法记录。
rewrite_log on;				# 开启记录请求重写结果日志,默认是关闭

3.7.5  internal_redirect 内部重定向

Syntax:     internal_redirect uri;
Default:     —
Context:    server, location

         设置请求内部重定向的 URI。也可以使用命名的位置来代替 URI。uri 值可以包含变量。如果 uri 值为空,则不会进行重定向。

server {
    location / {
        internal_redirect @rate_limited;
    }

    location @rate_limited {
        internal;
        proxy_pass http://backend;
    }
}

3.7.6 if & set

指令ifset
语法Syntax:    if (condition) { ... }
Default:    —
Context:   server, location, if
Syntax:    set $variable value;
Default:    —
Context:   server, location, if
功能

该指令用于条件判断。

condition:条件表达式。可使用Nginx变量、比较操作符、逻辑操作符。

该指令用于设置变量值,如果该变量不存在则初始化并赋值。

$variable:变量名

value:变量值 

 3.7.7 uninitialized_variable_warn 变量未初始化警告日志

Syntax:    uninitialized_variable_warn on | off;
Default:    uninitialized_variable_warn on;
Context:   http, server, location, if

        该指令用于控制是否记录变量未初始化的警告日志,日志级别是warn

        注意变量未初始化警告日志的级别是warn,所以error_log设置的日志级别不能高于warn。

3.7.8 allow 允许访问

Syntax:     allow address | CIDR | unix: | all;
Default:     —
Context:    http, server, location, limit_except

        指定允许访问的网络或地址。如果指定了特殊值 unix:(1.5.1),则允许所有UNIX域的连接访问。

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

3.7.9 deny 拒绝访问

Syntax:     deny address | CIDR | unix: | all;
Default:     —
Context:    http, server, location, limit_except

        指定拒绝访问的网络或地址。如果指定了特殊值 unix:(1.5.1),则拒绝所有UNIX域的连接访问。

3.8 error_page 错误页面&内部请求

3.8.1 error_page 

Syntax:    error_page code ... [=[response]] uri;
Default:    —
Context:   http, server, location, if in location

        该指令用于将指定响应码重定向到特定URI或URL。该指令可以继承上级配置。

        code可以包含多个,中间用空格隔开,uri也可以包含变量,例如:

error_page 404             /404.html;
error_page 500 502 503 504 /50x.html;

        此外,还可以使用"=response "语法将响应代码更改为其他代码,例如:

error_page 404 =200 /empty.gif;

测试1:error_page 404 =200 /test.html;

server {
    ···
    rewrite /t0 /t1;
    break;
    set $sn 1;
    error_page 404 =200 /test.html;
    
    location / {
        index  index.html index.htm;
    }
}

测试2:error_page 404 =200 /t2;

server {
    ···
    rewrite /t0 /t1;
    break;
    set $sn 1;
    error_page 404 =200 /t;
    
    location /t2 {
	    rewrite /t2 /t3;
	}

    location / {
        index  index.html index.htm;
    }
}
2023/11/18 15:42:39 [notice] 13347#13347: *443 "/t0" matches "/t0", client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [notice] 13347#13347: *443 rewritten data: "/t1", args: "", client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [error] 13347#13347: *443 open() "/usr/local/nginx/pages/t1" failed (2: No such file or directory), client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [notice] 13347#13347: *443 "/t0" does not match "/t2", client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [notice] 13347#13347: *443 "/t2" matches "/t2", client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [notice] 13347#13347: *443 rewritten data: "/t3", args: "", client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"
2023/11/18 15:42:39 [error] 13347#13347: *443 open() "/usr/local/nginx/pages/t3" failed (2: No such file or directory), client: 14.145.163.156, server: www.read*********.cn, request: "GET /t0 HTTP/1.1", host: "www.readerschool.cn:8688"

        如果请求由代理服务器处理并返回响应码,可以用如下方式进行响应返回:

error_page 404 = /404.php;

        如果在内部重定向过程中不需要更改 URI 和方法,可以将错误处理传递到指定位置,例如:

location / {
    error_page 404 = @fallback;
}

location @fallback {
    proxy_pass http://backend;
}

        还可以使用URL重定向来进行错误处理:

error_page 403      http://example.com/forbidden.html;
error_page 404 =301 http://example.com/notfound.html;

3.8.2 recursive_error_pages 

Syntax:     recursive_error_pages on | off;
Default:     recursive_error_pages off;
Context:    http, server, location

        设置是否允许使用error_page指令进行多次重定向。注意,Nginx内部重定向次数不能超过10次。

3.8.3 internal 内部请求

Syntax:     internal;
Default:     —
Context:    location

        指定特定的location只能用于内部请求。如果是外部请求,则返回404错误。

        常见的内部请求有如下:

  • 通过error_page,index,random_index和try_files指令重定向的请求;请注意,Nginx内部重定向次数不得超过10次,否则返回500错误
  • 由上游服务器通过“ X-Accel-Redirect”响应头字段重定向的请求;
  • 由ngx_http_ssi_module模块的“ include virtual”命令,ngx_http_addition_module模块指令以及auth_request和mirror指令形成的子请求;
  • rewrite指令更改了请求。
error_page 404 /404.html;
location = /404.html {
    internal;
}

3.9 root & alias & try_files 

3.9.1 root & alias

指令rootalias
语法Syntax:     root path;
Default:     root html;
Context:    http, server, location
Syntax:      alias path;
Default:      —
Context:     location 
功能设置请求文件根目录设置请求文件目录别名
相同点都是用来设置请求文件路径
不同点

root翻译成中文是“根部、根茎、根”的意思;

alias翻译成中文是“化名、别名、替换名”的意思;

root是用来指定请求文件的上层目录,也就是根目录;而alias是用来替换请求路径,或者可以理解为给原请求路径起别名,最终是为了建立请求路径和真实路径间的映射关系。

思考:alias替换的是哪部分内容呢?

       root和alias指令的区别及测试结论请参阅另一篇篇文章 Nginx(七) root和alias的区别及详细测试 

3.9.2 try_files

Syntax:     try_files file ... uri;
                 try_files file ... =code;
Default:     —
Context:    server, location 

        该指令用于设置Nginx检索文件时的路径顺序,并使用第一个找到的文件进行请求处理。文件检索根路径是root或alias指令的配置参数。可以通过在名称末尾添加斜杠来检查目录是否存在,例如“ $uri/”。如果未找到任何文件,则内部重定向到最后一个参数指定的uri。最后一个参数也可以是一个指定命名的文件或指定code。

try_files $uri /images/default.gif;    # 如果未找到任何文件,则内部重定向到 /images/default.gif

try_files $uri $uri/index.html $uri.html =404;    # 如果前两个参数未找到文件,则查找$uri.html,如果还未查找到则返回404.

         try_files 指令测试请参考 Nginx(八) try_files 指令测试

3.10 indexautoindex & random_index

指令indexautoindexrandom_index
语法Syntax:    index file ...;
Default:    index index.html;
Context:   http, server, location
Syntax:     autoindex on | off;
Default:     autoindex off;
Context:    http, server, location
Syntax:     random_index on | off;
Default:     random_index off;
Context:    location
模块ngx_http_index_modulengx_http_autoindex_modulengx_http_random_index_module
功能设置Nginx首页。

启用或禁用目录列表输出(以目录的方式列出根目录下所有文件和文件夹)。

当Nginx处理以斜杠('/')结尾的请求时,如果无法找到index文件,则将请求传递给autoindex处理,autoindex选择是否将目录列表(root定义的目录)返回给客户端。

目录中随机选择一个文件作为首页,前提是目录下有多个文件。

也是用于处理以斜杠('/')结尾的请求,但处理请求的优先级比index指令高,是在index指令之前触发。index指令是在目录下按照文件名配置顺序依次查找,而random_index是目录下随机选择一个文件并返回

备注

文件名可以包含变量。

文件将按配置顺序进行检查。

ngx_http_index_module 模块是处理以斜杠('/')结尾的请求。

默认关闭(off)。

主要用于文件浏览,无特殊使用场景时,不建议开启该功能。如需开启,请配合autoindex_exact_size 、autoindex_format 、autoindex_localtime 这3个指令一起使用。

默认情况下Nginx未构建此模块,应使用"--with-http_random_index_module"配置参数启用它。

思考:什么场景下会用到该指令?设置多个系统首页,用户每次访问时首页都不一样?有实用经验的麻烦评论分享下,感谢!

# 文件名可以带变量,文件列表的最后一项可以是具有绝对路径的文件。
index index.$geo.html index.0.html /index.html;

location / {
    # 未配置index时,Nginx默认配置是"index index.html;"。
}

3.11 Asynchronous I/O

BIO(Blocking Input/Output):同步阻塞I/O

NIO(Non-blocking Input/Output):同步非阻塞I/O

AIO(Asynchronous Input/Output):异步非阻塞I/O

Buffer Input/Output:缓存I/O

Direct Input/Output:直接I/O,对应linux的directio()系统调用。读写文件时不经过内核缓冲区,直接在用户缓冲区和磁盘空间之间进行数据读写,减少数据拷贝过程,降低CPU和内存开销。读写大文件时(如果文件超大将无法缓存到内存),建议用直接I/O。读写常用高频文件建议还是用缓存I/O,充分发挥缓存区数据,减少读盘次数。具体要不要用directio,需要根据使用场景和服务器性能做一个利弊权衡,无强制要求。

Sendfile:零拷贝(相对用户态的零拷贝,非绝对零拷贝),linux 2.1版本提供的一个专门用于文件发送的系统调用函数sendfile()。

sendfile()系统调用先用DMA(直接内存访问)引擎将文件数据从磁盘空间拷贝到内核缓冲区,再将数据从内核缓冲区拷贝到内核socket缓冲区(内核版本2.4之后,仅将数据的类型、位置、大小相关的文件元数据拷贝到socket缓存区),最后再用DMA引擎将数据拷贝到协议引擎。数据不会拷贝到用户缓冲区(应用程序,比如Nginx),所以相比传统I/O,减少了2次上下文切换,减少1(2)次数据拷贝过程,降低了CPU和内存开销。

sendfile = off :硬盘 → 内核缓冲区 → 用户缓冲区 → 内核网络缓冲区 → 网络接口

sendfile = on :硬盘 → 内核缓冲区 → 内核网络缓冲区 → 网络接口

        当客户端向服务器请求静态文件时,如果Nginx开启了sendfile,且该文件可以用sendfile发送,那么此时Nginx只需给系统内核发送一条sendfile()指令,之后由内核负责读取文件并将数据发送给客户端,无需Nginx参与。

3.11.1 aio & directio & sendfile 

指令aiodirectiosendfile
语法Syntax:    aio on | off | threads[=pool];
Default:    aio off;
Context:    http, server, location
Syntax:    directio size | off;
Default:    directio off;
Context:    http, server, location
Syntax:    sendfile on | off;
Default:    sendfile off;
Context:    http, server, location, if in location
功能

设置是否启用文件异步I/O功能。

默认关闭。

设置启用directio功能时的文件大小临界值。或者直接关闭directio功能。

默认关闭。

设置是否启用sendfile()系统调用来发送文件。

默认关闭。

备注

Nginx 版本不低于0.8.11

使用aio时,linux系统内核版本不能低于2.6.22,且需开启directio,否则读取数据会阻塞。

另外,aio还可配合threads一起使用,采用多线程读取和发送文件,性能更佳。参考章节1.5


location /video/ {
        aio            on;

        #aio        threads;
        directio       512;

        sendfile on;
        output_buffers 1 128k;
}

Nginx 版本不低于0.7.7。

主要用于高效传输文件

当文件大小大于等于size时,使用directio读取文件,此时会禁用sendfile。

注意:linux系统中,directio只能用于读取基于512字节边界对齐(由directio_alignment设置)的blocks,文件末尾那些未对齐的block将使用阻塞模式读取。对于字节范围请求和不是从文件开头开始的FLV请求也是如此:在文件的开头和末尾读取那些未对齐的数据将使用阻塞模式读取。这里所谓的对齐,就是文件数据在内存页中的缓存情况。

主要用于高效传输文件,同时开启aio时,aio会提前给sendfile预加载数据,读取文件更高效。

        directio和sendfile都针对的是静态文件,所以Nginx作为文件服务器时,开启sendfile可明显提高服务器性能。如果Nginx是用来做反向代理的,使用该指令没有太多用处。Nginx作为web容器时,建议开启该功能。


location /video/ {
        sendfile       on;
        tcp_nopush     on;
        aio            on;
}

location /video/ {
    sendfile       on;
    aio            on;
    directio       8m;
}

# 当文件大小大于或等于8M时,aio配合directio同时读取文件,sendfile自动禁用;
# 当文件大小小于8M时,aio配合sendfile同时读取文件,directio自动禁用。

 注意

        1.如果想配置aio on;需要构建 --with-file-aio 模块,否则会报如下错误。好像nginx默认未构建该模块,我是构建了该模块后才能配置aio on,否则只能配置成aio threads;

2023/11/26 17:07:31 [emerg] 12144#12144: "aio on" is unsupported on this platform in /usr/local/nginx/conf/nginx.conf:86

         关于aio、directio、sendfile的组合使用测试和测试结论,我专门写了两篇文章,如果感兴趣请移步下面两篇文章:

Nginx(九) aio & sendfile & directio 组合使用测试(1)

Nginx(十) aio & sendfile & directio 组合使用测试(2)

3.11.2 aio_write 

Syntax:     aio_write on | off;
Default:     aio_write off;
Context:    http, server, location
This directive appeared in version 1.9.13.

        用于控制在写入文件时是否要用aio。目前,仅在配置了aio threads时该功能才有效,而且仅限于将从代理服务器接收到的数据写入临时文件。

3.11.3 directio_alignment directio对齐方式

Syntax:      directio_alignment size;
Default:     directio_alignment 512;
Context:    http, server, location
This directive appeared in version 0.8.11.

         用于设置directio的对齐方式。在大多数情况下,512字节的对齐方式已经足够。但在Linux中使用 XFS 时,需要将其增加到 4K。

3.11.4 sendfile_max_chunk 

Syntax:     sendfile_max_chunk size;
Default:     sendfile_max_chunk 2m;
Context:    http, server, location

        该指令用于限制每次 sendfile() 调用可传输的最大数据尺寸。如果不限制的话,一个快速连接将独占整个工作进程。

3.12 延迟或立即推送

3.12.1 tcp_nopush & tcp_nodelay 

        服务端在将响应返回给客户端前,会先将数据写入socket缓冲区,再由tcp协议栈把数据传给网络协议,最终由网络协议把数据发送给客户端。那么tcp堆栈传输数据的策略是什么呢?多久传一次?一次传多少?默认情况下,tcp堆栈会等待0.2秒,等待结束后将这段时间内的数据进行打包再一并发送,而tcp_nopush和tcp_nodelay与默认策略却恰恰相反,tcp_nopush是等接收的数据达到一个MSS后(Nagle 算法)才打包发送,tcp_nodelay是不进行等待,有数据就立即发送。所以tcp_nodelay追求的是响应的“实时性”,tcp_nopush追求的是响应的“有效性”,默认策略是一种平衡策略,并不追求极致。

        tcp_nopush和tcp_nodelay虽然在功能上是“互斥”的,但在实际使用过程中它们是可以配合使用。比如,当响应的最后一段报文小于一个MSS时,tcp_nodelay此时会将数据立即发送出去,这样就能最大效率的利用网络,所以在Nginx配置文件中这两个指令是可以同时开启的。

指令tcp_nopush tcp_nodelay
语法Syntax:     tcp_nopush on | off;
Default:     tcp_nopush off;
Context:    http, server, location
Syntax:     tcp_nodelay on | off;
Default:     tcp_nodelay on;
Context:    http, server, location
功能

追求响应“有效性”。

设置是否开启tcp_nopush,默认关闭(off)。

追求响应“实时性”。

设置是否开启tcp_nodelay,默认开启(on)。

注意只有在开启sendfile时,该指令配置才有效。

只有在开启Keep-Alive(HTTP长连接)时,该指令配置才有效。

此外,在SSL连接、无缓冲代理和WebSocket代理中也会启用该指令。

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
}

3.12.2 postpone_output 延迟发送

Syntax:     postpone_output size;
Default:     postpone_output 1460;
Context:    http, server, location

        用于设置Nginx延迟传输数据的阈值,单位是字节,刚好对应TCP协议的MSS大小。如果值为零,Nginx会立即发送数据,否则只有当待发送数据累积到该值时,Nginx才会传输数据

3.13 file_cache文件描述符缓存

3.13.1 open_file_cache

Syntax:      open_file_cache off;
                  open_file_cache max=N [inactive=time];
Default:     open_file_cache off;
Context:    http, server, location 

        设置是否缓存打开过文件的信息,默认关闭。启用该指令后可以存储以下内容的缓存:

                1、打开文件的相关元数据,如文件描述符、大小、位置、最后修改时间等;思考:为什么只缓存元数据,不缓存文件内容(参考sendfile拷贝原则)?

                2、有关目录存在情况的信息;

                3、文件查找错误信息,如“文件未找到”、“没有读取权限”等。可通过 open_file_cache_errors(3.13.2 章节介绍)指令单独启用错误缓存。

        该指令有以下几个参数:

                max:设置缓存中文件的最大数量(最多缓存多少个文件);缓存溢出后,将按照最近最少使用(LRU,Least Recently Used)策略删除数据;

                inactive:设置非活动时间段。定义一个时间,如果在这段时间内该文件未被访问过,则从缓存中删除;默认为 60 秒;

                off:禁用缓存,默认。

# 最多缓存1000个文件,文件非活动时间为20秒。20秒内未被访问过的文件缓存将被清除。
open_file_cache  max=1000 inactive=20s;

# 最多缓存300个文件,文件非活动时间为10天。
open_file_cache  max=300 inactive=10d;


location / {
    open_file_cache max=1000 inactive=30s;  # 最多缓存1000个文件,非活动时间段为10秒
    open_file_cache_valid 60s;        # 60秒监测一次缓存有效性
    open_file_cache_min_uses 5;       # inactive时间段内至少要被访问5次才被标记为活跃
    open_file_cache_errors on;        # 开启缓存文件打开错误信息
 
    index  index.html index.php;
}

3.13.2 open_file_cache_errors

Syntax:     open_file_cache_errors on | off;
Default:     open_file_cache_errors off;
Context:    http, server, location

        设置是否缓存文件打开/查找错误信息,默认关闭。如果启用open_file_cache_errors,下次请求同一资源(不查找资源)时,Nginx会直接报错。

3.13.3 open_file_cache_min_uses

Syntax:     open_file_cache_min_uses number;
Default:     open_file_cache_min_uses 1;
Context:    http, server, location

        设置在inactive时间段内文件至少被访问多少次才被标记为活跃文件(文件描述符在缓存中保持打开状态)。

3.13.4 open_file_cache_valid

Syntax:     open_file_cache_valid time;
Default:     open_file_cache_valid 60s;
Context:    http, server, location

        设置多长时间检查一次缓存的有效信息,如果缓存失效(文件可能被修改)则更新。如果文件频繁更新,建议将此值设置小一些。

3.14 client body请求体

        学习这部分内容时,我们需要重点关注buffer,凡是涉及到buffer的指令,都可以作为我们后期在实际使用过程中的性能优化点。

3.14.1 client_body_buffer_size 请求体缓存区大小

Syntax:     client_body_buffer_size size;
Default:     client_body_buffer_size 8k|16k;
Context:    http, server, location

        该指令用于设置读取客户端请求体时的缓冲区大小,默认情况下,缓冲区大小等于两个内存页。在X86、X86-64或32位系统中,size默认是8K,其它64位操作系统中默认是16K。

        当请求体数据小于client_body_buffer_size时,Nginx会将数据写入在内存中;当请求体数据大于client_body_buffer_size,而小于client_max_body_size时,Nginx会将整个或部分数据写入临时文件(client_body_temp_path指令设置)中。

        如果想提高请求处理效率,可以把所有请求体数据都存储在内存中,此时需要将client_body_buffer_size和client_max_body_size设置为相同的值。此时,我们必须得综合考虑服务器在请求处理高峰期时内存能否满足需求、请求体最大的可能值等等其它因素,毕竟打铁还须自身硬。

3.14.2 client_max_body_size 请求体最大允许值

Syntax:     client_max_body_size size;
Default:     client_max_body_size 1m;
Context:    http, server, location

         该指令用于设置客户端请求主体的最大允许值,默认是1M。在“ Content-Length”的headers字段中指定。当客户端请求体大小超过配置值时,则向客户端(http协议)返回 413(请求体过大)错误,请求将终止,不会传递给后端服务。请注意,浏览器无法正确显示此错误。将 size 设置为 0 时,将不再检查客户端请求体的大小。所以,当部分请求的请求体过大或需要上传文件时,需要将该值适当调大一些,或者直接设置为0。

3.14.3 client_body_in_file_only 仅用临时文件

Syntax:     client_body_in_file_only on | clean | off;
Default:     client_body_in_file_only off;
Context:    http, server, location

        该指令用于设置是否将客户端请求体数据保存到临时文件中(不会保存到内存中),默认为off,主要是在系统调试期间用。这个指令跟client_body_buffer_size 是冲突的。

        on:请求体数据仅保存到临时文件中,请求结束后临时文件不被删除

        clean:请求体数据仅保存到临时文件中,请求结束后临时文件会被删除

        off:按照3.14.1章节描述的策略存储请求体数据。

        注意启用该指令后,请求体数据保存到了临时文件中,变量$request_body将失效,需要使用$request_body_file变量获取临时文件信息。

3.14.4 client_body_temp_path 临时文件目录

Syntax:     client_body_temp_path path [level1 [level2 [level3]]];
Default:     client_body_temp_path client_body_temp;
Context:    http, server, location

        该指令用于设置存储客户端请求体数据的临时文件的目录,默认是Nginx安装路径下的client_body_temp文件夹。

        注意由于Nginx工作进程需要在该目录下写入文件,所以一要确保该目录存在,二要确保Nginx工作进程执行者在该目录下有读写权限,否则无法写入文件。

        path:指定存储临时文件的(根)目录。

        level1、level2和level3又代表什么意思呢?这3个参数分别对应path目录下的3层子目录。如果只配置了level1和level2,那么Nginx就可以在path目录下创建两级子目录。3个同时配置时,可创建三级子目录,最多也只能建到三级子目录。level1、level2和level3的取值范围是[1-9],level值控制对应层级目录的命名数字范围和位数(参考下面的代码)。不配置level时,所有临时文件都在path目录下。配置level时,临时文件将在每个底层目录下轮流存储。

# 根目录是Nginx安装路径下的clientFile,该目录下可创建两级子目录,第一级子目录命名范围是[0-9],第二级子目录命名范围是[000000000,9999999999]
client_body_temp_path clientFile  1 9;

# 根目录是Nginx安装路径下的clientFile,该目录下可创建两级子目录,第一级子目录命名范围是[0-9],第二级子目录命名范围是[00,99]
client_body_temp_path clientFile  1 2;

# 根目录是Nginx安装路径下的clientFile,该目录下可创建三级子目录,第一级子目录命名范围是[00-99],第二级子目录命名范围是[0,9],第三级子目录命名范围是[0,9]
client_body_temp_path clientFile  2 1 1;
# client_body_temp_path clientFile  1 1;  
# 截取一部分日志

2023/11/21 15:43:57 [notice] 23846#23846: *19127 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/4/3/0000011334, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:43:58 [notice] 23846#23846: *19129 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/5/3/0000011335, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:43:58 [notice] 23846#23846: *19131 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/6/3/0000011336, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:43:59 [notice] 23846#23846: *19133 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/7/3/0000011337, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:00 [notice] 23846#23846: *19135 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/8/3/0000011338, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:00 [notice] 23846#23846: *19137 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/9/3/0000011339, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:01 [notice] 23846#23846: *19139 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/0/4/0000011340, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:01 [notice] 23846#23846: *19141 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/1/4/0000011341, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:02 [notice] 23846#23846: *19143 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/2/4/0000011342, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:03 [notice] 23846#23846: *19145 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/3/4/0000011343, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:03 [notice] 23846#23846: *19147 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/4/4/0000011344, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:04 [notice] 23846#23846: *19149 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/5/4/0000011345, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:04 [notice] 23846#23846: *19151 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/6/4/0000011346, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:05 [notice] 23846#23846: *19153 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/7/4/0000011347, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:06 [notice] 23846#23846: *19155 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/8/4/0000011348, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:06 [notice] 23846#23846: *19157 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/9/4/0000011349, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"
2023/11/21 15:44:07 [notice] 23846#23846: *19159 a client request body is buffered to a temporary file /usr/local/nginx/clientFile/0/5/0000011350, client: 14.145.163.156, server: www.read********.cn, request: "POST /t1 HTTP/1.1", host: "www.read********.cn:8688"

3.14.5 client_body_in_single_buffer 单独缓冲区

Syntax:     client_body_in_single_buffer on | off;
Default:     client_body_in_single_buffer off;
Context:    http, server, location

        该指令用于设置Nginx是否要将客户端请求体数据保存在单个缓冲区中,默认关闭。使用$request_body变量时,建议启用该指令,可以减少数据拷贝次数。

3.14.6 client_body_timeout 接收请求体等待超时时间

Syntax:     client_body_timeout time;
Default:     client_body_timeout 60s;
Context:    http, server, location

        该指令用于设置接收客户端请求体的等待超时时间,默认是60秒。这个设置的是从建立通信连接开始,到服务端接收到客户端发送的请求体后的最大间隔时间,而不是整个请求体传输过程的超时时间。如果客户端建立连接后,在超时时间段内未传输任何数据,Nginx会中断连接并返回408(Request Time-out)错误。

3.15 client header 请求头

3.15.1 client_header_buffer_size 请求头缓冲区大小

Syntax:     client_header_buffer_size size;
Default:     client_header_buffer_size 1k;
Context:    http, server

        类似于client_body_buffer_size指令,用于设置读取客户端请求头和请求行时的缓冲区大小,默认是1K。对于大多数请求,1K缓冲区已足够。

        Nginx接收到Htpp请求后,会将请求头和请求行数据保存在该缓冲区,如果请求头和请求行数据超过client_header_buffer_size设置的缓冲区大小,则会分配给由large_client_header_buffers指令配置的更大的缓冲区。

3.15.2 large_client_header_buffers 更大的请求头缓冲区

Syntax:     large_client_header_buffers number size;
Default:     large_client_header_buffers 4 8k;
Context:    http, server

        该指令用于设置读取较大的客户端请求头和请求行时的缓冲区最大number和size,默认在内存中分配4个大小为8K的缓冲区。Nginx处理大型客户端请求时,可用的缓冲区一共是32K,Nginx会按需将缓存分配给请求头和请求行,但每个请求行数据不能超过一个缓冲区的大小(8K),否则Nginx会中断请求并向客户端返回 414(请求 URI 太大)错误。请求头中的每个字段也不能超过一个缓冲区的大小,否则中断请求并向客户端返回400(错误请求)错误。如果在请求处理结束之后,连接转换为保持活动状态(持久连接),则会释放这些缓冲区。

3.15.3 client_header_timeout 接收请求头等待超时时间

Syntax:     client_header_timeout time;
Default:     client_header_timeout 60s;
Context:    http, server

        该指令用于设置接收客户端请求头的等待超时时间,默认是60秒。如果从建立连接开始,客户端在此时间内未传输完整的请求Headers,Nginx会中断请求并向客户端返回408(Request Time-out)错误。

3.15.4 ignore_invalid_headers 忽略无效请求头字段

Syntax:     ignore_invalid_headers on | off;
Default:     ignore_invalid_headers on;
Context:    http, server

        设置是否忽略请求头中的无效字段,默认是忽略。有效名称由英文字母,数字,连字符和可能的下划线组成。

        如果该指令是在server级别上指定的,则仅当服务器为默认服务器时才使用其值。指定的值也适用于在相同地址和端口上侦听的所有虚拟服务器。

3.15.5 underscores_in_headers 请求头字段下划线

Syntax:     underscores_in_headers on | off;
Default:     underscores_in_headers off;
Context:    http, server

        设置是否允许客户端请求头中的字段有下划线,默认不允许。当请求头字段不允许有下划线时,有下划线的字段会被标记为无效字段,该字段是否会被忽略由 ignore_invalid_headers 指令控制。

        如果该指令是在server级别上指定的,则仅当服务器为默认服务器时才使用其值。指定的值也适用于在相同地址和端口上侦听的所有虚拟服务器。

3.15.6 add_header 响应头添加字段

Syntax:    add_header name value [always];
Default:    —
Context:    http, server, location, if in location

        只有在响应代码为200、201、204、206、301、302、303、304、307或308时,才会将指定字段添加到响应头中。但是,如果指定了 always 参数,那么无论响应代码如何,都会将指定字段添加到响应头中。参数值可包含变量。

        name:字段名称。

        value:字段值。

        可以配置多个add_header指令。只有在当前配置层没有 add_header 指令时,才会从上一级配置层继承该指令

3.15.7 add_trailer 响应末尾添加字段

Syntax:    add_trailer name value [always];
Default:    —
Context:    http, server, location, if in location
This directive appeared in version 1.13.2.

        只有在响应代码为200、201、206、301、302、303、304、307或308时,才会将指定字段添加到响应末尾。但是,如果指定了 always 参数,那么无论响应代码如何,都会将指定字段添加到响应末尾。参数值可包含变量。

        name:字段名称。

        value:字段值。

        可以配置多个add_trailer指令。只有在当前配置层没有 add_trailer 指令时,才会从上一级配置层继承该指令

3.15.8 expires 响应缓存过期时间

Syntax:    expires [modified] time;
                expires epoch | max | off;
Default:    expires off;
Context:    http, server, location, if in location

        设置是否在响应头中添加或修改 "Expires"和 "Cache-Control"这两个字段,前提是响应码为200、201、204、206、301、302、303、304、307或308。time参数可以是正值或负值。客户端会根据这两个字段的值来校验本地缓存是否仍有效。

  • expires设置成相对时间 modified

        此时,实际过期时间Expires是根据当前时间和该指令指定的time计算和值后得出的。Cache-Control字段的值取决于指定time的符号,如果是负值,“Cache-Control: no-cache”。如果是正值或0,“Cache-Control: max-age=t”,t 对应就是该指令的time值,单位是秒。

server {
    expires    12h;           # 设置Expires为当前时间过后的12小时,Cache-Control为12h
    expires    modified +12h; # 编辑Expires增加12小时,Cache-Control的值增加12小时
    expires    $expires;      # 根据变量$expires来设置缓存时间
}
  • expires设置成绝对时间 @

        使用"@"前缀指定一天中的某个时间电为过期时间:

server {
    expires @15h30m;    # 设置Expires为当天的15点30分,Cache-Control为到当天15点30分的时间差
}
  • expires设置成无有效期(纪元) epoch
server {
    expires epoch; 
    # 此时Expires = "Thu, 01 Jan 1970 00:00:01 GMT",Cache-Control = "no-cache",表示当前响应数据的缓存无有效期。
}
  • expires设置成最大值 max
server {
    expires max;  # 此时Expires =  "Thu, 31 Dec 2037 23:55:55 GMT",Cache-Control = 10 years。
}
  • expires设置成 off:此时不添加或修改响应头字段 "Expires" 和 "Cache-Control" 。

3.16 subrequest_output_buffer_size 子请求缓存区大小

Syntax:     subrequest_output_buffer_size size;
Default:     subrequest_output_buffer_size 4k|8k;
Context:    http, server, location
This directive appeared in version 1.13.10.

        用于设置存储子请求响应正文的缓冲区大小。默认情况下,缓冲区大小等于一个内存页面。这要么是4K,要么是8K,取决于操作系统。然而,它可以做得更小。

        该指令仅适用于响应主体保存在内存中的子请求。例如,由SSI创建的子请求。

3.17 GZip压缩

        Gzip(GNU zip)是Http的三种标准压缩格式之一。Gzip可压缩传输如html、css、java等文件,传输文本文件效果尤为明显,开启后所需流量会将至1/4 ~ 1/3。参考文章前端开发者必备的Nginx知识 

        文件压缩是 CPU 密集型的操作,此过程会耗费 CPU 资源,特别是当文件较大或压缩率较高时,耗费的CPU资源会更多。因此,对图片、视频或其它大文件进行gzip压缩是不明智的,况且,音视频文件本来就是经过图形压缩算法压缩过的,再进行gzip压缩就得不偿失了。最适合进行gzip压缩的还是普通的文本类型文件,如纯文本文件、css、html、js、xml等文件。

        启用gzip需要客户端和服务端的同时支持,如果客户端支持gzip的解析,那么我们可以通过修改nginx配置来让服务端支持gzip。目前大多数浏览器都支持gzip解析,可通过查看请求头中的“Accept-Encoding”来判断客户端是否支持gzip。而服务端,我们只需在Nginx配置文件中将gzip指令设置为on就可开启gzip,或将gzip_static指令设置为on也可以。

        gzip可以理解成动态压缩,也就是实时压缩,当接收到客户端请求(Accept-Encoding:gzip)后,CPU才去压缩请求文件。

        gzip_static可以理解成静态压缩,其实它压根也没有进行文件压缩,如果真需要压缩最后还是交个了gzip来执行。当接收到客户端请求后,如果请求的文件已经被提前压缩过(.gz),那么nginx会直接将.gz文件返回给客户端。如果文件没有被压缩过且gzip=on,那么就由gzip负责将源文件压缩后再返回给客户端,否则直接返回源文件给客户端。

3.17.1 gzip 动态压缩

Syntax:    gzip on | off;
Default:    gzip off;
Context:   http, server, location, if in location

        该指令用于设置是否开启gzip功能,默认为关闭。开启gzip压缩服务可缩短传输时间,提高访问速度,相应的会增加cpu开销。

未开启gzip:

开启gzip,gzip_comp_level = 1:

 3.17.2 gzip_types 压缩类型

Syntax:    gzip_types mime-type ...;
Default:    gzip_types text/html;
Context:   http, server, location

        该指令用于设置对哪些MIME类型的文件启用gzip压缩,配置为"*"时,表示对所有MIME类型文件都启用gzip压缩。Nginx始终压缩满足压缩条件的"text/html"文件,所以不用专门配置"text/html",否则Nginx会警告配置冲突。

gzip_types *; # 所有类型都被压缩,前提是Nginx能识别该文件类型
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml video/mp4;

 3.17.3 gzip_comp_level 压缩等级

Syntax:    gzip_comp_level level;
Default:    gzip_comp_level 1;
Context:   http, server, location

        设置gzip压缩级别,level取值范围是[1-9],默认值是1。level越大压缩率越高,传输效率越高,压缩时间越长,但更消耗CPU资源。我们在生产环境中设置level时,需要综合考虑网站资源大小和cpu使用率,没有绝对的最佳level,但level=1确实有点低。如果文件普遍较小,level不建议过高(3~5即可),因为设置大一点时性能提升不太,反而cpu负载会过高。

gzip_comp_level = 1:

gzip_comp_level = 5:

gzip_comp_level = 9:

        另外,还可以用变量$gzip_ratio来测试压缩率。 

gzip_comp_level = 1:"gzip_ratio":"80.69"

{"time_iso8601":"2023-11-25T15:24:07+08:00","request_uri":"/test.html","status":"200","bytes_sent":"1972","gzip_ratio":"80.69",}

gzip_comp_level = 3:"gzip_ratio":"74.99"

{"time_iso8601":"2023-11-25T15:25:34+08:00","request_uri":"/test.html","status":"200","bytes_sent":"2099","gzip_ratio":"74.99",}

gzip_comp_level = 5:"gzip_ratio":"155.70"

{"time_iso8601":"2023-11-25T15:27:02+08:00","request_uri":"/test.html","status":"200","bytes_sent":"1167","gzip_ratio":"155.70",}

gzip_comp_level = 9:"gzip_ratio":"194.01"

{"time_iso8601":"2023-11-25T15:28:07+08:00","request_uri":"/test.html","status":"200","bytes_sent":"996","gzip_ratio":"194.01",}

 3.17.4 gzip_min_length 压缩最小长度

Syntax:    gzip_min_length length;
Default:    gzip_min_length 20;
Context:   http, server, location

        该指令用于设置启用gzip压缩时的文件最小长度,默认是20K,计量单位默认是K,也可以用k、m、M。当响应内容长度小于设定值时不启用gzip压缩。当length为0时,表示所有符合压缩(gzip_types)条件的文件都会被压缩。

        gzip压缩功能对大文件的压缩效果比较明显,如果文件较小的话,可能会越压越大,而且比直接sendfile更耗资源,传输效率可能比不压缩还低。因此我们需要根据响应内容的大小来决定是否使用gzip,建议该值不低于1K。

gzip_min_length 1024;    #默认计量单位是k
gzip_min_length 1024k;
gzip_min_length 1024K;
gzip_min_length 2M;
gzip_min_length 2m;

3.17.5 gzip_http_version 

Syntax:    gzip_http_version 1.0 | 1.1;
Default:    gzip_http_version 1.1;
Context:   http, server, location

        设置启用gzip所需的http协议最低版本,默认是1.1。

        思考:为什么默认版本是1.1而不是1.0呢?

        HTTP运行在TCP连接之上(HTTP属于应用层协议,主要解决如何包装数据,而TCP属于传输层协议,主要解决数据如何在网络中传输),自然也有着跟TCP一样的三次握手、慢启动等特性。为了尽可能地提高HTTP性能,启用长连接就显得尤为重要。HTTP/1.1默认支持长连接,HTTP/1.0也可以通过在请求头中加入"Connection:keep-alive"来启用长连接。对于TCP长连接上的HTTP 报文,客户端需要一种机制来准确判断结束位置,在HTTP/1.0中,这种机制只有"Content-Length",而在HTTP/1.1中,可以通过"Transfer-Encoding: chunked"对应的分块传输机制来完美解决这类问题。Nginx可以通过"chunked_transfer_encoding"指令来开启分块传输。

        Nginx在启用了gzip的情况下,不会等文件gzip完成后再返回响应,而是边压缩边响应,这样可以显著提高TTFB(Time To First Byte,首字节时间,WEB 性能优化重要指标)。这样唯一的问题是,Nginx开始返回响应时,它不知道将要传输的文件字符有多长,也就无法给出Content-Length这个响应头。所以,在用HTTP/1.0请求Nginx时,如果Nginx启用了gzip,此时是无法获得Content-Length,导致在HTTP/1.0中“开启长连接”和“使用gzip”只能二选一,所以在这里gzip_http_version默认设置为1.1。

3.17.6 chunked_transfer_encoding 分块传输

Syntax:    chunked_transfer_encoding on | off;
Default:    chunked_transfer_encoding on;
Context:   http, server, location

        设置是否允许在HTTP/1.1中开启分块传输编码(Transfer-Encoding: chunked),默认开启。

        分块传输编码是一种数据传输机制,它允许服务端将响应数据分成多个块(chunked),再分批发送给客户端。这样客户端就不用等到所有请求内容全部接收完毕后再解析,而是每接收到一个chunked就解析一个chunked。

3.17.7 gzip_buffers 压缩响应缓冲区

Syntax:    gzip_buffers number size;
Default:    gzip_buffers 32 4k|16 8k;
Context:   http, server, location

        该指令用于设置处理请求压缩时的缓冲区number和size。Nginx进行gzip压缩时,会将文件内容压缩到缓冲区。默认情况下,缓冲区大小等于一个内存页。number和size一般和服务器操作系统有关,根据平台的不同,它可以是 4K 或 8K。配置该值时建议保持默认就行。

        number:指定Nginx向系统申请的缓冲空间个数。

        size:指定每个缓冲空间大小。

        所以这个指令实现的就是Nginx向系统申请number个大小为size的内存空间。

3.17.8 gzip_disable 禁用指定UA的GZIP

Syntax:    gzip_disable regex ...;
Default:    —
Context:   http, server, location
This directive appeared in version 0.6.23.

        该指令用于设置对哪些“User-Agent”(指定正则表达式匹配)不启用gzip功能。

gzip_disable "Mozilla/5.0.*";
gzip_disable "MSIE [1-6]\.";    # IE6以下版本不支持gzip
gzip_disable "MSIE [1-6].(?!.*SV1)";
gzip_disable "(Chrome|curl|Firefox)";

3.17.9 gzip_proxied 代理响应压缩

Syntax:    gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any ...;
Default:    gzip_proxied off;
Context:   http, server, location

        用于Nginx作为反向代理的使用场景,根据请求头和响应头决定是否对代理请求的响应进行gzip压缩,默认关闭。可以通过检查请求头中是否有"Via "字段来判断请求是否被代理。

gzip_proxied off;
gzip_proxied any;
gzip_proxied no-cache no-store private no_etag;
参数作用
off禁用所有代理请求响应压缩,忽略其他参数
expired如果response header中包含”Expires:禁用缓存”字段信息,则启用压缩
no-cache如果response header中包含”Cache-Control:no-cache”字段信息,则启用压缩
no-store如果response header中包含”Cache-Control:no-store”字段信息,则启用压缩
private如果response header中包含”Cache-Control:private”字段信息,则启用压缩
no_last_modified如果response header中不包含 "Last-Modified"字段,则启用压缩
no_etag

如果response header中不包含 "ETag "字段,则启用压缩

auth如果request header中包含“Authorization”字段,则启用压缩
any为所有代理请求启用压缩

3.17.10 gzip_vary 

Syntax:    gzip_vary on | off;
Default:    gzip_vary off;
Context:   http, server, location

        该指令用于设置在启用gzip、gzip_staticgunzip时,是否要在请求响应头中插入“Vary: Accept-Encoding”字段,默认关闭用于告知接收方发送的数据经过了gzip压缩处理,这对于本身不支持gzip解析的客户端有用。

gzip_vary off:

gzip_vary on:

3.17.11 gzip_static 静态压缩

Syntax:     gzip_static on | off | always;
Default:     gzip_static off;
Context:    http, server, location


always:在所有情况下都使用 zipfile,而无需检查客户端是否支持gzip解析;

        gzip_static属于ngx_http_gzip_static_module模块,Nginx默认未构建此模块,如需使用该指令,可通过--with-http_gzip_static_module 参数重新编译Nginx。

        该指令用于设置是否启用检查预压缩文件的存在,默认关闭(off)。当设置为on时,Nginx会把与源文件相同路径下的预压缩(.gz文件)文件返回给客户端。如果想启用该指令,我们得先确保每个源文件的预压缩文件是存在的,如果不存在,即使启用了该指令也是无效的,最后还得让gzip来动态压缩文件,而且还多了一个检查预压缩文件是否存在的冗余步骤。

        gzip_static 和 gzip 之间并不冲突,也不互相影响,gzip_static 算是对gzip的强辅助吧,但gzip_static 指令的执行优先级要比gzip高。实际使用过程中,我们可以同时启用这两个指令。

        gzip_static 指令要受 gzip_http_version,gzip_proxied,gzip_disable和gzip_vary的影响,但不受gzip_min_length和gzip_types的影响。

        当开启gzip_static时,Nginx会先调用gzip_static指令来检查请求源文件对应(同路径下)的预压缩文件是否存在,如果存在就直接把预压缩文件返回给客户端,不再调用gzip进行动态压缩。如果预压缩文件不存在但源文件存在,则再根据gzip配置(gzip、gzip_types、gzip_min_length)判断是否进行gzip压缩,只有满足了动态压缩条件才会对响应进行gzip压缩。如果源文件都不存在,Nginx会返回404错误。所以,同时开启这两个指令时,可以有效降低CPU消耗。至于文件如何返回给客户端,仅受aio、sendfile和directio的配置影响。

        gzip或gzip_static的配置结果不影响sendfile、aio和directio的系统调用规则,因为gzip和gzip_static的配置仅用于控制Nginx是否对响应进行压缩以及如何压缩,而aio、sendfile和directio的配置是用于控制Nginx以哪种方式进行文件I/O。所以从根本上来讲,gzip和aio这两类指令在系统配置层面是不会冲突的。如果我们同时使用了gzip、gzip_static、aio、sendfile和directio指令,一定要优化好gzip_min_length和directio的size大小,否则会出现CPU负载高、性能不佳的现象

        gzip、gzip_static、aio、sendfile和directio指令的配合使用情况请参考以下两篇文章

Nginx(十一) gzip & gzip_static & sendfile & directio & aio 组合使用测试(1)

Nginx(十二) gzip & gzip_static & sendfile & directio & aio 组合使用测试(2)

3.17.12 gunzip & gunzip_buffers 

指令gunzipgunzip_buffers
语法Syntax:     gunzip on | off;
Default:     gunzip off;
Context:    http, server, location
Syntax:     gunzip_buffers number size;
Default:     gunzip_buffers 32 4k|16 8k;
Context:    http, server, location
功能为缺乏 gzip 支持的客户端启用或禁用 gzip 响应的解压缩设置用于解压缩响应的缓冲区的number和size。
备注

        gunzip和gunzip_buffers都属于ngx_http_gunzip_module模块,Nginx默认未构建此模块,如需使用该指令,可通过--with-http_gunzip_module 参数重新编译Nginx。

        目前,基本主流浏览器都支持gzip,所以不用构建ngx_http_gunzip_module模块。

3.17.13 gzip配置完整示例 

http {
    #### Gzip压缩服务配置
    gzip  on;					    # 设置是否开启gzip压缩服务,用于提高传输速度,默认关闭(off)。
    #gzip_static off;               # 是否开启静态压缩。如果所有或大部分源文件都有对应的预压缩文件,可以开启静态压缩。
    #gzip_types *				    # 配置为"*"时,表示对所有MIME类型文件都启用gzip压缩。
    gzip_types application/javascript text/css text/xml text/plain	# 设置对哪些MIME类型的文件启用gzip压缩,默认"text/html",Nginx始终压缩"text/html"文件,不用专门配置,否则会警告配置冲突
    gzip_min_length 20;				# 设置启用gzip压缩的文件最小长度,默认是20k,计量单位默认是k。比较"Content-Length"。
    #gzip_min_length 1m;
    gzip_comp_level 5;				# 设置gzip压缩等级,默认是1。值越大,等级越高,压缩率越高、压缩时间越长,cpu负载越高。
    gzip_http_version 1.1;			# 设置启用gzip所需的http协议最低版本,默认是1.1,保持默认即可。
    #gzip_buffers 32 4k;			# 设置处理请求压缩时的缓冲区number和size,不需要设置,使用默认配置即可。
    gzip_disable "MSIE [1-6]\.";	# 设置对哪些“User-Agent”(正则表达式匹配)不启用gzip功能。IE6版本以下开启gzip服务。
    gzip_proxied any;				# 设置是否对代理请求的响应进行gzip压缩,默认关闭(off)。
    gzip_vary on;				    # 设置是否要在请求响应头中插入“Vary: Accept-Encoding”字段,默认关闭。

}

        我们可以把上面这部分配置单独抽取出来放到一个.ocnf文件中,方便在其它地方直接引入使用。比如我们将配置抽取出来放到nginx_gzip.conf,然后用include指令引入配置。

http {
    include nginx_gzip.conf;
}

3.18 Keep-Alive 长连接

        在学习Keep-Alive知识之前我们先简单了解下HTTP请求过程。HTTP是一种无状态事务协议,我们在前面介绍gzip_http_version指令时曾提到过HTTP是建立在TCP连接之上的,所以客户端在给服务端发送HTTP请求前,需要先与服务端建立TCP连接,再发送HTTP请求,服务端接收到请求后进行响应,响应结束后断开TCP连接(三次握手建立TCP连接 -> 发送请求 -> 响应请求 -> 四次握手断开TCP连接),这种通信方式称之为HTTP短连接。如果每次请求都以短连接的方式处理请求是非常消耗服务器资源的,所以建立长连接是非常有必要的,为此HTTP中加入了Keep-Alive模式。客户端与服务端建立TCP连接后,服务端发起请求时在请求头中添加"Connection:keep-alive",告知服务端需要保持长连接,服务端响应时也会在响应头中添加"Connection:keep-alive",告知客户端允许保持长连接,这样的话,客户端与服务端进行下一次通信时,不再建立TCP连接,继续在上次建立的TCP连接上进行(多次)请求和响应,这种通信方式称之为HTTP长连接。那么这个长连接什么时候关闭呢?每建立一个连接都要消耗内存,不能一直存活吧?Nginx中可以通过设置keepalive_timekeepalive_requestskeepalive_timeout来控制一个长连接的存活期。

        TCP和HTTP都支持Keepalive机制,但两者有所不同,上面讲的仅仅是HTTP层的 Keep-Alive,是由【用户态(应用层,应用程序)】 实现的,称之为 HTTP 长连接(有时间的可以再了解下pipeline流水线作业)。还有一种是TCP层的 Keepalive,是由【内核态】实现的,称之为 TCP 保活机制

HTTP Keep-Alive和TCP Keepalive的区别:

        Http Keep-Alive 针对的是HTTP连接(本质上也是TCP连接)。是为了延长TCP连接的时长(注意:并不是TCP长连接),使得可以用一个TCP连接处理多次Http请求和响应,减少因创建和销毁TCP连接而造成的系统开销。

        TCP Keepalive 针对的是TCP连接。是一种心跳检测机制,主要用来检测对端是否存活,一方面能防止连接因长时间空闲而关闭,确保两端通信链路畅通(保活),另一方面能防止因对端异常而产生“半打开”连接,及时注销连接避免系统资源浪费(检测死链)。当客户端与服务端在设定时间段内未发生网络活动时, 内核为了确保该连接是否有效,会给服务端发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接。

        可能一两句话解释不太清楚,如果还不明白可以看看TCP协议和HTTP协议。

Linux如何开启TCP Keepalive?

        Linux系统仅提供了一种TCP KeepAlive机制,但无法全局开启TCP KeepAlive,应用程序如需开启TCP KeepAlive必须通过调用 socket 的 setsockopt() 函数来设置 SO_KEEPALIVE 选项才能生效。

# 设置是否开启TCP保活
int flag = 1; # 1表示打开keepalive,0表示关闭,默认值是0;
ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag));
# 设置保活时长
int val = 7200;       # 单位是秒
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val));
# 设置两次相邻检测间隔时间
int interval = 75;    # 单位是秒
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
# 设置检测次数
int cnt = 9;
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));

        Linux 提供的TCP KeepAlive机制有三个关键参数

[root@reader ~]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200

# 或者是用cat命令
[root@reader ~]# find / -name tcp_keepalive*
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_time
[root@reader ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[root@reader ~]# cat /proc/sys/net/ipv4/tcp_keepalive_*
75
9
7200
[root@reader ~]# 

############解释===
#tcp_keepalive_time=7200:保活时长/闲置超时时长,单位是秒。表示保活时长是7200秒(2小时),连接空闲时长达到2小时时启动保活机制;
#tcp_keepalive_intvl=75: 两次检测的间隔时间,单位是秒。表示两次检测的间隔时间是 75 秒;
#tcp_keepalive_probes=9: 最多检测次数。表示连续9次检测都未收到对端响应,则认为对端异常,中断连接。

# 如果任意一次检测时对端能正常响应,表示对端正常,此时内核会重置TCP保活时间,直到下一个保活时间的到来。
# 一个TCP连接的最长存活时间=keepalive_time + keepalive_intvl * keepalive_probes

        临时修改Keepalive全局配置:

[root@reader ~]# echo 3000 > /proc/sys/net/ipv4/tcp_keepalive_time
[root@reader ~]# echo 30 > /proc/sys/net/ipv4/tcp_keepalive_intvl 
[root@reader ~]# sysctl -w net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_keepalive_probes = 5
[root@reader ~]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 3000
[root@reader ~]# 

# 注意:<echo>和<sysctl -w>这两种方式都是临时修改,修改后虽会立即生效,但服务器重启后这个三个參数值又会恢复到默认值。

        永久修改Keepalive全局配置:

#在/etc/sysctl.conf配置文件中选择性地添加相关keepalive配置
net.ipv4.tcp_keepalive_intvl = 45
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 3600

#保存并关闭文件后,记得运行以下命令使新的配置生效:
sysctl -p
[root@reader logs]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
[root@reader logs]# 
[root@reader logs]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
[root@reader logs]# 
[root@reader logs]# 
[root@reader logs]# vim /etc/sysctl.conf            # 修改完,保存并关闭sysctl.conf
[root@reader logs]# 
[root@reader logs]# cat /etc/sysctl.conf            # 查看修改后的sysctl.conf
vm.swappiness = 0
kernel.sysrq = 1
net.ipv4.neigh.default.gc_stale_time = 120

# see details in https://help.aliyun.com/knowledge_detail/39428.html
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2

# see details in https://help.aliyun.com/knowledge_detail/41334.html
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.tcp_keepalive_time = 3600
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 45
[root@reader logs]# 
[root@reader logs]# 
[root@reader logs]# sysctl -a | grep keepalive     # 因为未执行sysctl -p,所以新配置未生效
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
[root@reader logs]# 
[root@reader logs]# find /proc -name tcp_keepalive_*
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_time
[root@reader logs]# cat /proc/sys/net/ipv4/tcp_keepalive_time 
7200
[root@reader logs]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl 
75
[root@reader logs]# 
[root@reader logs]# 
[root@reader logs]# sysctl -p
vm.swappiness = 0
kernel.sysrq = 1
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.tcp_keepalive_time = 3600
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 45
[root@reader logs]# 
[root@reader logs]# 
[root@reader logs]# sysctl -a | grep keepalive    # 执行完sysctl -p,新配置已生效
net.ipv4.tcp_keepalive_intvl = 45
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 3600
[root@reader logs]# 

        查看已开启的Keepalive:

[root@reader ~]# netstat -no | grep keepalive
tcp        0      0 127.0.0.1:43398         127.0.0.1:3306          ESTABLISHED keepalive (3976.29/0/0)
tcp6       0      0 127.0.0.1:3306          127.0.0.1:43398         ESTABLISHED keepalive (3976.33/0/0)

Nginx如何开启TCP Keepalive?

        通过配置listen指令中的so_keepalive参数值来设置TCP保活机制

[so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]
此参数用于配置侦听套接字的“TCP keepalive”行为。一共有三项参数值,on、off、[keepidle]:[keepintvl]:[keepcnt],这3项参数值不能同时使用,仅能配置一项。
on:开启TCP保活,但保活机制使用系统默认值;
off:关闭TCP保活;

[keepidle]:[keepintvl]:[keepcnt],通过配置这3个参数可以覆盖系统默认配置项。
keepidle:保活时长,单位是秒,对应系统默认配置项 tcp_keepalive_time;
keepintvl:两次检测的间隔时间,单位是秒。对应系统默认配置项 tcp_keepalive_intvl;
keepcnt:最多检测次数。对应系统默认配置项 tcp_keepalive_probes。

keepidle、keepintvl、keepcnt这3个参数值不需要全部配置,可以省略1-2个,如果省略则使用系统默认配置。

配置举例:
listen 80 default_server so_keepalive=on; # 开启TCP保活,保活机制使用系统默认值;
listen 80 default_server so_keepalive=off; # 关闭TCP保活;
listen 80 default_server so_keepalive=1h::5; # 开启TCP保活,保活时长是1小时,间隔时间是系统默认值(75秒),检测次数是5次;
listen 80 default_server so_keepalive=20m:30:; # 开启TCP保活,保活时长是20分钟,间隔时间是30秒,检测次数是系统默认值(9次);
listen 80 default_server so_keepalive=20m:30:5; # 开启TCP保活,保活时长是20分钟,间隔时间是30秒,检测次数是5次;

        我们在Nginx 8688端口下开启TCP保活后,再查看下已开启的keepalive:

[root@reader conf]# netstat -no | grep keepalive
tcp        0      0 172.30.233.163:22       14.145.133.89:51559     ESTABLISHED keepalive (7094.56/0/0)
tcp        0      0 127.0.0.1:58330         127.0.0.1:3306          ESTABLISHED keepalive (5252.04/0/0)
tcp        0      0 172.30.233.163:8688     14.145.133.89:51598     ESTABLISHED keepalive (593.10/0/0)
tcp6       0      0 127.0.0.1:3306          127.0.0.1:58330         ESTABLISHED keepalive (5252.09/0/0)

什么场景适合开启TCP保活?

        开启TCP保活主要是为了确保两端通信链路畅通,提高服务响应速度,但服务器维护每个TCP长连接是要消耗系统资源和带宽的,所以TCP长连接不能过多,严重时可能会发生系统宕机。TCP保活主要用于TCP连接数量不多,但通信频繁的场景,比如Tomcat与MySQL之间可开启TCP保活机制。还有一种场景就是,客户端和服务端间要进行上传/下载大文件,数据传输时长可能要超过3分钟,此时通过调高HTTP长连接的keepalive_timeout时长是无法彻底解决问题的,因为一旦调高了keepalive_timeout,客户端和服务端间完成通信后连接无法及时断开,就会白白占用连接数,随着通信次数的不断增加,连接数量越来越多,最后造成连接池溢出,Nginx挂了,就更别提高并发的场景了,这时候就可以开启TCP保活,但保活时长不宜过长。

3.18.1 keepalive_disable 限制客户端

Syntax:    keepalive_disable none | browser ...;
Default:    keepalive_disable msie6;
Context:   http, server, location

        设置禁止哪些不正常的浏览器开启HTTP长连接。默认IE6及其更低版本禁止长连接。设置为safari时表示禁止Safari及所有类似于Safari的浏览器进行长连接 。设置为none时表示允许所有浏览器开启HTTP长连接。

3.18.2 keepalive_requests 最大请求数

Syntax:    keepalive_requests number;
Default:    keepalive_requests 1000;
Context:   http, server, location
This directive appeared in version 0.8.0.

        限制一个HTTP长连接可处理的最大请求数。请求次数达到上限后,连接将关闭。默认是1000次,在 1.19.10 版本之前,默认值为 100。

        必须定期关闭连接以便于释放每个连接的内存分配。设置过高的最大请求数可能会导致服务器内存消耗较大,因此不建议配置太高。当QPS较高时可适当调高参数值。

3.18.3 keepalive_time 长连接处理请求最长时间

Syntax:    keepalive_time time;
Default:    keepalive_time 1h;
Context:   http, server, location
This directive appeared in version 1.19.10.

        限制一个HTTP长连接处理请求的最长时间。达到该时间后,连接将在后续请求处理后被强制关闭。默认配置是1小时。

3.18.4 keepalive_timeout 长连接空闲等待超时时间

Syntax:    keepalive_timeout timeout [header_timeout];
Default:    keepalive_timeout 75s;
Context:   http, server, location

       限制一个HTTP长连接的空闲等待超时时间,也就是TCP传输完所有响应数据后等待下一个HTTP请求的最长等待时间,单位是秒,默认是75秒。值为0时,表示禁止开启HTTP长连接。keepalive_timeout 要尽量大于 client_body_timeout,先礼后兵。

        第二个参数是可选参数,用于在响应头中添加"Keep-Alive:timeout = time",告知客户端HTTP长连接的超时时间,header_timeout不需要跟timeout值相同。

keepalive_timeout 65 60;    # 默认单位是秒
keepalive_timeout 65s 60s;

        查看已建立的tcp连接 

netstat -antp | grep 8688                         # 用端口号查询

netstat -antp | grep 233.163                    # 用IP查询

netstat -antp | grep 233.163:8688           # IP+端口查询

[root@reader logs]# netstat -antp | grep 233.163
tcp        0      0 172.30.233.163:8688     14.145.133.89:58101     FIN_WAIT2   -                   
tcp        0      0 172.30.233.163:8688     14.145.133.89:58104     FIN_WAIT2   -                   
tcp        0      0 172.30.233.163:22       14.145.133.89:53877     ESTABLISHED 23600/sshd: root [p 
tcp        0      0 172.30.233.163:58372    100.100.30.26:80        ESTABLISHED 21972/AliYunDun     
tcp        0     36 172.30.233.163:22       14.145.133.89:51723     ESTABLISHED 16818/sshd: root [p 
tcp        0      0 172.30.233.163:43024    100.100.18.120:443      TIME_WAIT   -                   
tcp        0      0 172.30.233.163:22       14.145.133.89:56177     ESTABLISHED 24428/sshd: root [p 
tcp        0      0 172.30.233.163:8688     14.145.133.89:58103     FIN_WAIT2   -                   
tcp        0      0 172.30.233.163:22       14.145.133.89:50705     ESTABLISHED 16333/sshd: root [p 
tcp        0      0 172.30.233.163:22       14.145.133.89:50695     ESTABLISHED 16270/sshd: root [p 
tcp        0      0 172.30.233.163:33262    100.100.18.120:80       TIME_WAIT   -                   
[root@reader logs]# 

3.19 send_timeout 发送响应空闲等待超时时间

        在ngx_http_core_module模块中一共有6个指令跟timeout相关,前面我们已经介绍过了client_body_timeout、client_header_timeout和keepalive_timeout这3个指令的功能和用法,lingering_timeoutresolver_timeout指令的功能和用法会在3.20和3.21章节会介绍,下面我们先看看send_timeout指令的功能和用法。

Syntax:     send_timeout time;
Default:     send_timeout 60s;
Context:    http, server, location

        设置服务端向客户端传输响应的空闲等待超时时间,单位是秒,默认是60秒。

        注意:该指令限制的仅仅是服务端两次连续write操作之间的间隔时间,而不是发送整个响应的用时时间。所以当服务端发送完第一次响应后,如果在send_timeout设定时间段内未发送任何响应,Nginx将关闭该连接。

3.20 lingering_close 延迟关闭

        在了解Nginx的lingering_close指令作用之前,我们先简单看下TCP Socket中的SO_LINGER选项,通过配置SO_LINGER可改变Socket关闭TCP连接时的行为,可分为3种行为

#include <sys/socket.h>
struct linger
{
    int l_onoff;     // 是否开启延迟调用close()函数,0:关闭,非0:开启,默认是0。
    int l_linger;    // 延迟多少秒调用close()
};
  • l_onoff = 0:默认配置。调用close()函数后立即返回0,如果TCP发送缓冲区还有数据则继续发送给对端,等确认接收后再关闭socket并发送FIN报文,开始四次挥手断开连接;
  • l_onoff > 0,l_linger = 0:开启延迟调用close(),调用close()函数后立即返回0,丢弃TCP发送缓冲区和接收缓冲区中的数据(造成接收端接收到的数据不全),关闭socket并发送RST报文给对端,强制断开连接;
  • l_onoff > 0,l_linger > 0:开启延迟调用close(),调用close()函数后延迟返回,返回值取决于接收TCP接收缓冲区数据是否发送完毕。如果在l_linger时间内发送缓冲区数据已发送完毕并已确认接收,关闭socket并发送FIN报文给对端,开始四次挥手断开连接,返回值是0;如果在l_linger时间内发送缓冲区数据未发送完毕,关闭socket并发送RST报文给对端,强制断开连接,返回值是-1。

        再来看下TCP的shutdown()函数,该函数可选择性关闭socket的读和写。

#include <sys/socket.h>
int shutdown(int sockfd, int how);
  • how = SHUT_WR:仅关闭写;
  • how = SHUT_RD:仅关闭读;
  • how = SHUT_RDWR:同时关闭读和写。

Nginx在什么情况下使用lingering_close?


        既然要延迟关闭,那就说明请求还没处理完,在彻底断开连接前需要有个平滑过渡时间。所以只有在TCP发送缓冲区或接收缓冲区的数据未处理完,且HTTP为短连接或HTTP为长连接但keepalive已超时的情况下才会延迟关闭TCP连接。

Nginx开启lingering_close后是如何关闭TCP连接的?


        当Nginx处理请求的过程中发生异常,Nginx会先调用shutdown()函数来关闭socket的写(也就是说延迟关闭的仅仅是读,写还是立即关闭),随后设置一个定时器,超时时间是lingering_close,如果在这段时间内新收到了对端发来的数据包,则丢弃数据并重置定时器开启新的等待,直到无法收到对端新发来的数据包或总的等待时间超过lingering_time后,再关闭socket的读,从而彻底关闭TCP连接。

3.20.1 lingering_close

Syntax:     lingering_close off | on | always;
Default:     lingering_close on;
Context:    http, server, location
This directive appeared in versions 1.1.0 and 1.0.6.

        设置TCP连接的关闭方式。

  • always:始终延迟关闭。nginx在关闭连接前,必须无条件地等待并处理完客户端的所有数据。
  • off:不启用延迟关闭。Nginx会立即关闭连接,不会等待接收对端发来的数据包。
  • on:有条件的启用延迟关闭。nginx在超时结束前等待并处理来自客户端的额外数据。

3.20.2 lingering_time

Syntax:     lingering_time time;
Default:     lingering_time 30s;
Context:    http, server, location

        设置总的延迟等待时间,默认是30秒。总的等待时间超过lingering_time设置的时间后,Nginx不管对端是否仍在发送数据,都会关闭连接。

        如果lingering_time时间内已接收完客户端数据,则通过四次挥手断开连接,否则发送RST报文强制断开连接。

3.20.3 lingering_timeout

Syntax:     lingering_timeout time;
Default:     lingering_timeout 5s;
Context:    http, server, location

        设置每一轮的延迟等待时间,默认是5秒。

3.21 resolver DNS解析

3.21.1 resolver 

Syntax:     resolver address ... [valid=time] [ipv4=on|off] [ipv6=on|off] [status_zone=zone];
Default:     —
Context:    http, server, location

        该指令用于设置DNS解析服务器地址,便于动态解析域名。
        address:配置DNS服务器的域名或IP地址,端口可选。如未指定端口,则使用端口53。address可以配置多个,中间用空格隔开。DNS服务器以循环方式查询。

        [valid=time]:设置DNS解析信息的缓存时间,单位是秒,默认时间是DNS记录的TTL值。
        [ipv4=on|off]:设置解析域名时是否需要查找IPv4地址,默认情况下,nginx 在解析时会同时查找 IPv4 和 IPv6 地址。on表示需要,off表示不需要。
        [ipv6=on|off]:设置解析域名时是否需要查找IPv6地址,on表示需要,off表示不需要。

resolver 11.11.11.11:54 127.0.0.1 [::1]:5353 valid=30s ipv6=off;

3.21.2 resolver_timeout DNS解析超时时间

Syntax:     resolver_timeout time;
Default:     resolver_timeout 30s;
Context:    http, server, location

        设置DNS解析超时时间,单位是秒,默认是30秒。可以缩短到10秒左右。 

3.22 limit_rate 流量限制

3.22.1 limit_rate

Syntax:     limit_rate rate;
Default:     limit_rate 0;
Context:    http, server, location, if in location

        限制向客户端传输响应的速率。rate以每秒字节数为单位。零值表示禁用速率限制。限制是针对每个请求设置的,因此如果客户端同时打开两个连接,总速率将是指定限制的两倍。参数值可以包含变量。速率限制也可以在代理服务器响应头中的“ X-Accel-Limit-Rate”字段设置。可以使用proxy_ignore_headers,fastcgi_ignore_headers,uwsgi_ignore_headers和scgi_ignore_headers指令禁用此功能。

map $slow $rate {
    1     4k;
    2     8k;
}

limit_rate $rate;

3.22.2 limit_rate_after

Syntax:     limit_rate_after size;
Default:     limit_rate_after 0;
Context:    http, server, location, if in location
This directive appeared in version 0.8.0.

        设置发送数据量超过多少时开始限制发送速率。参数值可包含变量 (1.17.0)。

# 向客户端发送的数据量达到5M后就开启限速,此后的发送速率不得超过50k/s。
location /flv/ {
    flv;
    limit_rate_after 5m;
    limit_rate       50k;
}

3.23 静态资源

3.23.1 etag 实体标签

Syntax:     etag on | off;
Default:     etag on;
Context:    http, server, location
This directive appeared in version 1.3.3.

        设置处理静态资源请求时是否要在响应头中添加"ETag"字段,默认开启。

        Nginx作为Web服务器时,会对静态资源请求自动添加响应头字段Etag,字段值为静态资源文件的最后编辑时间(last_modified_time)和文件大小的十六进制组合。

        只有Nginx响应的文件才会自动添加 Etag 字段,如果被代理服务器不是Nginx服务器,代理响应内容不会自动添加 Etag 字段。

3.23.2 if_modified_since 静态资源是否仍有效

Syntax:     if_modified_since off | exact | before;
Default:     if_modified_since exact;
Context:    http, server, location
This directive appeared in version 0.7.24.

        指定如何处理响应文件的最后修改时间与请求头中"If-Modified-Since"字段对应时间的比较结果。

        Nginx作为Web服务器时,会对静态资源请求自动添加响应头字段Last-Modified,字段值为静态资源文件的最后编辑时间(last_modified_time)。客户端再次请求同一文件时,发现有缓存数据,但不确定缓存是否过期,于是在请求头中添加If-Modified-Since或者If-None-Match字段,服务端接收到请求后会用If-Modified-Since与响应数据中的Last-Modified值进行比较,根据比较结果决定是发送新数据,还是返回304 Not Modified响应,表示浏览器仍使用之前的缓存。

  • off : 忽略请求中的if_modified_since头部,每次都发新数据。
  • exact:精确匹配,默认配置。将请求头中if_modified_since的时间与响应数据中last_modified的时间进行精确匹配,如果完全相等则认为客户端缓存有效,返回304。
  • before:如果请求头中if_modified_since的时间大于等于响应数据中last_modified的时间,则返回304。

3.24 output_buffers 

Syntax:     output_buffers number size;
Default:     output_buffers 2 32k;
Context:    http, server, location

         设置用于从磁盘读取响应的缓冲区的number和size。

3.25 auth_delay 

Syntax:     auth_delay time;
Default:     auth_delay 0s;
Context:    http, server, location
This directive appeared in version 1.17.10.

        用于设置延迟处理未经授权的请求的延迟时间,防止定时攻击,默认是0秒,也就是未延迟。当访问受密码、子请求结果或JWT限制的请求时,如果请求未授权则返回401响应码并延迟处理该请求,防止定时攻击。该指令最好是配合auth_basic 、auth_jwt 、auth_http 等指令一起使用。

3.26 disable_symlinks 符号链接

Syntax:     disable_symlinks off;
                 disable_symlinks on | if_not_owner [from=part];
Default:     disable_symlinks off;
Context:    http, server, location
This directive appeared in version 1.1.15.

        设置Nginx打开文件时如何处理软链接/符号链接,默认是off。符号链接就是windows系统中的文件快捷方式,Linux系统可以用ln命令创建符号链接文件。有以下几种配置方式:

  1. off:默认行为,允许路径中出现符号链接,不做检查。
  2. on:如果文件路径中任何组成部分含有符号链接,拒绝访问该文件。
  3. if_not_owner:如果文件路径中任何组成部分含有符号链接,且符号链接和链接目标的所有者不同,拒绝访问该文件。
  4. from=part:当 Nginx 进行符号链接检查时(参数 on 和参数 if_not_owner ),路径中所有部分默认都会被检查。而使用from=part 参数可以避免对路径开始部分进行符号链接检查,而只检查后面的部分路径。如果某路径不是以指定值开始,整个路径将被检查,就如同没有指定这个参数一样。如果某路径与指定值完全匹配,将不做检查。这个参数的值可以包含变量。
disable_symlinks on from=$document_root;
disable_symlinks if_not_owner from=$document_root$uri;

3.27 limit_except 

Syntax:     limit_except method ... { ... }
Default:     —
Context:    location

        为location指定允许的 HTTP 方法。method值可以是以下参数之一:GET,HEAD,POST,PUT,DELETE,MKCOL,COPY,MOVE,OPTIONS,PROPFIND,PROPPATCH,LOCK,UNLOCK或PATCH。允许使用 GET 方法,也就允许使用 HEAD 方法。可以使用ngx_http_access_module,ngx_http_auth_basic_module和ngx_http_auth_jwt_module(1.13.10)模块指令来限制对其他方法的访问。

limit_except GET {
    allow 192.168.1.0/32;
    deny  all;
}

3.28 max_ranges 限制断点续传

Syntax:     max_ranges number;
Default:     —
Context:    http, server, location
This directive appeared in version 1.1.2.

        客户端请求大文件(如视频类)时往往会采用多线程的方式进行分段请求(断点续传),请求头中带有“Range: bytes=first-end”信息,如“Range: bytes=0-100”,服务端如果支持Range,则会在响应头中添加“Content-Range: bytes first-end/total”,如“Accept-Ranges: bytes 0-100/3213”。
        该指令是用来限制请求头中的Range最大范围,单位是字节。超过限制范围的请求将按未指定字节范围来处理。默认情况下,Range范围大小不受限制。设为0时表示服务端不支持Range断点请求。

max_ranges 4096;    # rang范围最大值是4096byte。

3.29 merge_slashes URI斜杠压缩

Syntax:     merge_slashes on | off;
Default:     merge_slashes on;
Context:    http, server

        设置是否将请求 URI 中的两个或多个相邻斜杠压缩成一个斜杠,默认是on,表示开启压缩。请注意,压缩对于正确匹配前缀字符串和正则表达式location是至关重要的。如不启用压缩,类似于“ //scripts/one.php”这样的请求将无法被匹配到location,并且可能会被当成静态文件进行处理。因此有必要将其转换为“ /scripts/one.php”。

location /scripts/ {
    ...
}

        如果 URI 包含 base64 编码的名称,则有必要关闭斜杠压缩,因为 base64 在内部使用“ /”字符。但是,出于安全考虑,最好开启斜杠压缩。

        如果该指令是在server级别上指定的,则仅当服务器为默认服务器时才使用其值。指定的值也适用于在相同地址和端口上侦听的所有虚拟服务器。

3.30 msie_padding

Syntax:     msie_padding on | off;
Default:     msie_padding on;
Context:    http, server, location

        设置是否开启支持IE浏览器的msie_padding特性,默认开启。如果开启,Nginx会将响应体大小增加到512字节,以便于响应大于或等于400状态码的请求。

3.31 msie_refresh 

Syntax:     msie_refresh on | off;
Default:     msie_refresh off;
Context:    http, server, location

        设置是否允许为IE浏览器发布一个refresh而不是做一次redirect。默认拒绝。

3.32 read_ahead 预读取

Syntax:     read_ahead size;
Default:     read_ahead 0;
Context:    http, server, location

        设置内核处理文件时的预读取量,默认是0。

        在 Linux 上,使用posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL)系统调用,因此size参数将被忽略。

3.33 request_pool_size 请求内存分配

Syntax:     request_pool_size size;
Default:     request_pool_size 4k;
Context:    http, server

        允许精确调整每次请求的内存分配。该指令对性能的影响极小,一般不应使用。

3.34 reset_timedout_connection 重置超时连接

Syntax:     reset_timedout_connection on | off;
Default:     reset_timedout_connection off;
Context:    http, server, location

        设置是否重置超时的连接和使用非标准代码 444 关闭的连接 (1.15.2)。正常情况下,已超时的HTTP长连接会执行四次挥手来关闭连接。如果开启此功能,连接超时后,TCP将调用close()函数,并设置socket的SO_LINGER选项中的l_linger=0,发送缓冲区和接收缓冲区的数据被丢弃,内核发送RST报文给客户端,TCP连接被强制关闭。具体可参考3.20章节。实际使用中,不建议开启该功能。

3.35 send_lowat

Syntax:     send_lowat size;
Default:     send_lowat 0;
Context:    http, server, location

        如果指令设置为非零,nginx将尝试使用kqueue方法的NOTE_LOWAT标志或SO_SNDLOWAT套接字选项,尽量减少客户端套接字的发送操作次数。在这两种情况下,都会使用指定的大小。

        请注意,在 Linux、Solaris 和 Windows 系统中,该指令将被忽略。

3.36 types_hash_bucket_size

Syntax:     types_hash_bucket_size size;
Default:     types_hash_bucket_size 64;
Context:    http, server, location

        设置types哈希表的存储桶大小。在 1.5.13 版本之前,默认值取决于处理器的缓存行的大小。

3.37 types_hash_max_size

Syntax:     types_hash_max_size size;
Default:     types_hash_max_size 1024;
Context:    http, server, location

        设置types哈希表的最大size。

3.38 variables_hash_bucket_size

Syntax:     variables_hash_bucket_size size;
Default:     variables_hash_bucket_size 64;
Context:    http

        设置变量哈希表的存储桶大小。

3.39 variables_hash_max_size

Syntax:     variables_hash_max_size size;
Default:     variables_hash_max_size 1024;
Context:    http

        设置变量哈希表的最大值size。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值