《深入理解 Nginx》读书笔记

一、研究 Nginx 前的准备

1.1 Nginx 是什么

Nginx 官网Nginx Wiki第三方模块

Nginx 与 Apache、Tomcat、Jetty 都是 Web 服务器

1.2 为什么选择 Nginx

  1. 高扩展
  2. 高可靠
  3. 高并发(单机可支持 10 万以上的并发连接)
  4. 热部署
  5. 免费开源

1.3 编译安装 Nginx

  1. 下载 Nginx tar.gz 包

  2. 执行安装命令

    # 检测操作系统内核和已经安装的软件,我在这里指定参数安装目录为 /usr/shuang/nginx 并安装模块 http_stub_status_module
    ./configure --prefix=/usr/shuang/nginx --with-http_stub_status_module
    
    make 
    
    make intall
    

1.4 Nginx 的命令行控制

  • 启动 nginx 服务

    # 启动(默认读取的是 ../conf/nginx.conf 配置文件)
    /usr/shuang/nginx/sbin/nginx 
    # 或者进入 sbin 目录下,执行
    ./nginx
    
    # 启动(指定读取 ../conf/nginx1.conf 配置文件)
    ./nginx -c ../conf/nginx1.conf
    
  • 查看版本信息

    # 显示版本信息
    ./nginx -v
    
    # 显示编译阶段的参数(大写 V)
    ./nginx -V
    
    # nginx version: nginx/1.19.10
    # built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
    # configure arguments: --prefix=/usr/shuang/nginx
    
  • 校验配置信息(nginx.conf 文件)

    # 校验配置文件是否正确
    ./nginx -t
    
    # 校验配置文件是否正确(不输出 error 级别以下的信息到屏幕)
    ./nginx -t -q
    
  • 停止 nginx 服务

    # 快速地强制停止 nginx 服务
    ./nginx -s stop
    
    # "优雅"地停止 nginx 服务
    ./nginx -s quit
    
  • 使运行中的 nginx 重读配置项并生效

    ./nginx -s reload
    
  • 显示所有支持的命令行参数

    ./nginx -?
    # 或者
    ./nginx -h
    

二、Nginx 的配置

2.1 运行中的 Nginx 进程间的关系

  • Nginx 使用一个 master 进程管理多个 worker 进程,一般情况下,worker 进程的数量与服务器上的 CPU 核心数相等

  • 每一个 worker 进程都是很繁忙的,它们在真正地提供互联网服务,master 相对“清闲”,只负责监控管理 worker 进程

  • worker 进程之间通过共享内存、原子操作等一些进程间的通信机制来实现负载均衡等功能

  • master 进程需要拥有较大的权限,而 worker 进程权限要小于等于 master 进程的权限,这样 master 进程才能完全管理 worker 进程

  • 当任意一个 worker 进程出现错误从而导致 coredump 时,master 进程会立刻启动新的 worker 进程继续服务

  • 多个 worker 进程可以充分利用现在常见的 SMP 多核架构,从而实现微观上真正的多核并发处理

  • 为什么 nginx 将 worker 进程数量与 CPU 核心数量保持一致,与 Apache 不同呢?

    当 Nginx 上的进程数与 CPU 核心数相等时(最好每一个 worker 进程都绑定特定的 CPU 核心),此时进程间切换的代价是最小的。

    举例说:服务器 CPU 的核心数为 8,那么就需要配置 8 个 worker 进程

    nginx.conf 文件中配置:worker_processes 1;

2.2 Nginx 配置的通用语法

2.2.1 块配置项

块配置项由一个块配置项名和一对大括号组成

events {
	...
}

http {
	server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }
	}
}
  • 所有事件类配置都要在 events 块中
  • 块配置项可以嵌套,内层块直接继承外层块;当内外层块中的配置发生冲突时,究竟是以内层块还是外层块的配置为准,取决于解析这个配置项的模块

2.2.2 配置项的语法格式

# 格式如下
配置项名 配置项值1 配置项值2 ...;

配置项名在行首,可以配置多个值,多个值之间由空格符来分隔,每行配置的结尾必须加分号

2.2.3 配置项的注释

加 “#” 注释掉这一行配置

2.2.4 配置项的单位

大部分模块遵循一些通用的规定,如指定空间大小不用每次定义到字节,指定时间不用精确到毫秒

  • 当指定空间大小时,可以使用的单位包括:

    # K 或者 k(千字节)
    gzip_buffers   4  8k;
    # M 或者 m(兆字节)
    client_max_body_size  64M;
    
  • 当指定时间时,可以使用的单位包括:

    # ms(毫秒)、s(秒)、m(分钟)、h(小时)、d(天)、w(周,7天)、M(月,30天)、y(年,365天)
    expires  10y;
    proxy_read_timeout  600;
    client_body_timeout  2m;
    

配置项后的值究竟是否可以使用这些单位,取决于解析该配置项的模块

2.2.5 在配置中使用变量

使用变量时,在其前面加上 “$” 符号

注意:这种变量只有少数模块支持,并不是通用的

2.3 Nginx 服务的基本配置

Nginx 在运行时,至少必须加载几个核心模块和一个事件类模块

这些模块运行时所支持的配置项称为基本配置——所有其他模块执行时都依赖的配置项

配置项很多,按照用户使用时的预期功能分成了以下 4 类:

2.3.1 用于调试进程和定位问题的配置项

  1. error 日志的设置

    # 语法:error_log /path/file level;
    # 默认:error_log logs/error.log error;
    

    error 日志是定位 Nginx 问题的最佳工具

    level 是日志的输出级别,取值范围为 debug、info、notice、warn、error、crit、alert、emerg,从左到右级别依次增大,小于该级别的日志则不会输出

    如果日志级别设定到 debug,必须在 configure 时加入 --with-debug 配置项

2.3.2 正常运行的配置

  1. 指定 Nginx worker 进程可以打开的最大句柄的描述符个数

    # 语法:worker_rlimit_onfile limit;
    # 例:设置最大句柄的描述符个数为 512000
    worker_rlimit_nofile 512000;
    
  2. 限制信号队列

    设置每个用户发往 Nginx 的信号队列的大小。若某个用户的信号队列满了,这个用户再发送的信号量会被丢掉。

    # 语法:worker_rlimit_sigpending limit;
    

2.3.3 优化性能的配置项

  1. Nginx worker 进程个数

    在 master/worker 运行方式下,定义 worker 进程的个数

    # 语法:worker_processes number;
    # 默认:worker_processes 1;
    

2.3.4 事件类配置项

  1. 选择事件模型

    # 语法:use [kqueue | rtsig | epoll | /dev/poll | select | poll | eventport ];
    # 默认:Nginx 会自动使用最适合的事件模型
    # 例:使用 epoll 事件模型
    use epoll;
    
  2. 每个 worker 的最大连接数

    # 语法:worker_connections number;
    # 例:设置最大连接数为 512000
    worker_connections  512000;
    

2.4 用 HTTP 核心模块配置一个静态 Web 服务器

所有的 HTTP 配置项都必须直属于 http 块、server 块、location 块、upstream 块或 if 块等

Nginx 为配置一个完整的静态 Web 服务器提供了非常多的功能,把这些配置项分为大致 8 类:

2.4.1 虚拟主机与请求的分发

背景:IP 地址的数量有限,经常存在多个主机域名对应着同一个 IP 地址的情况

实现:nginx.conf 中按照 server_name(对应用户请求中的主机域名)并通过 server 块来定义虚拟主机,每个 server 块就是一个虚拟主机,它只处理与之相对应的主机域名请求

