You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
name 是给后端服务器组起的名字。花括号中列出后端服务器组中包含的服务器,其中可以使用下面介绍到的指令。
默认情况下,某个服务器组接收到请求以后,按照轮叫调度(Round-Robin,RR)策略顺序选择组内服务器处理请求,如果一个服务器在处理请求的过程中出现错误,请求会被依次交给组内下一个服务器进行处理,以此类推,直到返回正常响应。当所有组内服务器出错,则返回最后一个服务器的处理结果。当然,我们可以根据各个服务器处理能力或者资源配置情况的不同,给各个服务器配置不同的权重,让能力强的服务器多处理请求,能力弱的少处理。配置权重的变量包含在 server 指令中。
《Nginx 高性能 Web 服务器详解》于 2018 年购买,两年有余。印象中是看了一下就看不下去了,毕竟当时没有实际应用。现在终于使用上了,也遇到一些问题,所以有动力看了,并整理了笔记。
Nginx 初探
Nginx(engine-x)的开发工作从 2002 年开始,于 2004.10.04 发布正式版本,版本号为 0.1.0。Nginx 最早开发的目的之一是邮件代理服务器。
本书将 Nginx 提供的基本功能服务归纳为基本 HTTP 服务、高级 HTTP 服务和邮件服务等三大类。
基本 HTTP 服务
在 Nginx 提供的基本 HTTP 服务中,主要包含以下功能特性:
高级 HTTP 服务
在 Nginx 提供的高级 HTTP 服务中,主要包含以下功能特性:
邮件代理服务
Nginx 提供邮件代理服务也是基本开发需求之一,主要包含以下功能特性:
常用功能介绍
HTTP 代理和反向代理
负载均衡
Web 缓存
Nginx 服务器的安装部署
安装目录
Nginx 服务器的安装目录主要包括了 conf、html、logs 和 sbin 等 4 个目录。
Nginx 服务的启停控制
在 Linux 平台下,控制 Nginx 服务的启停有不止一种方法。
Nginx 服务的信号控制
信号机制是实现启停 Nginx 服务的方法之一。
Nginx 服务在运行时,会保持一个主进程和一个或多个 worker process 工作进程。我们通过给 Nginx 服务的主进程发送信号就可以控制服务的启停了,其步骤如下:
获取 PID 有两个途径:
a:在 Nginx 服务启动以后,默认在 Nginx 服务器安装目录下的 logs 目录中会产生文件名为 nginx.pid 的文件,此文件中保持的就是 Nginx 服务主进程的 PID。此文件的存放路径和文件名都可以在 Nginx 服务器的配置文件中进行设置。
b: 使用 Linux 平台下查看进程的工具 ps,其使用方法是:
表2.2 Nginx 服务可接受的信号
a. 使用 nginx 二进制文件,如
$ ./sbin/nginx -g <SIGNAL>
b. 使用 kill 命令发送信号,其语法:
kill <SIGNAL> PID
,SIGNAL 用于指定信号(即表 2.2);PID 为 Nginx 服务主进程的 PID,也可以使用 nginx.pid 动态获取 PID 号:kill <SIGNAL> 'filepath'
,其中,filepath 为 nginx.pid 路径。启动 Nginx 服务:在 Linux 平台下,直接运行安装目录下 sbin 目录中的二进制文件即可。
停止 Nginx 服务有两种方式:
a. 快速停止:立即停止当前 Nginx 服务正在处理的所有网络请求和丢弃连接,停止工作。
b. 平缓停止:允许 Nginx 服务将当前正在处理的网络请求处理完成,但不再接收新的请求,之后关闭连接,停止工作。
平滑重启的过程(如更改 Nginx 服务器的配置文件和加入新模块):Nginx 服务进程接收到信号后,首先读取新的 Nginx 配置文件,如果配置语法正确,则启动新的 Nginx 服务,然后平缓关闭旧的服务进程;如果新的 Nginx 配置有问题,将显示错误,仍然使用旧的 Nginx 进程提供服务。
平滑升级的过程(如 Nginx 服务器进行版本升级、应用新模块):Nginx 服务接收到 USR2 信号后,首先将旧的 nginx.pid 文件(如果在配置文件中更改过这个文件的名字,也是相同的过程)添加后缀 .oldbin,变为 nginx.pid.oldbin 文件;然后执行新版本 Nginx 服务器的二进制文件重启服务。如果新的服务器启动成功,系统中将有新旧两个 Nginx 服务共同提供 Web 服务。之后,需要向旧的 Nginx 服务进程发送 WINCH 信号,使旧的 Nginx 服务平滑停止,并删除 nginx.pid.oldbin 文件。在发送 WINCH 信号之前,可以随时停止新的 Nginx 服务。
Nginx 服务的启动、停止、重启、升级
Nginx 启动后,就能通过使用 -s 参数调用可执行文件来对其进行控制。语法如下:
signal 的取值:
什么叫重新打开日志文件?
内容来自:https://developer.aliyun.com/article/316188
先移动日志文件
发送信号重新打开日志文件
简单说明一下:
kill -USR1 cat ${pid_path}
之前,即便已经对文件执行了mv
命令也只是改变了文件的名称,Nginx 还是会向新命名的文件 “access.log.20161024” 中照常写入日志数据。原因在于 Linux 系统中,内核是根据文件描述符来找文件的。Nginx 服务器基础配置指令
默认的 Nginx 服务器配置文件都存放在安装目录 conf 中,主配置文件为 nginx.conf。
nginx.conf(展示各条语句的生效范围)
nginx.conf 文件的结构
nginx.conf 一共由三部分组成,分别为全局块、events 块和 http 块。在 http 块中,又包含 http 全局块、多个 server 块。每个 server 块中,可以包含 server 全局块和多个 location 块。在同一配置块中嵌套的配置块,各个之间不存在次序关系。
配置文件支持大量可配置的指令,绝大多数指令不是特定属于某一个块。同一个指令放在不同层级的块中,其作用域也不同。一般情况下,高一级块中的指令可作用于自身所在的块和此块包含的所有低层级块。若某个指令同时出现在两个不同层级的块中,则以较低层级块中的配置为准。
各个块的作用:
配置运行 Nginx 服务器用户(组)
用于配置运行 Nginx 服务器用户(组)的指令是 user,其语法格式为:
只有被设置的用户或者用户组成员才有权限启动 Nginx 进程,如果是其他用户(如 test_user)尝试启动 Nginx 进程,将会报错:
可以从错误信息中看到,Nginx 无法运行的原因是查找 test_user 失败,引起错误的原因是 nginx.conf 的第二行内容,即配置 Nginx 服务器用户(组)的内容。
如果希望所有用户都可以启动 Nginx 进程,有两种办法:
a. 将此指令注释掉:
# user <user> [group];
或者将用户(和用户组)设置为
nobody
:这也是 user 指令的默认配置。user 指令只能用在全局块。
配置允许生成的 worker_process 数
worker process 是 Nginx 服务器实现并发处理的关键所在。
worker_processes 指令用于配置允许生成的 worker process 数,其语法格式为:
在默认配置文件中,number = 1。
此指令只能在全局块中设置。
配置 Nginx 进程 PID 存放路径
Nginx 进程作为系统的守护进程运行,我们需要在某文件中保存当前运行程序的主进程号。Nginx 支持对它的存放路径进行自定义配置,指令是 pid,其语法格式为:
配置文件默认将此文件存放在 Nginx 安装目录 logs 下,名为 nginx.pid。支持绝对路径和以 Nginx 安装目录为根目录的相对路径。
此指令只能在全局块中设置。
配置错误日志的存放路径
使用 error_log 指令,其语法结构是:
Nginx 服务器的日志支持输出到特定文件 file 或者标准错误输出 stderr;日志的级别是可选项,由低到高分别为 debug(需要在编译时使用 --with-debug 开启 debug 开关)、info、notice、warn、error、crit、alert、emerg。需要注意的是,设置某一级别后,比该级别高的日志也会被记录。
Nginx 日志存放和级别的默认设置为:
error_log logs/eror.log error;
此指令可以在全局块、http 块、server 块以及 location 块中配置。
配置文件的引入
通过 include 指令将其他 Nginx 配置或者第三方模块的配置引入到主配置文件中。其语法结构:
此指令可放在配置文件的任何地方。
设置网络连接的序列化
在《UNIX 网络编程》第 1 卷里提到过一个叫“惊群”的问题(Thundering herd problem),大致意思是,当某一时刻只有一个网络连接到来时,多个睡眠进程会被同时唤醒,但只有一个进程可获得连接。如果每次唤醒的进程数目太多,会影响系统性能。在 Nginx 服务器的多进程下,就有可能出现这样的问题。
为了解决这样的问题,Nginx 配置中包含了这样一条指令 accept_mutex,当其设置为开启时,多个 Nginx 进程会序列化地接收连接,从而防止多个进程争抢连接。其语法结构为:
此指令默认为开启(on)状态。
此指令只能在 events 块中进行配置。
设置是否允许同时接收多个网络连接
每个 Nginx 服务器的 worker_process 都有能力同时接收多个新到达的网络连接,但这需要在配置文件中进行设置,其指令为 multi_accept,语法结构为:
此指令默认为关闭(off)状态,即每个 worker process 一次只能接收一个新到达的网络连接。
此指令只能在 events 块中进行配置。
事件驱动模型的选择
Nginx 服务器提供了多种事件驱动模型来处理网络消息。配置文件为我们提供了相关的指令来强制 Nginx 服务器选择哪种事件驱动模型进行消息处理,指令为 use,其语法结构为:
其中,method 可选择的内容有:select、poll、kqueue、epoll、rtsig、/dev/poll 以及 eventport。
此指令只能在 events 块中进行配置。
配置最大连接数
worker_connections 指令用于设置一个 worker process 可同时打开的最大连接数(注意,该连接数包含所有连接,如与代理服务器的连接等,而不仅是与客户端的连接)。其语法结构为:
此指令的默认设置为 512。
此指令只能在 events 块中进行配置。
定义 MIME-Type
MIME Type 是网络资源的媒体类型。Nginx 服务器作为 Web 服务器,必须能够识别客户端请求的资源类型。
在默认的 Nginx 配置文件中,我们看到在 http 全局块中有以下两行配置:
第一行从外部引用了 mime_types 文件,其内容片段如下:
从 mime_types 文件的内容片段可以看到,其中定义了一个 types 结构,结构中包含了浏览器能够识别的 MIME 类型以及对应于相关类型的文件后缀名。由于 mime_types 文件是主配置文件引入的第三方文件,因此,types 也是 Nginx 配置文件中的一个配置块,我们可称之为 types 块,其用于定义 MIME 类型。
第二行中使用指令 default_type 配置了用于处理客户端请求的 MIME 类型,其语法结构为:
其中,mime-type 为 types 块中定义的 MIME-type。该指令的默认值为 text/plain。
此指令可以在 http 块、server 块或者 location 块中进行配置。
自定义服务日志
在全局块中,我们介绍过 error_log 指令,其用于配置 Nginx 进程运行时的日志存放文件和级别。而服务日志是指记录 Nginx 服务器提供服务过程中客户端的请求日志。
Nginx 服务器支持对服务日志的格式、大小、输出等进行配置。这涉及两个指令,分别是 access_log 和 log_format 指令。
access_log 指令的语法结构为:
此指令的默认配置为:
access_log logs/access.log combined;
其中,combined 为 log_format 指令默认定义的日志格式字符串名称。
若要取消记录服务日志的功能,则使用:
access_log off;
此指令可以在 http 块、server 块或者 location 块中进行设置。
log_format 指令是用于定义服务日志的格式,并且可以为格式字符串定义名字,以便 access_log 指令直接调用。其语法格式为:
例子:
此指令只能在 http 块中进行配置。
配置允许 sendfile 方式传输文件
在 Apache、lighttd 等 Web 服务器配置总,都有和 sendfile 相关的配置。配置 sendfile 传输方式的相关指令 sendfile 和 sendfile_max_chunk 的语法结构:
用于开启或关闭使用 sendfile() 传输文件,默认值为 off。
此指令可以在 http 块、server 块或者 location 块中配置。
若 size 大于 0,则 Nginx 进程的每个 worker process 每次调用 sendfile() 传输的数据量最大不能超过这个值;若设置为 0,则无限制。默认值为 0。
例子:
sendfile_max_chunk 128k;
此指令可以在 http 块、server 块或 location 块中配置。
配置连续超时时间
与用户建立连接后,Nginx 服务器可以保持这些连接打开一段时间,此时间段通过指令 keepalive_timeout 设置,其语法结构:
例子:
keepalive_timeout 120s 100s;
其含义是:在服务器端保持连接的时间设置为 120s,发给用户端的响应报文头部中 Keep-Alive 域的超时时间设置为 100s。
此指令可以在 http 块、server 块或者 location 块中配置。
单连接请求数上限
Nginx 服务器端和用户端建立会话连接后,用户端通过此连接发送请求。指令 keepalive_requests 用于限制用户通过某一连接向 Nginx 服务器发送请求的次数。其语法结构为:
此指令可以出现在 http 块、server 块和 location 块。
配置网络监听
listen 指令看来起来比较复杂,但其实在一般的使用过程中,相对来说比较简单,其默认设置为:
即监听所有 80 端口和 8000 端口。
案例:
基于名称的虚拟主机配置
“主机”是指 server 块对外提供的虚拟主机。设置了主机的名称并配置好 DNS,用户就可以使用这个名称向此虚拟主机发送请求了。配置主机名称的指令为 server_name,其语法结构为:
name 支持设置多个名称,它们之间用空格隔开。Nginx 服务器规定,第一个名称作为此虚拟主机的主要名称。
name 支持三种形式:
对于通配符名称,通配符只能出现在名称的前后两侧,并且是
.
边上。例如,www.*.example.org
和w*.example.org
都是无效的,但它们可用在“正则表达式名称”,如~^www\..+\.example\.org$
和~^w.*\.example\.org$
。一个通配符能匹配多个片段(即 . 分隔的字符串),如*.example.org
不仅能匹配www.example.org
,还能匹配www.sub.example.org
。对于正则表达式名称,Nginx 使用的正则表达式与 Perl 编程语言(PCRE)的正则表达式兼容。要使用正则表达式,服务器名称必须以
~
字符开头。否则将被视为“确切名称”,或者如果表达式中包含星号,则被视为“通配符名称”(而且很可能是无效的名称)。不要忘记设置
^
和$
,虽然它们不是语法要求,但逻辑上需要。同时注意,域名的
.
应该用反斜杠转义。包含字符{
和}
的正则表达式应加双引号。否则 Nginx 将无法启动并显示错误信息。
对于正则表达式,支持几种方式的字符串捕获,并在稍后用作变量:
当通过 name 搜索虚拟主机,并且 name 被多个虚拟主机的 server_name 匹配,那么会根据以下规则决定该请求交给哪个虚拟主机处理(注:按 1 ~ 4 的优先顺序):
*
开头的最长通配符名称,如*.example.com
*
结尾的最长通配符名称,如mail.*
配置 location 块
location 的语法结构为:
以一个典型且简单的 PHP 网站为例:
Nginx 是如何选择一个 location 去处理请求的:
为了方便描述,我们约定:
Nginx 首先不考虑定义顺序,搜索与请求字符串最匹配的 prefix location(笔者注:此处匹配是指 startsWith,而不是 includes,这就是 prefix 所指的意思)。在上述配置中,只有
/
一个 prefix location,因为它与任意请求都匹配,所以它作为兜底选择。然后 Nginx 按照配置文件中含“正则 uri”的 location 的定义顺序,寻找第一个与请求字符串匹配的 location。若找到第一个匹配的“正则 uri”,则停止搜索并使用该 location。若最终找不到匹配的“正则 uri”,Nginx 则使用先前找到的最匹配 prefix location。需要注意的是,请求字符串的参数(即查询字符串)不参与所有类型的 location 的匹配。这是因为查询字符串中的参数能以多种方式给出,例如:
了解以上内容后,下面解释可选项中各个标识的含义:
=
:用于“标准 uri”前,要求请求字符串与 uri 严格相等才能匹配。如果匹配成功,则停止继续搜索并使用此 location 处理此请求。如果经常请求 “ /”,则定义 “location = /” 能加快该请求的处理速度。~
:用于表示 uri 包含正则表达式,并且区分大小写。~*
:用于表示 uri 包含正则表达式,并且不区分大小写。^~
:用于“标准 uri”前,表示搜索到与请求字符串最匹配的 prefix location 后,就停止搜索并使用此 location 处理此请求。我们看看以上 PHP 网站如何处理请求:
/logo.gif
请求首先与 prefix location/
匹配,然后与“正则 uri”\.(gif|jpg|png)$
匹配。因此,该请求会被后者 location 处理。使用指令root /data/www
将请求映射到文件/data/www/logo.gif
,然后该文件会被 Nginx 发送到客户端。/index.php
请求同样首先与 prefix location/
匹配,然后与“正则 uri”\.(php)$
匹配。因此,该请求会被后者 location 处理。该 location 会将该请求传递给在localhost:9000
监听的 FastCGI 服务器。fastcgi_param
指令设置 FastCGI 参数 SCRIPT_FILENAME 为/data/www/index.php
,从而 FastCGI 服务器会执行该文件。其中,变量$document_root
等同于root
指令的值,变量$fastcgi_script_name
等同于请求 URI,如/index.php
。/about.html
请求只与 prefix location/
匹配,因此,该请求由该 location 处理。使用指令root /data/www
将请求映射到文件/data/www/about.html
,然后该文件会被 Nginx 发送到客户端。/
请求的处理会复杂一些。它只与 prefix location/
匹配,因此,请请求由该 location 处理。指令 index 会根据其参数和root /data/www
指令检查 index file 是否存在。若文件/data/www/index.html
不存在,而/data/www/index.php
存在,则该指令会内部重定向到index.php
,即就像从客户端发送过来的请求一样,Nginx 会再次搜索 location。正如我们之前看到的那样,重定向后的请求最终会被 FastCGI 服务器处理。基于官方文档补充以下知识点:
location 块支持嵌套。显然,严格相等的 location(即 = uri)显然不支持嵌套 location。
还有一种以
@
为前缀的命名 location(named location),它不用于常规的请求处理,而是用于内部重定向请求。它不支持被嵌套和嵌套 location。可结合 try_files、error_page 指令使用:
如果 prefix location 以
/
结尾,并且请求由proxy_pass
、fastcgi_pass
、uwsgi_pass
、scgi_pass
、memcached_pass
、grpc_pass
中的一个指令处理,则会执行一个特殊处理。对于无/
结尾的请求,会以 301 永久重定向至追加/
后的 URI。如果这不是你想要的处理方式,请使用严格相等的 location,如下所示:配置请求的根目录
Web 服务器接收到网络请求之后,首先要在服务器端指定目录中寻找请求资源。在 Nginx 服务器中,指令 root 就是用来配置这个根目录的,其语法结构为:
$document_root
和$realpath_root
不可使用。此指令可以在 http 块、server 块 和 location 块中配置。
更改 location 的 URI
在 location 块中,除了用
root
指令指明处理请求的根目录,还可以用alias
指令改变 location 接收到的 URI 的请求路径,其语法结构为:$document_root
和$realpath_root
不可使用。为指定 location 定义一个替换值。如:
对于请求
/i/top.gif
,会向客户端返回/data/w3/images/top.gif
文件。当在“正则 uri”的 location 使用 alias,该“正则 uri”应该包含捕获(captures),然后在 alias 引用这些捕获,例如:
否则会出现意想不到的问题。
当 location 与 alias 指令的末段一致:
则更推荐使用 root 指令:
location /images/ { root /data/w3; }
另外,经笔者测试:
对于 prefix location,若 loaction 的 uri 末尾含
/
,而 alias 指令值的末尾不含/
,会返回 403。因此,对于 prefix location 内的 alias 指令值的末尾应该始终含
/
。设置网站的默认首页
指令 index 用于设置网站的默认首页。它一般有两个作用:
其语法结构为:
index.html
。案例:
当 location 块接收到
/data/locationtest/web/
请求时,匹配成功,它首先将预置变量 $1 置为locationtest
,然后在/data/locationtest/web/
路径下按照 index 的配置次序依次寻找 index.locationtest.html 页、index.my1.html 页和 index.html 页,将找到的页面作为请求响应。设置网站的错误页面
Nginx 服务器设置网站错误页面的指令为 error_page,其语法结构为:
案例:
设置 Nginx 服务器使用“Nginx 安装路径/html/404.html”页面响应 404 错误:
error_page 404 /404.html;
设置 Nginx 服务器使用
http://somewebsite.com/forbidden.html
页面响应 403 错误:error_page 403 http://somewebsite.com/forbidden.html;
设置 Nginx 服务器产生 410 的 HTTP 消息时,使用“Nginx 安装路径/html/empty.gif” 返回给用户端 301 消息。
error_page 410 =310 /empty.gif;
从以上案例看到,变量 uri 实际上是一个相对于 Nginx 安装路径的相对路径。如果我们不想将错误页面放到 Nginx 服务器的安装路径下,那么只需新增一个 location 指令将错误页面指向新的路径下即可。
error_page 404 /404.html location /404.html { root /myserser/errorpage/; }
error_page 指令可以在 http 块、server 块和 location 块中配置。
基于 IP 配置 Nginx 的访问权限
Nginx 通过两种途径支持基本的访问权限控制,其中一种是由 HTTP 标准模块 ngx_http_access_module 支持的,其通过 IP 来判断客户端是否拥有对 Nginx 的访问权限,这里涉及两个指令。
allow 指令,用于设置允许访问 Nginx 的客户端 IP,语法结构为:
deny 指令,用于设置禁止访问 Nginx 的客户端 IP,语法结构为:
在同时使用这两个指令时,需要注意设置为 all 的用法。
案例:
对于 deny 或 allow 指令,Nginx 是按顺序对当前客户端的连接进行访问权限检查的,当遇到匹配配置就停止向下搜索。因此,当 192.168.1.0/24 客户端访问时,Nginx 在第 3 行解析配置时发现允许该客户端访问,就不会继续寻找了,即允许该客户端访问。
这两个指令可以在 http 块、server 块或者 location 块中配置。
基于密码配置 Nginx 的访问权限
Nginx 支持基于 HTTP Basic Authentication 协议的认证。该协议是一种 HTTP 性质的认证办法,需要识别用户名和密码。认证成功的客户端才拥有访问 Nginx 服务器的权限。该功能由 HTTP 标准模块 ngx_http_auth_basic_module 支持,这里涉及两个指令。
auth_basic 指令,用于开启或关闭该认证功能,语法结构为:
auth_basic_user_file 指令,用于设置包含用户名和密码信息的文件路径,语法结构为:
密码文件支持明文或密码加密后的文件。明文的格式如下:
加密密码可以使用
crypt()
函数进行密码加密的格式,在 Linux 平台上可以使用 htpassword 命令生成。使用 htpassword 命令的一个示例为:运行后输入密码即可。
Nginx 服务器架构初探
Nginx 服务器的 Web 请求处理机制
一般来说,实现并行处理请求的方式有三种:
服务器每当接收到一个客户端请求时,就由服务器主进程生成一个子进程和该客户端建立连接进行交互,直到连接断开,该子进程就结束。
服务器每当接收到一个客户端请求时,会由服务器主进程派生一个线程出来和该客户端进行交互。
Nginx 服务器如何处理请求
Nginx 结合多进程机制和异步机制对外提供服务。
Nginx 服务器启动后,会产生一个主进程(master process)和多个工作进程(worker process),其中可以在配置文件中指定产生的工作进程数量。Nginx 服务器的所有工作进程都用于接收和处理客户端的请求。这类似于 Apache 使用的改进后的多进程机制,预生成多个工作进程,等待处理客户端请求。
每个工作进程都使用了异步非阻塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求后调用 I/O 进行处理,如果不能立即得到结果,就去处理其他的请求;而客户端在此期间也无需等待响应,可以去处理其他事情;当 I/O 调用返回结果时就会通知此工作进程;该进程得到通知,暂时挂起当前处理的事务,去响应客户端请求。
客户端请求数量增加、网络负载繁重时,Nginx 服务器使用多进程机制能够保证不增长对系统资源的压力;同时使用异步非阻塞方式避免了工作进程在 I/O 调用上的阻塞延迟,保证了不降低对请求的处理能力。
Nginx 服务器的事件处理机制
I/O 调用是如何把自己的状态通知到工作进程的呢?
一般解决这个问题的方案有两种:
显然,前者不断地检查在时间和资源上会导致不小的开销,最理想的解决方案是第二种。
select/poll/epoll/kqueue 等事件驱动模型就是用来支持第二种解决方案的。它们提供了一种机制,让进程可以同时处理多个并发请求,不用关心 I/O 调用的具体状态。I/O 调用完全由事件驱动模型来管理,事件准备好后就通知工作进程事件已经就绪。
Nginx 服务器的事件驱动模型
事件驱动模型概述
事件驱动模型一般由事件收集器、事件发送器和事件处理器三个基本单元组成。
Nginx 中的事件驱动模型
“目标对象”中的“事件处理器”可以有以下几种实现办法:
以上三种处理方式,各自优缺点如下:
事件驱动处理库又被称为多路 I/O 复用方法。
Nginx 服务器针对不同的 Linux 或 Unix 衍生平台提供了多种事件驱动模型的处理,尽量发挥系统平台本身的优势,最大程度地提供处理客户端请求事件的能力。在实际工作中,我们需要根据具体情况和应用场景选择使用不同的事件驱动模型,以保证 Nginx 服务器的高效运行。
设计架构预览
Nginx 服务器架构
Nginx 服务器启动后,产生一个主进程(master process),主进程执行一系列工作后生成一个或多个工作进程(worker process)。主进程主要进行 Nginx 配置文件解析、数据结构初始化、模块配置和注册、信号处理、网络监听生成、工作进程生成和管理等工作;工作进程主要进行进程初始化、模块调用和请求处理等工作,是 Nginx 服务器提供服务的主体。
在客户端请求动态站点的过程中,Nginx 服务器还涉及和后端服务器的通信。Nginx 服务器将接收到的 Web 请求通过代理转发到后端服务器,由后端服务器进行数据处理和页面组织,然后将结果返回。
另外,Nginx 服务器为了提高对请求的响应效率,进一步降低网络压力,采用了缓存机制,将历史响应数据缓存到本地。在每次 Nginx 服务器启动后的一段时间内,会启动专门的进程对本地缓存的内容重建索引,保证对缓存文件的快速访问。
Nginx 服务器架构示意图
Nginx 服务器的进程
到目前为止,我们一共提到 Nginx 服务器的三大类进程:主进程、由主进程生成的工作进程和刚提到的用于为缓存文件建立索引的进程。
主进程(Master Process)
Nginx 服务器启动时运行的主要进程。它的主要功能是与外界通信和内部对其他进程进行管理,具体来说有以下几点:
工作进程(Worker Process)
由主进程生成,生成数量由 Nginx 配置文件指定,正常情况下会存在于主进程的整个生命周期。该进程的主要工作有以下几项:
工作进程是 Nginx 服务器提供 Web 服务、处理客户端请求的主要进程,完成了 Nginx 服务器的主体工作。因此,我们应该重点监视工作进程的运行状态,保证 Nginx 服务器能向外提供稳定的 Web 服务。
缓存索引重建及管理进程(Cache Loader & Cache Manager)
上图的 Cache 模块,主要由缓存索引重建(Cache Loader)和缓存索引管理(Cache Manager)两类进程来完成工作。缓存索引重建进程是在 Nginx 服务启动一段时间之后(默认是 1 分钟)由主进程生成,在缓存元数据重建完成后就自动退出;缓存索引管理进程一般存在于主进程的整个生命周期,负责对缓存索引进行管理。
这两个进程维护的内存索引元数据库,为工作进程对缓存数据的快速查询提供了便利。
进程交互
Nginx 服务器在使用 Master-Worker 模型时,会涉及主进程与工作进程(Master-Worker)之间的交互和工作进程(Worker-Worker)之间的交互。这两类交互都依赖于管道(channel)机制,交互的准备工作都在工作进程生成时完成的。
工作进程是由主进程生成的。Nginx 服务器启动以后,主进程根据配置文件生成指定数量的工作进程,然后建立一张全局的工作进程表,用于存放当前未退出的所有工作进程。
在主进程生成工作进程后,会将新生成的工作进程加入到工作进程表中,然后建立一个单向管道并将其传递给该工作进程。该管道与普通的管道不同,它是由主进程指向工作进程的单向管道,包含了主进程向工作进程发出的指令、工作进程 ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号进制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送指令。每个工作进程都有能力捕获管道中可读的事件,当管道中有可读事件时,工作进程从管道读取并解析指令,然后采取相应的处理。这样就完成了 Master-Worker 的交互。
工作进程之间是相互隔离的,因此一个进程想要知道另一个进程的信息,只能通过主进程来设置。
为了达到工作进程之间交互的目的,主进程在生成工作进程后,在工作进程表中进行遍历,将该新进程的 ID 以及针对该进程建立的管道句柄传递给工作进程表中的其他进程,为工作进程之间的交互做准备。每个工作进程会从管道中捕获可读事件,然后根据指令采取相应的处理。
当工作进程 W1 需要向 W2 发送指令时,首先在主进程给它的“其他工作进程信息”中找到 W2 的进程 ID,然后将指令写入指向 W2 的通道。工作进程 W2 捕获到管道中的事件后,解析指令并采取相应的处理。这样就完成了 Worker-Worker 交互。
Nginx 服务器的高级配置
上文已记录部分常用配置,其余配置暂忽略。
Nginx 服务器的 Gzip 压缩
相关指令可在 http 块、server 块或者 location 块中配置。
由 ngx_http_gzip_module 模块处理的 9 个指令
ngx_http_gzip_module 模块主要负责 Gzip 功能的开启和设置,对响应数据进行在线实时压缩。该功能模块包含以下主要指令。
该指令用于开启或者关闭 Gzip 功能,语法结构为:
默认设置为
off
。该指令用于设置 Gzip 压缩文件使用缓存空间的大小,语法结构为:
根据该配置项,Nginx 服务器在对响应数据进行 Gzip 压缩时需向系统申请 number * size 大小的空间用于存储压缩数据。从 Nginx 0.7.28 开始,默认情况下 number * size 的值为 128,其中 size 的值取系统内存页一页的大小,为 4KB 或者 8KB,即:
该指令用于设定 Gzip 压缩程度,1-9 级。级别 1 表示压缩程度最低,压缩效率最高,9 反之。其语法结构为:
默认设置为 1。
针对不同种类客户端发起的请求,可以选择性地开启和关闭 Gzip 功能。其语法结构为:
示例:
表示来自 User-Agent 字符串中包含 MSIE4 - 6 的请求,Nginx 都不进行 Gzip 压缩。
该指令用于设置开启 Gzip 功能的最低 HTTP 协议版本。其语法结构为:
默认设置为 1.1,即只有客户端使用 1.1 及以上版本的 HTTP 协议时,才使用 Gzip 功能。
Gzip 压缩功能对大数据的压缩效果明显,但是如果压缩很小的数据,可能会出现越压缩数据量越大的问题(许多压缩算法都有这样的情况发生),因此应该根据数据的大小,选择性地开启或者关闭 Gzip 功能。其语法结构为:
该指令在使用 Nginx 服务器的反向代理功能时有效,前提是在后端服务器返回的响应头部中,Requests 部分包含用于通知代理服务器的 Via 域。它主要用于设置 Nginx 服务器是否对后端服务器返回的结果进行 Gzip 压缩。该指令的语法结构为:
Nginx 服务器可根据响应的 MIME 类型选择性地开启 Gzip 压缩功能。其语法结构为:
mime-type 变量的默认值为
text/html
。值*
表示对所有 MIME 类型的数据进行 Gzip 压缩。该指令用于设置在使用 Gzip 功能时是否发送带有
Vary: Accept-Encoding
域的响应头部,该域的主要功能是告诉接收方:发送的数据经过了压缩处理。开启后的效果是在响应头部添加Accept-Encoding: gzip
。其语法结构为:默认设置为 off。事实上,我们可通过 Nginx 配置的 add_header 指令强制 Nginx 服务器在响应头部添加
Vary: Accept-Encoding
域,以达到同样的效果:add_header Vary Accept-Encoding gzip;
由 ngx_http_gzip_static_module 模块处理的指令
ngx_http_gzip_static_module 模块主要负责搜索和发送经过 Gzip 功能预压缩的数据。这些数据以
.gz
后缀名存储在服务器上。如果客户端请求的数据在之前已被压缩,且客户端支持 Gzip 压缩,就直接返回压缩后的数据。该模块与 ngx_http_gzip_module 模块的不同之处主要在于,该模块使用的是静态压缩,在 HTTP 响应头部包含 Content-Length 域来指明报文体的长度,用于服务器可缺点响应数据长度的情况;而后者默认使用 Chunked 编码的动态压缩,其主要适用于服务器无法确定响应数据长度的情况,比如大文件下载的情形,这时需要实时生成数据长度。
gzip_static 指令,用于开启和关闭该模块的功能,其语法结构:
由 ngx_http_gunzip_module 模块处理的 2 个指令
Nginx 服务器支持对响应数据进行 Gzip 压缩,这对客户端来说,需要有能力解压和处理 Gzip 压缩数据,但如果客户端本身不支持该功能,就需要 Nginx 服务器在向其发送数据之前先将该数据解压。压缩数据可能来自后端服务器压缩产生或 Nginx 服务器预压缩产生。ngx_http_gunzip_module 模块便是用来针对不支持 Gzip 压缩数据处理的客户端。
该指令用于开启或者关闭该模块的功能,其语法结构为:
默认设置为 off。当功能开启时,如果客户端不支持 Gzip 处理,Nginx 服务器将返回解压后的数据;如果客户端支持 Gzip 处理,Nginx 服务器忽略该指令的设置,返回压缩数据。
当客户端不支持 Gzip 数据处理时,使用该模块可以解决数据解析的问题,同时保证 Nginx 服务器与后端服务器传输数据或本身存储数据时仍然使用压缩数据,从而减少服务器之间的数据传输量,降低本地存储空间和缓存的使用率。
用于设置 Nginx 服务器解压 Gzip 文件使用缓存空间的大小,语法结构为:
根据该配置项,Nginx 服务器在对 Gzip 数据进行解压时需向系统申请 number * size 大小的空间。默认情况下 number * size 的值为 128,其中 size 的值取系统内存页一页的大小,为 4KB 或者 8KB,即:
Gzip 压缩功能的使用
Nginx 服务器的 Rewrite 功能
Rewrite 功能是大多数 Web 服务器支持的一项功能,其在提供重定向服务时起到主要作用。
5 个 Nginx 后端服务器组的配置指令
Nginx 服务器支持设置一组服务器作为后端服务器,在学习 Nginx 服务器的反向代理、负载均衡等重要功能时会经常涉及后端服务器。
服务器组的指令由标准 HTTP 模块 ngx_http_upstream_module 进行解析和处理。
该指令是设置后端服务器组的主要指令,其他指令都在该指令中进行配置。其语法结构:
name 是给后端服务器组起的名字。花括号中列出后端服务器组中包含的服务器,其中可以使用下面介绍到的指令。
默认情况下,某个服务器组接收到请求以后,按照轮叫调度(Round-Robin,RR)策略顺序选择组内服务器处理请求,如果一个服务器在处理请求的过程中出现错误,请求会被依次交给组内下一个服务器进行处理,以此类推,直到返回正常响应。当所有组内服务器出错,则返回最后一个服务器的处理结果。当然,我们可以根据各个服务器处理能力或者资源配置情况的不同,给各个服务器配置不同的权重,让能力强的服务器多处理请求,能力弱的少处理。配置权重的变量包含在 server 指令中。
该指令用于设置组内的服务器,其语法结构为:
unix:
为前缀的 Unix Domain Socket(用于进程间通信)。示例:
在该示例中,我们设置了一个名为 backend 的服务器组,组内包含三台服务器,分别是基于域名的 backend1.example.com、基于 IP 地址的 127.0.0.1:8080 和用于进程间通信的 Unix Domain Socket。backend1.example.com 的权重设置为 5,为组内最大,优先接收和处理请求;对本地服务器 127.0.0.1:8080 的状态检查设置为:如果在 30s 内产生 3 次请求失败,则该服务器在之后 30s 内被认为是无效(down)状态。
该指令用于实现会话保持功能,将某个客户端的多次请求定向到组内同一台服务器上,保证客户端与服务器之间建立稳定的会话。只有当该服务器处于无效(down)状态时,客户端请求才会被下一个服务器接收和处理。其语法结构为:
ip_hash;
好处:
注意:
示例:
该示例中配置了一个名为 backend 的服务器组,包含两台后端服务器 myback1.proxy.com 和 myback2.proxy.com。在添加 ip_hash 指令后,我们使用同一个客户端向 Nginx 服务器发送请求。我们会看到一直是由同一台服务器响应。如果注释 ip_hash 指令后进行相同的操作,请求会由两台服务器轮流响应。
激活到 upstream 服务器的连接缓存。
connections 参数:用于设置每工作进程在缓存中保持的到 upstream 服务器的空闲 keepalive 连接的最大数量。当超过该数量时,最近使用最少的连接将会被关闭。
特别提醒:keepalive 指令不会限制 Nginx 的一个工作进程到 upstream 服务器的连接总数。connections 参数应该设置为一个足够小的数值来让 upstream 服务器来处理新进来的连接。
该指令在功能上实现了最少连接负载均衡算法。首选遍历服务器组内的服务器,比较每个后端的
conns/weight
,选取该值最小的服务器。如果有多个服务器的conns/weight
值同为最小,那么对它们采用加权轮询算法。least_conn;
Rewrite 功能的配置
“地址重写”与“地址转发”
地址重写与地址转发是两个不同的概念。
地址重写:是为了实现地址的标准化,比如我们可以在地址栏中中输入 www.baidu.com. 我们也可以输入 www.baidu.cn. 最后都会被重写到 www.baidu.com 上。浏览器的地址栏也会显示 www.baidu.com。
地址转发:“转发”是指在网络数据传输过程中数据分组到达路由器或桥接器后,该设备通过检查分组地址并将数据转发到最近局域网的过程。后来该概念被用在 Web 上,出现了“地址转发”的说法,是指将一个域名指到另一个已有站点的过程。
因此地址重写和地址转发有以下不同点:
if 指令
该指令可在 server 块或 location 块中使用。其语法结构为:
condition 为判断条件,它支持以下几种设置方法:
false
,其余情况认为是true
:~
判断变量是否与正则表达式(大小写敏感)匹配,~*
是大小写不敏感。正则表达式可包含捕获(capture),可在后续通过$1...$9
变量引用这些捕获。反运算符!~
和!~*
均可用。若正则表达式包含}
或;
符号,则整个表达式应使用单引号或双引号包围。-f
和!-f
检查文件是否存在。-d
和!-d
检查目录是否存在。-e
和!-e
检查文件、目录或符号链接(symbolic link)是否存在。-x
和!-x
判断文件是否为可执行文件。(笔者注:Linux 中文件x
属性表示文件可执行)break 指令
该指令用于中断当前相同作用域的其他 Nginx 配置。与该指令处于同一作用域的 Nginx 配置中,位于它前面的指令配置生效,位于它后面的指令配置无效。Nginx 服务器在根据配置处理请求的过程中,遇到该指令会回到上一层作用域,然后继续向下读取配置。
该指令可以在 server 块、location 块和 if 块中使用。
return 指令
该指令用于完成对请求的处理,直接向客户端返回响应状态码。处于该指令后的所有 Nginx 配置都是无效的。其语法结构为:
从 0.8.42 起,可为 301、302、303、307 和 308 状态码指定 URL,为其他状态码返回文本 text。URL 和 text 均支持变量。
该指令可以在 server 块、location 块和 if 块中使用。
rewrite 指令
该指令可用在 server、location、if 块。
若指定的正则表达式匹配请求 URI 部分(即不包含 HTTP 协议和域名,如 www.baidu.com/abc?arg=1 中的 /abc),则 URI 部分会被替换为
replacement
字符串。rewrite 指令会按配置文件的出现次序依次执行(即可指定多个 rewrite 指令)。可通过使用 flag 中止后续 rewrite 指令的执行。若replacement
字符串以http://
、https://
或$scheme
开头,处理就会到此为止,并将重定向给客户端。可选项 flag 可以为以下之一:
replacement
不是以http://
、https://
或$scheme
开头,但又要实现同样的效果,则可以使用该 flag。rewrite_log 指令
该指令用于是否开启 URL 重写日志的输出功能,其语法结构为:
默认设置为 off。若开启,URL 重写的相关日志将以 notice 级别输出到 error_log 指令配置的日志文件中。
set 指令
该指令用于设置一个新变量,其语法结构为:
$
开头,且不能与 Nginx 服务器预设的全局变量同名。uninitialized_variable_warn 指令
该指令用于配置使用未初始化的变量时,是否记录警告日志,其语法结构为:
默认设置为开启
on
。Rewrite 常用全局变量
忽略。
Rewrite 的使用
通过 Rewrite 功能可以实现一级和多级域名跳转。在 server 块中配置 Rewrite 功能即可。
镜像网站是指将一个完全相同的网站分别放置到几个服务器上,并分别使用独立的 URL,其中一个服务器上的网站叫主站,其他为镜像网站。镜像网站和主站没有太大区别,或者可算是主站的后备。可以通过镜像网站提高网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载,可以解决网络带宽限制、封锁等。
使用 Nginx 服务器的 Rewrite 功能可以轻松地实现域名镜像的跳转。在 server 块中配置 Rewrite 功能,将不同的镜像 URL 重写到指定的 URL 即可。
若不想将整个网站做镜像,只想为某一个子目录下的资源做镜像,我们可以在 location 块中配置 Rewrite 功能,原理和上面一样。
当一个网站包含多个板块时,可以为其中某些板块设置独立域名。其原理和设置某个子目录镜像的原理相同。
如果网站设定了默认资源文件,那么当客户端使用 URL 访问时可以不加具体的资源文件名称。比如,在访问
www.myweb.name
站点时,应该在浏览器地址中输入http://www.myweb.name/index.htm
这样的 URL,如果我们设置了www.myweb.name
站点的首页为index.htm
,那么直接在地址栏中输入http://www.myweb.name
即可访问成功,/index.htm
可以忽略不写。但如果请求的资源文件在二级目录下,这样的习惯可以会造成无法正常访问资源。比如,在访问
http://www.myweb.name/bbs/index.htm
时,如果将 URL 省略为http://www.myweb.name/bbs/
可以进行正常访问,但是如果将 URL 写为http://www.myweb.name/bbs
,将末尾的斜杠/
也省略,那么就无法访问。我们可以使用 Rewrite 功能为末尾没有斜杠“/”的 URL 自动添加一个斜杠/
:使用 if 指令判断请求的“/bbs”是目录后,匹配接收到的 URI,并将各部分的值截取出来重新组装,并在末尾添加斜杠“/”。
目录合并用于增强 SEO 的一个方法,它将多级目录下的资源文件转化为看上去是对目录级数很少的资源访问。
比如将
/server/12/34/56/78/9.htm
目录变为/server/12-34-56-78-9.htm
的 URL。通过检测 Referer 域的值是否是自身网站的 URL,并采取措施,从而实现防盗链。但由于 Referer 域的值可被更改,因此该方法并不是完美的。
Nginx 配置中有一个指令 valid_referers,它会根据指定值来判断 Referer 值是否符合要求,并为 Nginx 变量(Embedded Variables)
$invalid_referer
赋值。如果 Referer 不符合 valid_referers 指令配置的值,$invalid_referer
变量会被赋值为"1"
,反之为空字符串。valid_referers 指令的语法结构为:*
。检测期间,Referer 值的端口号会被忽略。~
。应当注意:正则表达式会与“http://”或“https://”后的字符串进行匹配。案例:
有了 valid_referers 指令和 $invalid_referer 变量,就能通过 Rewrite 功能实现防盗链。有两种方案:1. 根据请求资源的类型;2. 根据请求目录。
根据文件类型实现防盗链:
根据请求目录实现防盗链(原理一致,只是改变 location 块的 uri。):
Nginx 服务器的代理服务
正向代理和反向代理的概念
代理(Proxy)服务,通常也称为正向代理服务。局域网内的机器借助代理服务器访问局域网外的网站,这主要是为了增强局域网内部网络的安全性,使得网外的威胁因素不容易影响到网内,这里的代理服务器起到了一部分防火墙的功能。同时,利用代理服务器可以对局域网对外网的访问进行必要的监控和管理。正向代理服务器不支持外部对内部网络的访问请求。
正向代理服务器示意图
与正向代理服务相反,如果局域网向 Internet 提供资源,让 Internet 上的其他用户可以访问局域网内的资源,也可以设置使用一个代理服务器,它提供的服务就叫做反向代理(Reverse Proxy)服务。
反向代理服务器示意图
正向代理服务器让局域网客户机接入外网以访问外网资源,反向代理服务器让外网的客户端接入局域网中的站点以访问站点中的资源。理解这两个概念的关键是明白我们当前的角色和目的是什么,在正向代理服务器中,我们的角色是客户端,目的是要访问外网的资源;在反向代理服务器中,我们的角色是站点,目的是把站点的资源发布出去让其他客户端能访问。
Nginx 服务器的正向代理服务
3 个 Nginx 服务器正向代理服务的配置指令
该指令用于指定 DNS 服务器的 IP 地址。DNS 服务器的主要工作是进行域名解析,将域名映射为对应的 IP 地址。其语法结构为:
该指令用于设置 DNS 服务器域名解析的超时时间,语法结构为:
该指令用于设置代理服务器的协议和地址。其语法结构为:
在代理服务器配置中,该指令的设置是相对固定的:
其中,代理服务器协议设置为 HTTP,$http_host 和 $request_uri 两个变量是获取主机和 URI(含参数) 的变量。
Nginx 服务器正向代理服务的使用
设置 DNS 服务器地址为 8.8.8.8,使用默认的 53 端口,代理服务器的监听端口设置为 82 端口,Nginx 服务器接收到的所有请求都由第 5 行的 location 块进行处理。
需要注意:设置 Nginx 的代理服务器,一般是配置到一个 server 块中。该 server 块中不要出现 server_name 指令,即不要设置虚拟主机的名称或 IP。而 resolver 指令是必须的。若无该指令,Nginx 服务器无法处理接收到的域名。
Nginx 服务器的反向代理服务
21 个基本的反向代理设置指令
该指令用于设置被代理服务器的地址。支持主机名称、IP 地址加端口号、服务器组名称。
该指令的值可以包含变量。在这种情况下,如果将地址指定为域名,首先在服务器组中搜索。在找不到的情况下使用 resolver 指令解析该域名。
对于服务器组,若组内的各个服务器都指明了传输协议
http://
,那么在 proxy_pass 指令就无要指明。反之则反之。请求 URI 按如下方式传递到被被代理服务器:
location /name/ { proxy_pass http://127.0.0.1/remote/; }
客户端请求
http://192.168.1.10/name/path/index.html
会被代理到http://127.0.0.1/remote/path/index.html
。即 location URI:/name/
被替换为 proxy_pass 指定的 URI:/remote/
location /some/path { proxy_pass http://127.0.0.1; }
客户端请求
http://192.168.1.10/some/path/index.html
会被代理到http://127.0.0.1/some/path/index.html
。URI 保持不变。在某些情况下,请求 URI 无法确定替换后的值:
对于正则表达式和命名 location,proxy_pass 不应该带有 URI。
当 URI 被 location 内 rewrite 指令更改时,传递给被代理服务器的 URI 是更改后的,且行为与 location URI 一致(即上述两种情况)。
在该案例中,proxy_pass 无 URI,所以 rewrite 后的 URI 会原样传递给被代理服务器。
当 proxy_pass 使用变量:
在该案例中,proxy_pass 指定的 URI 会传递给被代理服务器,即替换掉原始请求的 URI。
该指令用于设置 Nginx 服务器在发送 HTTP 响应时,需要隐藏的一些头部域信息。其语法结构为:
默认情况下,Nginx 服务器在发送响应报文时,报文头不包含“Date”、“Server”、“X-Accel”等来自被代理服务器的头部域信息。该指令可以设置这些头部域信息可以被发送,其语法结构为:
该指令用于配置是否将客户端请求的请求体发送给代理服务器,其语法结构为:
默认设置为 on。
该指令用于配置是否将客户端请求的请求头发送给代理服务器,其语法结构为:
默认设置为 on。
该指令可以更改 Nginx 服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给被代理的服务器。其语法结构为:
默认设置为:
该指令可以更改 Nginx 服务器接收到的客户端请求的请求体信息,然后将新的请求体发送给被代理的服务器。其语法结构为:
在配置了多个基于名称或 IP 的主机的情况下,可指定主机。
proxy_connect_timeout 指令
proxy_read_timeout 指令
proxy_send_timeout 指令
proxy_http_version 指令
proxy_method 指令
该指令用于设置 Nginx 服务器请求被代理服务器时使用的请求方法。设置该指令后,会覆盖客户端的请求方法。
proxy_ignore_client_abort 指令
proxy_ignore_headers 指令
proxy_redirect 指令
proxy_intercept_errors 指令
开始状态下,如果被代理服务器返回的 HTTP 状态码为 300 或大于 300,则 Nginx 服务器使用自己定义的错误页(使用 error_page 指令);关闭状态下,Nginx 服务器直接将被代理服务器返回的 HTTP 状态码返回给客户端。其语法结构为:
默认值为 off。
proxy_headers_hash_max_size 指令
proxy_headers_hash_bucket_size 指令
proxy_next_upstream 指令
在配置 Nginx 服务器反向代理功能时,如果使用 upstream 指令配置了一组服务器作为被代理服务器,服务器组中各服务器的访问规则遵循 upstream 指令配置的轮询规则,同时可以使用该指令配置在发生哪些异常情况时,将请求顺次交由组内下一个服务器处理。该指令的语法结构为:
该指令用于配置是否使用基于 SSL 安全协议的会话连接(https://)被代理的服务器,其语法结构为:
默认设置为 on。
Proxy Buffer 的配置的 7 个指令
Proxy Buffer 启用后,Nginx 服务器会异步地将被代理服务器的响应数据传递给客户端。
Nginx 服务器首先尽可能地从被代理服务器接收响应数据,并放置在 Proxy Buffer 中,Buffer 大小由 proxy_buffer_size 指令和 proxy_buffers 指令决定。在接收过程中,如果发现 Buffer 没有足够空间接收一次响应的数据,Nginx 服务器会将部分接收到的数据临时存放在磁盘的临时文件中,磁盘上的临时文件路径可通过 proxy_temp_path 设置,临时文件的大小由 proxy_max_temp_file_size 和 proxy_temp_file_write_size 决定。一次响应数据被接收完成或 Buffer 已经装满后,Nginx 服务器开始向客户端传输数据。
每个 Proxy Buffer 装满数据后,在从开始向客户端发送一直到 Proxy Buffer 中的数据全部传输给客户端的过程中,它都处于 BUSY 状态,期间对它进行的其他操作都会失败。同时处于 BUSY 状态的 Proxy Buffer 总大小由 proxy_busy_buffers_size 限制。
Proxy Cache 的配置的 12 个指令
在 Nginx 服务器中,Proxy Buffer 和 Proxy Cache 都与代理服务相关,它们主要用来提高客户端与被代理服务器之间的交互效率。Proxy Buffer 实现了被代理服务器响应数据的异步传输,Proxy Cache 实现了 Nginx 服务器对客户端请求的快速响应。Nginx 服务器在接收到被代理服务器的响应数据之后,一方面通过 Proxy Buffer 机制将数据传递给客户端,另一方面根据 Proxy Cache 的配置将这些数据缓存到本地磁盘。当客户端下次访问相同数据时,Nginx 服务器会直接从硬盘检索到相应的数据返回给用户。
Proxy Cache 机制依赖于 Proxy Buffer 机制,只有在 Proxy Buffer 机制开启的情况下 Proxy Cache 的配置才发挥作用。
Nginx 服务器还提供另一种将被代理服务器数据缓存到本地的方法 Proxy Store,与 Proxy Cache 的区别是,它对来自被代理服务器的响应数据,尤其是静态数据只进行简单的缓存,不支持缓存过期更新、内存索引建立等功能,但支持设置用户或用户组对缓存数据的访问权限。
Nginx 服务器的负载均衡
Nginx 反向代理服务的一个重要用途是实现负载均衡。
负载均衡主要通过专门的硬件设备实现或通过软件算法实现。通过硬件设备实现的负载均衡效果好、效率高、性能稳定,但成本较高。通过软件实现的负载均衡主要依赖于均衡算法的选择和程序的健壮性。均衡算法常见有两类:静态负载均衡算法和动态负载均衡算法。
静态算法实现比较简单,在一般网络环境下也能达到比较好的效果,主要有:
动态负载在较为复杂的网络环境中适应性更强,效果更好,主要有:
以下 5 个配置案例展示了 Nginx 服务器实现不同情况下负载均衡的基本方法。由于 Nginx 服务器的功能在结构上是增量式的,我们可以在这些配置的基础上继续添加更多功能,比如 Web 缓存、Gzip、身份认证、权限管理等。同时在使用 upstream 指令配置服务器组时,可以充分发挥各个指令的功能,配置出满足需求,高效稳定的 Nginx 服务器。
配置实例一:对所有请求实现一般轮询规则的负载均衡
在以下案例片段中,backend 服务器组中所有服务器的优先级全部配置为默认的 weight=1,这样它们会按照一般轮询策略依次接收请求任务。该配置是一个最简单的实现 Nginx 服务器负载均衡的配置。所有访问 www.myweb.com 的请求都会在 backend 服务器组中实现负载均衡。
配置实例二:对所有请求实现加权轮询规则的负载均衡
配置实例三:对特定资源实现负载均衡
在该实例片段中,我们设置了两组被代理的服务器组。其中,名为 “videobackend” 的一组用于对请求 video 资源的客户端请求进行负载均衡,另一组名为 filebackend 的用于对请求 file 资源的客户端请求进行负载均衡。通过对 location 块 uri 的不同配置,我们就很轻易地实现了对特定资源的负载均衡。所有对
http://www.myweb.name/video/*
的请求都会在 videobackend 服务器组中获得均衡效果,所有对http://www.myweb.name/file/*
的请求都会在 filebackend 服务器组中获得均衡效果。在该实例中展示的是实现一般负载均衡的配置,对于加权负载均衡的配置可以参考“配置实例二”。在 location /file/ {...} 块中,我们将客户端的真实信息分别填充到了请求头中的 “Host”、“X-Real-IP” 和 “X-Forwarded-For” 域,这样后端服务器组收到的请求中保留了客户端的真实信息,而不是 Nginx 服务器的信息。实例代码如下:
配置实例四:对不同域名实现负载均衡
在该实例片段中,我们设置了两个虚拟服务器和两组后端被代理的服务器组,分别用来接收不同域名的请求,并对这些请求进行负载均衡处理。如果客户端请求域名为 “home.myweb.name”,则由服务器 server 1 接收并转向 homebackend 服务器组进行负载均衡处理;如果客户端请求域名为 “bbs.myweb.name”,则由服务器 server 2 接收并转向 bbsbackend 服务器组进行负载均衡处理。这样就实现了对不同域名的负载均衡。
需要注意两组后端服务器组中有一台服务器 server 192.168.1.4:80 是公用的。在该服务器上需要部署两个域名下的所有资源才能保证客户端请求不会出现问题。实现代码如下:
实现实例五:实现带有 URL 重写的负载均衡
首先,我们来看具体的源码实现,这是在实例一的基础上做的修改:
该实例片段与“配置实例一”相比,增加了对 URI 包含 "/file/" 的 URL 重写功能。例如客户端的请求 URL 为
http://www.myweb.name/file/download/media/1.mp3
时,该虚拟服务器首先使用 location /file/ {...} 块将该 URL 进行重写为http://www.myweb.name/file/download/mp3/1.mp3
时,然后新的 URL 再由 location / {...} 块转发到后端的 backend 服务器组中实现负载均衡。在该配置方案中,一定要掌握清楚 rewrite 指令中 last 标记和 break 标记的区别,才能达到预期效果。Nginx 服务器的缓存机制
Nginx 服务器的邮件服务
忽略。
Nginx 源码结构
解压 Linux 版本的 Nginx 压缩包后,有一个 src 目录,其中存放了 Nginx 软件的所有源代码。
$ cd src $ ls core event http mail misc os
ngx_cpp_test_module.cpp
文件实现的功能是测试程序中引用的头文件是否与 C++ 兼容。ngx_google_perftools_module.c
文件是用来支持 Google PerfTools 的使用。Google PerfTools 包含四个工具,用于优化内存分配的效率和速度,帮助在高并发的情况下控制内存的使用,对 Nginx 服务器的运行做出进一步优化。Nginx 基本数据结构
忽略。
Nginx 的启动初始化
Nginx 初始化过程的主要工作
Nginx 服务器程序完成初始化工作后,就会开始启动进程的工作。Nginx 服务器程序的进程模型分为 Single 和 Master 两种,其中 Single 模型是以单进程方式工作的,一般不会在实际应用中使用;Master 模型是以 Master-Worker 多进程方式进行工作的,它是实际应用中使用的主要模式。
启动多进程的过程和执行一般的多进程程序是一样的,主要使用 fork() 函数产生子进程。主进程通过一个 for 循环来接收和处理外部信息,对 Nginx 服务器的启停进行控制;产生的子进程就是工作进程,每个工作进程执行一个 for 循环来实现 Nginx 服务器对事件的接收和处理,以提供 Nginx 服务器的各项功能。
Master 模型下多进程的启动过程
Nginx 的时间管理
忽略。
Nginx 的内存管理
忽略。
Nginx 的工作进程
忽略。
Nginx 的模块编程
忽略。
Nginx 在动态网站建设中的应用案例
忽略。
The text was updated successfully, but these errors were encountered: