参考文献

  • 深入理解Nginx-模块开发与架构解析(第二版) 陶辉

第一部分 Nginx能帮我做什么

第一章 研究Nginx前的准备工作

Nginx的优点

  • 高并发,高性能
  • 高扩展性
  • 高可靠性
  • 热部署
  • 最自由的BSD许可证

使用Nginx的必备软件

  • GCC编译器

    1
    yum install -y gcc-c++
  • PCRE

    1
    yum install -y pcre pcre-devel
  • zlib

    1
    yum install -y zlib zlib-devel
  • OpenSSL开发库

    1
    yum install -y openssl openssl-devel

磁盘目录

  • Nginx源代码存放目录
  • Nginx编译阶段产生的中间文件存放目录
    • 该目录用于放置在configure命令执行后所生成的源文件及目录,以及make命令执行后生成的目标文件和最终连接成功的二进制文件.
    • 默认情况下,configure命令会将目录命名为objs,并放在Nginx源代码目录下
  • 部署目录
    • 该目录存放实际Nginx服务运行期间所需要的二进制文件,配置文件等.
    • 默认情况下,该目录为/usr/local/nginx
  • 日志文件存放目录

Nginx的命令行控制

  • 默认情况下,Nginx被安装在目录/usr/local/nginx/中,其二进制文件路径为/usr/local/nginx/sbin/nginx,其配置文件路径为/usr/local/nginx/conf/nginx.conf
启动方式
  • 默认启动方式

    1
    /usr/local/nginx/sbin/nginx
    • 会读取默认路径下的配置文件: /usr/local/nginx/conf/nginx.conf
  • 另行指定配置文件的启动方式

    • -c参数指定配置文件
    1
    /usr/local/nginx/sbin/nginx -c /tmp/nginx.conf
  • 另行指定安装目录的启动方式

    • -p参数指定Nginx的安装目录
    1
    /usr/local/nginx/sbin/nginx -p /usr/local/nginx
  • 另行指定全局配置项的启动方式

    • 可以通过-g参数临时指定一些全局配置项,以使新的配置项.
    1
    /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;"
    • -g参数的约束条件是指定的配置项不能与默认路径下的nginx.conf中的配置项冲突,否则无法启动.

    • 另外一个约束条件是,以-g方式启动的Nginx服务执行其他命令行时,需要把-g参数也带上,否则可能会出现配置项不匹配的情况.例如,要停止Nginx服务,那么需要执行下面代码:

      1
      /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;" -s stop
测试配置信息是否由有误
  • 在不启动Nginx的情况下,使用-t参数仅测试配置文件是否有误.

    1
    /usr/local/nginx/sbin/nginx -t
  • 在测试配置阶段不输出信息

    • 测试配置选项时,使用-q参数可以不把error级别以下的信息输出到屏幕.

      1
      /usr/local/nginx/sbin/nginx -t -q
显示版本信息
1
/usr/local/nginx/sbin/nginx -v
显示编译阶段的参数
1
/usr/local/nginx/sbin/nginx -V
快速停止服务
1
/usr/local/nginx/sbin/nginx -s stop
优雅地停止服务
1
/usr/local/nginx/sbin/nginx -s quit
日志文件回滚
1
/usr/local/nginx/sbin/nginx -s reopen
平滑升级Nginx
  • Nginx服务升级到新的版本时,必须要将旧的二进制文件Nginx替换掉,通常情况下这是需要重启服务的,但是Nginx支持不重启服务来完成新版本的平滑升级.

  • 升级时包括以下步骤:

    1. 通知正在运行的旧版本Nginx准备升级.通过向master进行发送USR2信号可达到目的.如

      1
      kill -s SIGUSR2 <nginx master pid>
      • 这时,运行的Nginx会将pid文件重命名,如将/usr/local/nginx/logs/nginx.pid重命名为/usr/local/nginx/logs/nginx.pid.oldbin,这样新的Nginx才有可能启动成功.
    2. 启动新版本的Nginx,可以使用以上任意一种启动方式.这时通过ps命令可以发现新旧版本的Nginx在同时运行.

    3. 通过kill命令向旧版本的master进程发送SIGQUIT信号,以优雅的方式关闭旧版本的Nginx.随后将只有新版本的Nginx服务运行,此时平滑升级完毕.

第二章 Nginx的配置

Nginx服务的基本配置

  • 按用户使用时的预期功能分成以下4类
    • 用于调试,定位问题的配置项
    • 正常运行的必备配置项
    • 优化性能的配置项
    • 事件类配置项
用于调试进行和定位问题的配置项
  • 是否以守护进程方式运行Nginx

    1
    2
    语法: daemon on | off;
    默认: daemon on;
  • 是否以master/worker方式工作

    1
    2
    语法: master_process on | off;
    默认: master_process on;
  • error日志的设置

    1
    2
    语法: error_log /path/file level;
    默认: error_log logs/error/log error;
    • level是日志的输出级别,取值范围是debug.info,notice,warn,error,crit,alert,emerg,从左至右级别依次增大.
    • 当设定为一个级别时,大于或等于该级别的日志都会被输出到/path/file文件中,小于该级别的日志则不会输出.
    • 如果日志级别设定到debug,必须要在configure时加入--with-debug配置项
  • 仅对指定的客户端输出debug级别的日志

    1
    语法: debug_connection [IP|CIDR]
    • 这个配置项实际上属于事件类配置,因此,它必须放在events {...}中才有效.它的值可以是IP地址或CIDR地址,如:

      1
      2
      3
      4
      events {
      debug_connection 10.224.66.14;
      debug_connection 10.224.57.0/24;
      }
    • 使用debug_connection前,需要确保在执行configure时已加如了--with-debug参数,否则不会生效.

正常运行的配置项
  • 定义环境变量

    1
    语法: env VAR | VAR=VALUE;
    • 这个配置项可以让用户直接设置操作系统上的环境变量.如:

      1
      env TESTPATH=/tmp/;
  • 嵌入其他配置文件

    1
    语法: include /path/file;
    • include配置项可以将其他配置文件嵌入到当前的nginx.conf中,它的参数既可以是绝对路径,也可以是相对路径(相对于Nginx的配置目录,即nginx.conf所在的目录),例如:

      1
      2
      include mime.types;
      include vhost/*.conf;
  • pid文件的路径

    1
    2
    语法: pid /path/file;
    默认: pid logs/nginx.pid;
    • 保存master进程IDpid文件存放路径.默认与configure执行的参数--pid-path所指定的路径相同的,也可以随时修改,但应确保Nginx有权在相应的目标中创建pid文件,该文件直接影响Nginx是否可以运行.
  • Nginx worker进程运行的用户以及用户组

    1
    2
    语法: user username[groupname];
    默认: user nobody nobody;
  • 指定Nginx worker进程可以打开的最大句柄描述符个数

    1
    语法: worker_rlimit_nofile limit;
优化性能的配置项
  • Nginx worker进程个数

    1
    2
    语法: worker_processes number;
    默认: worker_processes 1;
    • master/worker运行方式下,定义worker进行的个数.
    • 一般情况下,用户要配置与CPU内核相等的worker进程,并且使用下面的worker_cpu_affinity配置来绑定CPU内核.
  • 绑定Nginx worker进程到指定的CPU内核

    1
    语法: worker_cpu_affinity cpumask[cpumask...]
    1
    2
    worker_processes 4;
    worker_cpu_affinity 1000 0100 0010 0001;
    • worker_cpu_affinity配置仅对Linux操作系统有效.Linux操作系统使用sched_setaffinity()系统调用实现这个功能.
  • SSL硬件加速

    1
    语法: ssl_engine device;
    • 如果服务器上有SSL硬件加速设备,那么就可以进行配置以加快SSL协议的处理速度.可以使用OpenSSL提供的命令来查看是否有SSL硬件加速设备:

      1
      openssl engine -t

虚拟主机与请求的分发

监听端口
1
2
3
4
5
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
主机名称
1
2
3
Syntax:	server_name name ...;
Default: server_name "";
Context: server
  • server_name可以跟多个主机名称,如server_name www.testweb.com download.testweb.com;
  • 在开始处理一个HTTP请求时,Nginx会取出header头中的Host,与每个server中的server_name进行匹配,以此决定到底由哪一个server块来处理这个请求.有可能一个Host与多个server块中的server_name都匹配,这时会根据匹配优先级来选择实际处理的server块.
  • server_nameHost的匹配优先级如下:
    1. 首先选择所有字符串完全匹配的server_name,如www.testweb.com
    2. 其次选择通配符在前面的server_name,如*.testweb.com
    3. 再次选择通配符在后面的server_name,如www.testweb.*
  • 如果Host与所有的server_name都不匹配,这时会按照下列顺序选择处理的server
    1. 优先选择在listen配置项后加入[default|default_server]server
    2. 找到匹配listen端口的第一个server
  • 如果server_name后跟着空字符串(如server_name "";),那么表示匹配没有Host这个HTTP头部的请求.
  • Nginx正是使用server_name配置项针对特定的Host域名的请求提供不同的服务,以此实现虚拟主机功能.
serve_names_hash_bucket_size
1
2
3
Syntax:	server_names_hash_bucket_size size;
Default: server_names_hash_bucket_size 32|64|128;
Context: http
  • 为了提高快速寻找到相应server_name的能力,Nginx使用散列表来存储server_name.server_names_hash_bucket_size设置了每个散列桶占用的内存大小.
server_names_hash_max_size
1
2
3
Syntax:	server_names_hash_max_size size;
Default: server_names_hash_max_size 512;
Context: http
location
1
2
3
4
Syntax:	location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default: —
Context: server, location
  • location会尝试根据用户请求中的URI来匹配上面的/uri表达式,如果可以匹配,就选择location {}块中的匹配来处理用户请求.

  • location的匹配规则:

    1. =表示把URI作为字符串,以便与参数中的uri做完全匹配.例如:

      1
      2
      3
      location = / {
      # 只有当用户请求是/时,才会使用该location下的配置
      }
    2. ^~:表示uri以某个常规字符串开头,理解为匹配url路径即可.Nginx不对url做编码.因此请求为/static/20%/aa可以被规则^~/static/ /aa匹配到;

    3. ~表示区分大小写(字母大小写敏感)的正则匹配;

    4. ~*表示不区分大小写的正则匹配;

    5. !~表示区分大小写不匹配的正则;

    6. !~*表示不区分大小写不匹配的正则;

    7. /通用匹配,任何请求都会匹配到,默认匹配;

  • 匹配优先级

    • 第一优先级: 等号类型(=)的优先级最高.一旦匹配成功,则不再查找其他匹配项.
    • 第二优先级: ^~类型表达式.一旦匹配成功,则不再查找其他匹配项.
    • 第三优先级: 正则表达式类型(~ ~*)的优先级次之.如果有多个location的正则能匹配的话,则使用正则表达式最长的那个.
    • 第四优先级: 常规字符串匹配类型.按前缀匹配.
    1
    (location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

文件路径的定义

  • root方式设置资源路径

    1
    2
    3
    语法: root path 
    默认值: root html
    配置段: http、server、location、if
  • alias方式设置资源路径

    1
    2
    语法: alias path 
    配置段: location
    • 使用alias时,目录名后面一定要加上/

    • alias可以指定任何名称

    • alias在使用正则匹配时,必须捕捉匹配的内容并指定的内容处使用

    • alias只能位于location块中

    • 例如,如果有一个请求的URI/conf/nginx.conf,而用户实际想访问的文件在/usr/local/nginx/conf/nginx.conf,那么想要使用alias来进行设置的话,可以采用如下方式:

      1
      2
      3
      location /conf {
      alias /usr/local/nginx/conf/;
      }
    • 如果用root设置,那么语句如下所示:

      1
      2
      3
      location /conf {
      root /usr/local/nginx/;
      }
    • 使用alias时,在URI向实际文件路径的映射过程中,已经把location后配置的/conf这部分字符串丢弃掉,因此,/conf/nginx.conf请求将根据alias path映射为path/nginx.conf

    • root则不然,它会根据完整的URI请求来映射,因此,/conf/nginx.conf请求会根据root path映射为path/conf/nginx.conf.

  • 访问首页

    1
    2
    3
    Syntax:	index file ...;
    Default: index index.html;
    Context: http, server, location
  • 根据HTTP返回码重定向页面

    1
    2
    3
    Syntax:	error_page code ... [=[response]] uri;
    Default: —
    Context: http, server, location, if in location
    1
    2
    error_page 404             /404.html;
    error_page 500 502 503 504 /50x.html

第二部分 如何编写HTTP模块

第三章 开发一个简单的HTTP模块

第四章 配置error日志和请求上下文

第五章 访问第三方服务

第六章 开发一个简单的HTTP过滤模块

第七章 Nginx提供的高级数据结构

第三部分 深入Nginx

第八章 Nginx基础架构

第九章 事件模块

第十章 HTTP框架初始化

第十一章 HTTP框架的执行流程

第十二章 upstream机制的设计与实现

第十三章 邮件代理模块

第十四章 进程间的通信机制

第十五章 变量

第十六章 slab共享内存