作用:一台服务器上的 Nginx 以不同的方式处理 访问不同主机域名的 HTTP 请求

  1. 监听端口

    作用:指定监听的端口

    listen 参数决定 Nginx 服务如何监听端口

    在 listen 后可以只加 IP 地址、端口或者主机名,非常灵活

    # 语法:listen address:port;
    # 默认:listen 80;
    # 配置块:server
    # 例:监听 127.0.0.1 的 8000 端口
    listen 127.0.0.1:8000;
    
    # 例:监听 127.0.0.1 的 80 端口(不加端口时,默认监听 80 端口)
    listen 127.0.0.1;
    
    # 例:监听 8000 端口
    listen 8000;
    
    # 例:监听 localhost 的 8000 端口
    listen localhost:8000;
    
    # 例:监听 443 端口,加上 default_server ssl 参数
    listen 443 default_server ssll;
    

    参数说明:

    • default:将所在的 server 块作为整个 Web 服务的默认 server 块。当一个请求无法匹配配置文件中的所有主机域名时,就会选用默认的虚拟主机。
    • default_server:与 default 相同
    • ssl:在当前监听的端口上建立的连接必须基于 ssl 协议
  2. 主机名称

    # 语法:server_namee name [...]
    # 默认:server_name ""
    # 配置块:server
    # 例:Host 为 www.testweb.com download.testweb.com 的域名,交由该 server 进行处理
    server_name	www.testweb.com download.testweb.com;
    

    server_name 后可以跟多个主机名称

    配置项作用:处理 HTTP 请求时,Nginx 会取出 header 中的 Host,与每个 server 中的 server_name 进行匹配,以此决定到底由哪一个 server 块来处理这个请求。

    匹配优先级:有可能一个 Host 与多个 server 块中的 server_name 都匹配,这里就会根据匹配优先级来选择实际处理的 server 块

    server_name 与 Host 的匹配优先级如下:

    1. 首先选择所有字符串完全匹配的 server_name,如 www.testweb.com
    2. 其次选择通配符在前面的 server_name,如 *.testweb.com
    3. 再次选择通配符在后面的 server_name,如 www.testweb.*
    4. 最后选择使用正则表达式才匹配上的 server_name,如 ~^.testweb\.com$

    这个规则则是带通配符散列表的实现依据

    如果 Host 与所有的 server_name 都不匹配,这里将会按下列顺序选择处理的 server 块

    1. 优先选择在 listen 配置项后加入 [default | default_server] 的 server 块
    2. 找到匹配 listen 端口的第一个 server 块

    Nginx 正是使用 server_name 配置项针对特定 Host 域名的请求提供不同的服务,以此实现虚拟主机功能

  3. server_names_hash_bucket_size

    作用:提高快速寻找到相应 server name 的能力,Nginx 使用散列表来存储 server name

    server_names_hash_bucket_size 设置了每个散列桶占用的内存大小

    # 语法:server_names_hash_bucket_size size;
    # 默认:server_names_hash_bucket_size 32|64|128;
    # 配置块:http、server、location
    
  4. server_names_hash_max_size

    server_names_hash_max_size 会影响散列表的冲突率

    server_names_hash_max_size 越大,消耗的内存就越多,但散列 key 的冲突率则会降低,检索速度也更快

    server_names_hash_max_size 越小,消耗的内存就越少,但散列 key 的冲突率可能增高

    # 语法:server_names_hash_max_size size;
    # 默认:server_names_hash_max_size 512;
    # 配置块:http、server、location
    
  5. 重定向主机名称的处理

    该配置需要配置 server_name 使用。

    在使用 on 打开时,表示在重定向请求时会使用 server_name 里配置的第一个主机名代替原先请求中的 Host 头部

    而使用 off 关闭时,表示在重定向请求时使用请求本身的 Host 头部

    # 语法:server_name_in_redirect on | off;
    # 默认:server_name_in_redirect on;
    # 配置块:http、server、location
    
  6. location

    # 语法:location [= | ~ | ~* | ^~ | @] /uri/ {...}
    # 配置块:server
    

    location 会尝试根据用户请求的 URI 来匹配上面的 /uri 表达式,如果可以匹配,就选择 location {} 块中的配置来处理用户请求。

    location 的几种配置规则:

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

      location = / {
      	# 只有当用户请求是 / 时,才会使用该 location 下的配置
        ...
      }
      
    2. ~ 表示匹配 URI 时是字母大小写敏感的(TEST != test)

    3. ~* 表示匹配 URI 时忽略字母大小写问题(TEST == test == Test == TesT)

    4. ^~ 表示匹配 URI 时只需要其前半部分与 uri 参数匹配即可

      location ^~ /images {
      	# 以 /images/ 开始的请求都会匹配上,进入该 location 块
      	...
      }
      
    5. @ 表示仅用于 Nginx 服务内部请求之间的重定向,带有 @ 的 location 不直接处理用户请求

    6. 在 uri 参数里是可以用正则表达式的

      location ~* \.(gif|jpg|jpeg)$ {
       	# 匹配以 .gif、.jpg、.jpeg 结尾的请求
        ...
       }
      
    7. 匹配所有请求

      location / {
      	# / 可以匹配所有请求
      	...
      }
      

    location 是有顺序的,当一个请求有可能匹配多个 location 时,实际上这个请求会被第一个 location 处理

    小技巧:一般在最后一个 location 中使用 / 作为参数,它会匹配所有的 HTTP 请求,这样就可以表示如果不能匹配前面的所有 location,则由 “/” 这个 location 处理

2.4.2 文件路径的定义

常见的文件路径的定义配置项

  1. 以 root 方式设置资源路径

    # 语法:root path;
    # 默认:root html;
    # 配置块:http、server、location、if
    

    例如:定义资源文件相对于 HTTP 请求的根目录

    # 若请求的 URI 是 /download/index/test.html,那么 Web 服务器会返回服务器上 
    # /opt/web/html/download/index/test.html 文件的内容(把 /download/ 替换为 /opt/web/html/download/)
    location /download/ {
    	root /opt/web/html/;
    }
    
  2. 以 alias 方式设置资源路径

    # 语法:alias path;
    # 配置块:location
    

    alias 也是用来设置文件资源路径的

    与 root 的不同点:在于如何解读 location 后的 uri 参数,将会致使 alias 与 root 以不同的方式将用户请求映射到真正的磁盘文件上

    例如:用户实际想访问的文件在 /usr/local/nginx/conf/nginx.conf

    # alias 方式实现(直接使用 alias 的配置)
    location /conf {
    	alias /usr/local/nginx/conf/;
    }
    
    # root 方式实现(root 的配置 + /conf)
    location /conf {
    	root /usr/local/nginx/;
    }
    
  3. 访问首页

    # 语法:index file ...;
    # 默认:index index.html;
    # 配置块:http、server、location
    

    作用:有点访问站点时的 URI 是 /,这里一般是返回网站的首页,这与 root、alias 不同

    使用 ngx_http_index_module 模块中提供的 index 配置实现。

    index 后可以跟多个文件参数,Nginx 将会按照顺序(倒序)来访问这些文件

    location / {
    	root path;
    	index /index.html /html/index.php /index.php;
    }
    

    接收到请求后,Nginx 首先会尝试访问 path/index.php 文件,如果可以访问,就直接返回文件内容结束请求,否则再尝试返回 path/html/index.php 文件的内容

  4. 根据 HTTP 返回码重定向页面

  5. 是否允许递归使用 error_page

  6. try_files

2.4.3 内存及磁盘资源的分配

常见的处理请求时内存、磁盘资源分配的配置项

2.4.4 网络连接的设置

  1. 发送响应的超时时间

    默认单位:秒

    Nginx 服务器向客户端发送了数据包,但客户端在 send_timeout 时间内未接收数据包,则 Nginx 关闭这个连接

    # 语法:send_timeout time;
    # 配置:send_timeout 60;
    # 配置块:http、server、location
    
  2. keepalive 超时时间

    默认单位:秒

    # 语法:keepalive_timeout time;
    # 默认:keepalive_timeout 75;
    # 配置块:http、server、location
    

    一个 keepalive 连接在闲置设定的时间后,服务器和浏览器都会去关闭这个连接。

2.4.5 MIME 类型的设置

2.4.6 对客户端请求的限制

2.4.7 文件操作的优化

常见的文件操作的优化配置项

  1. sendfile 系统调用

    # 语法:sendfile on | off;
    # 默认:sendfile off;
    # 配置块:http、server、location
    

    作用:提高了发送文件的效率

    通过启动 Linux 上的 sendfile 系统调用来发送文件,它减少了内核态与用户态之间的两次内存复制,这样就会从磁盘中读取文件后直接在内核态发送到网卡设备

