文章目录
一、研究 Nginx 前的准备
1.1 Nginx 是什么
Nginx 与 Apache、Tomcat、Jetty 都是 Web 服务器
1.2 为什么选择 Nginx
- 高扩展
- 高可靠
- 高并发(单机可支持 10 万以上的并发连接)
- 热部署
- 免费开源
1.3 编译安装 Nginx
-
执行安装命令
# 检测操作系统内核和已经安装的软件,我在这里指定参数安装目录为 /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 用于调试进程和定位问题的配置项
-
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 正常运行的配置
-
指定 Nginx worker 进程可以打开的最大句柄的描述符个数
# 语法:worker_rlimit_onfile limit; # 例:设置最大句柄的描述符个数为 512000 worker_rlimit_nofile 512000;
-
限制信号队列
设置每个用户发往 Nginx 的信号队列的大小。若某个用户的信号队列满了,这个用户再发送的信号量会被丢掉。
# 语法:worker_rlimit_sigpending limit;
2.3.3 优化性能的配置项
-
Nginx worker 进程个数
在 master/worker 运行方式下,定义 worker 进程的个数
# 语法:worker_processes number; # 默认:worker_processes 1;
2.3.4 事件类配置项
-
选择事件模型
# 语法:use [kqueue | rtsig | epoll | /dev/poll | select | poll | eventport ]; # 默认:Nginx 会自动使用最适合的事件模型 # 例:使用 epoll 事件模型 use epoll;
-
每个 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 请求
-
监听端口
作用:指定监听的端口
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 协议
-
主机名称
# 语法: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 的匹配优先级如下:
- 首先选择所有字符串完全匹配的 server_name,如 www.testweb.com
- 其次选择通配符在前面的 server_name,如 *.testweb.com
- 再次选择通配符在后面的 server_name,如 www.testweb.*
- 最后选择使用正则表达式才匹配上的 server_name,如
~^.testweb\.com$
这个规则则是带通配符散列表的实现依据
如果 Host 与所有的 server_name 都不匹配,这里将会按下列顺序选择处理的 server 块
- 优先选择在 listen 配置项后加入 [default | default_server] 的 server 块
- 找到匹配 listen 端口的第一个 server 块
Nginx 正是使用 server_name 配置项针对特定 Host 域名的请求提供不同的服务,以此实现虚拟主机功能
-
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
-
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
-
重定向主机名称的处理
该配置需要配置 server_name 使用。
在使用 on 打开时,表示在重定向请求时会使用 server_name 里配置的第一个主机名代替原先请求中的 Host 头部
而使用 off 关闭时,表示在重定向请求时使用请求本身的 Host 头部
# 语法:server_name_in_redirect on | off; # 默认:server_name_in_redirect on; # 配置块:http、server、location
-
location
# 语法:location [= | ~ | ~* | ^~ | @] /uri/ {...} # 配置块:server
location 会尝试根据用户请求的 URI 来匹配上面的 /uri 表达式,如果可以匹配,就选择 location {} 块中的配置来处理用户请求。
location 的几种配置规则:
-
= 表示把 URI 作为字符串,以便与参数中的 uri 做完全匹配。
location = / { # 只有当用户请求是 / 时,才会使用该 location 下的配置 ... }
-
~ 表示匹配 URI 时是字母大小写敏感的(TEST != test)
-
~* 表示匹配 URI 时忽略字母大小写问题(TEST == test == Test == TesT)
-
^~ 表示匹配 URI 时只需要其前半部分与 uri 参数匹配即可
location ^~ /images { # 以 /images/ 开始的请求都会匹配上,进入该 location 块 ... }
-
@ 表示仅用于 Nginx 服务内部请求之间的重定向,带有 @ 的 location 不直接处理用户请求
-
在 uri 参数里是可以用正则表达式的
location ~* \.(gif|jpg|jpeg)$ { # 匹配以 .gif、.jpg、.jpeg 结尾的请求 ... }
-
匹配所有请求
location / { # / 可以匹配所有请求 ... }
location 是有顺序的,当一个请求有可能匹配多个 location 时,实际上这个请求会被第一个 location 处理
小技巧:一般在最后一个 location 中使用 / 作为参数,它会匹配所有的 HTTP 请求,这样就可以表示如果不能匹配前面的所有 location,则由 “/” 这个 location 处理
-
2.4.2 文件路径的定义
常见的文件路径的定义配置项
-
以 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/; }
-
以 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/; }
-
访问首页
# 语法: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 文件的内容
-
根据 HTTP 返回码重定向页面
-
是否允许递归使用 error_page
-
try_files
2.4.3 内存及磁盘资源的分配
常见的处理请求时内存、磁盘资源分配的配置项
2.4.4 网络连接的设置
-
发送响应的超时时间
默认单位:秒
Nginx 服务器向客户端发送了数据包,但客户端在 send_timeout 时间内未接收数据包,则 Nginx 关闭这个连接
# 语法:send_timeout time; # 配置:send_timeout 60; # 配置块:http、server、location
-
keepalive 超时时间
默认单位:秒
# 语法:keepalive_timeout time; # 默认:keepalive_timeout 75; # 配置块:http、server、location
一个 keepalive 连接在闲置设定的时间后,服务器和浏览器都会去关闭这个连接。
2.4.5 MIME 类型的设置
2.4.6 对客户端请求的限制
2.4.7 文件操作的优化
常见的文件操作的优化配置项
-
sendfile 系统调用
# 语法:sendfile on | off; # 默认:sendfile off; # 配置块:http、server、location
作用:提高了发送文件的效率
通过启动 Linux 上的 sendfile 系统调用来发送文件,它减少了内核态与用户态之间的两次内存复制,这样就会从磁盘中读取文件后直接在内核态发送到网卡设备
2.4.8 对客户端请求的特殊处理
-
文件未找到时是否记录到 error 日志
# 语法:log_not_found on | off; # 默认:log_not_found on; # 配置块:http、server、location
当用户请求且需要访问文件时,如果没有找到文件,是否将错误日志记录到 error.log 文件中
该配置仅用于定位问题
-
merge_slashes
# 语法:merge_slashes on | off; # 默认:merge_slashes on; # 配置块:http、server、location
此配置项表示是否合并相信的 “/”,例如,
//test///a.txt
,在配置项为 on 时,会将其匹配为/test/a.txt
如果配置为 off,则不会匹配,URI 将仍然是
//test///a.txt
-
DNS 解析地址
# 语法:resolver address ...; # 配置块:http、server、location # 例:设置 DNS 名字解析服务器的地址 resolver 127.0.0.1 192.0.2.1;
-
DNS 解析的超时时间
# 语法:resolver_timeout time; # 默认:resolver_timeout 30s; # 配置块:http、server、location
配置 DNS 解析的超时时间
-
返回错误页面时是否在 Server 中注明 Nginx 版本
# 语法:server_tokens on | off; # 默认:server_tokens on; # 配置块:http、server、location
表示请求出错时,是否在响应的 Server 头部中标明 Nginx 版本
便于定位问题
2.4.9 ngx_http_core_module 模块提供的变量
常见的变量记录如下:
参数名 | 意义 |
---|---|
$uri | 当前请求的 URL,不带任何参数 |
$arg_PARAMETER | HTTP 请求中的某个参数的值,如 /index.html?size=100 ,可以用 $arg_size 取得 100 这个值 |
$args | HTTP 请求中的完整参数。例如,在请求 /index.html?_w=100&_h=100 中,$args 表示字符串 _w=100&_h=100 |
$content_type | 客户端请求头部的 Content-Length 字段 |
$content_Length | 客户端请求头部的 Content-Type 字段 |
$cookie_COOKIE | 客户端请求头部的 cookie 字段 |
$host | 客户端请求头部的 Host 字段 |
$hostname | Nginx 所在机器的名称 |
$limit_rate | 当前连接的限速是多少,0 表示无限速 |
$nginx_version | 当前 Nginx 的版本号,如 1.0.18 |
$remote_addr | 客户端地址 |
$remote_port | 客户端连接使用的端口 |
$scheme | HTTP 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 负载均衡的基本配置
作为代理服务器,一般都需要向应用服务器的集群转发请求
负载均衡策略:尽量把请求平均地分布到每一台应用服务器上
负载均衡配置项:
-
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; } }
-
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 配置项时才有用
-
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 反向代理的基本配置
介绍几种常见的配置项
-
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; } }
-
proxy_method
此配置项表示转发时的协议方法名
# 语法:proxy_method method # 配置块:http、server、location # 例:将客户端发来的 GET 请求在转发时改为 POST 请求 proxy_method POST
-
proxy_hide_header
Nginx 会将应用服务器的响应转发给客户端,使用 proxy_hide_header 后可以任意地指定哪些 HTTPS 头部字段不能被转发
# 语法:proxy_hide_header the_header; # 配置块:http、server、location # 例:指定 Cache-Control 头部字段不能被转发 proxy_hide_header Cache-Control
-
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;
-
proxy_pass_request_body
作用:确定是否向应用服务器发送 HTTP 包体部分
# 语法:proxy_pass_header on | off; # 默认:proxy_pass_header on; # 配置块:http、server、location
-
proxy_pass_request_headers
作用:确定是否转发 HTTPS 头部
# 语法:proxy_pass_request_headers on | off; # 默认:proxy_pass_request_headers on; # 配置块:http、server、location
-
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 字段维持不变
-
proxy_next_upstream
参考书籍
- 《深入理解Nginx——模块开发与架构解析》