2.4.8 对客户端请求的特殊处理

  1. 文件未找到时是否记录到 error 日志

    # 语法:log_not_found on | off;
    # 默认:log_not_found on;
    # 配置块:http、server、location
    

    当用户请求且需要访问文件时,如果没有找到文件,是否将错误日志记录到 error.log 文件中

    该配置仅用于定位问题

  2. merge_slashes

    # 语法:merge_slashes on | off;
    # 默认:merge_slashes on;
    # 配置块:http、server、location
    

    此配置项表示是否合并相信的 “/”,例如,//test///a.txt,在配置项为 on 时,会将其匹配为 /test/a.txt

    如果配置为 off,则不会匹配,URI 将仍然是 //test///a.txt

  3. DNS 解析地址

    # 语法:resolver address ...;
    # 配置块:http、server、location
    # 例:设置 DNS 名字解析服务器的地址
    resolver 127.0.0.1 192.0.2.1;
    
  4. DNS 解析的超时时间

    # 语法:resolver_timeout time;
    # 默认:resolver_timeout 30s;
    # 配置块:http、server、location
    

    配置 DNS 解析的超时时间

  5. 返回错误页面时是否在 Server 中注明 Nginx 版本

    # 语法:server_tokens on | off;
    # 默认:server_tokens on;
    # 配置块:http、server、location
    

    表示请求出错时,是否在响应的 Server 头部中标明 Nginx 版本

    便于定位问题

2.4.9 ngx_http_core_module 模块提供的变量

常见的变量记录如下:

参数名意义
$uri当前请求的 URL,不带任何参数
$arg_PARAMETERHTTP 请求中的某个参数的值,如 /index.html?size=100,可以用 $arg_size 取得 100 这个值
$argsHTTP 请求中的完整参数。例如,在请求 /index.html?_w=100&_h=100 中,$args 表示字符串 _w=100&_h=100
$content_type客户端请求头部的 Content-Length 字段
$content_Length客户端请求头部的 Content-Type 字段
$cookie_COOKIE客户端请求头部的 cookie 字段
$host客户端请求头部的 Host 字段
$hostnameNginx 所在机器的名称
$limit_rate当前连接的限速是多少,0 表示无限速
$nginx_version当前 Nginx 的版本号,如 1.0.18
$remote_addr客户端地址
$remote_port客户端连接使用的端口
$schemeHTTP scheme,如 https://nginx.com/ 中的 https
$server_addr服务器地址
$server_port服务器端口
$server_name服务器名称

2.5 用 HTTP proxy module 配置一个反向代理服务器(常用)

反向代理(reverse proxy)方式是指代理服务器来接受 Intenet 上的连接请求,然后将请求转发给内部网络中的应用服务器,并将从应用服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外的表现就是一个 Web 服务器。

充当反向代理服务器也是 Nginx 的一种常见用法

2.5.1 负载均衡的基本配置

作为代理服务器,一般都需要向应用服务器的集群转发请求

负载均衡策略:尽量把请求平均地分布到每一台应用服务器上

负载均衡配置项:

  1. upstream 块

    upstream 块定义了一个应用服务器的集群,便于反向代理中的 proxy_pass 使用

    # 语法:upstream name {...}
    # 配置块:http
    upstream backend {
    	server 10.99.80.31:8001;
        server 10.99.80.32:8001;
    	server 10.99.80.35:8001 max_fails=5 fail_timeout=60s weight=1;
    }
    
    # 将所有请求分发到 backend 集群中
    server {
    	location / {
    		proxy_pass http://backend;
    	}
    }
    
  2. server 块

    server 配置项指定了一台应用服务器的名字,这个名字可以是域名、IP 地址端口、UNIX 句柄等

    # 语法:server name [parameters];
    # 配置块:upstream
    

    主要参数:

    • weight=number:设置向这台应用服务器转发的权重,默认 1
    • max_fails=number:与 fail_timeout 配合使用,指在 fail_timeout 时间段内,如果向该应用服务器转发失败次数超过 number 次,则认为在当前的 fail_timeout 时间段内这台应用服务器不可用。max_fail 默认为 1,如果设置为 0,则表示不检查失败次数
    • fail_timeout=time:fail_timeout 表示该时间段内转发失败多少后就认为应用服务器暂时不可用,用于优化反向代理功能。默认为 10 秒
    • down:表示该应用服务器永久下线,只在使用 ip_hash 配置项时才有用
  3. ip_hash

    应用场景:确保同一个客户端的请求只会转发到指定的应用服务器中

    实现方式:根据客户端的 IP 地址计算出一个 key,将 key 按照 upstream 集群里的应用服务器数量进行取模,然后以取模后的结果把请求转发到相应的应用服务器中

    upstream backend {
    	ip_hash;
    	server 10.99.80.31:8001;
        server 10.99.80.32:8001 down;
    	server 10.99.80.35:8001;
    }
    

    ip_hash 与 weight(权重)配置不可同时使用,如果 upstream 集群中有一台应用服务器暂时不可用,不能直接删除该配置,而是要用 down 参数标识,确保转发策略的一致性。

2.5.2 反向代理的基本配置

介绍几种常见的配置项

  1. proxy_pass

    此配置项将当前请求反向代理到 URL 参数指定的服务器上,URL 可以是主机名或 IP 地址加端口的形式

    # 语法:proxy_pass URL;
    # 配置块:location、if
    # 例:
    proxy_pass http://localhost:8000/uri/;
    # 用户可以把 HTTP 转换成更安全的 HTTPS
    proxy_pass https://192.168.0.1;
    
    # 直接代理到 upstream 块
    upstream backend {
    	server 10.99.80.31:8001;
        server 10.99.80.32:8001;
    	server 10.99.80.35:8001 max_fails=5 fail_timeout=60s weight=1;
    }
    
    # 将所有请求分发到 backend 集群中
    server {
    	# 默认情况下反向代理是不会转发请求中的 Host 头部的。如果需要转发,那么必须加上配置
    	proxy_set_header Host $host;
    	
    	location / {
    		proxy_pass http://backend;
    	}
    }
    
  2. proxy_method

    此配置项表示转发时的协议方法名

    # 语法:proxy_method method
    # 配置块:http、server、location
    # 例:将客户端发来的 GET 请求在转发时改为 POST 请求
    proxy_method POST
    
  3. proxy_hide_header

    Nginx 会将应用服务器的响应转发给客户端,使用 proxy_hide_header 后可以任意地指定哪些 HTTPS 头部字段不能被转发

    # 语法:proxy_hide_header the_header;
    # 配置块:http、server、location
    # 例:指定 Cache-Control 头部字段不能被转发
    proxy_hide_header Cache-Control
    
  4. proxy_pass_header

    与 proxy_hide_header 功能相反,proxy_pass_header 会将原来禁止转发的 header 设置为允许转发

    # 语法:proxy_pass_header the_header;
    # 配置块:http、server、location
    # 例:允许转发头部字段 X-Accel-Redirect;
    proxy_pass_header X-Accel-Redirect;
    
  5. proxy_pass_request_body

    作用:确定是否向应用服务器发送 HTTP 包体部分

    # 语法:proxy_pass_header on | off;
    # 默认:proxy_pass_header on;
    # 配置块:http、server、location
    
  6. proxy_pass_request_headers

    作用:确定是否转发 HTTPS 头部

    # 语法:proxy_pass_request_headers on | off;
    # 默认:proxy_pass_request_headers on;
    # 配置块:http、server、location
    
  7. proxy_redirect

    当应用服务器的响应是重定向或刷新请求(HTTP 响应码是 301 或 302)时,proxy_redirect 可以重设 HTTP 头部的 location 或 refresh 字段

    # 语法:proxy_redirect [default|off|redirect replacement];
    # 默认:proxy_redirect default;
    # 配置块:http、server、location
    
    • redirect replacement:使用 replacement 替换 redirect
    • default:按照 proxy_pass 配置项和所属的 location 配置项重组发往客户端的 location 头部
    • off:使 location 或者 refresh 字段维持不变
  8. proxy_next_upstream

参考书籍

  • 《深入理解Nginx——模块开发与架构解析》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值