Nginx系列四: Nginx的配置指令和handler模块概述

Nginx系列一:概念和配置
Nginx系列二: Nginx 的数据结构
Nginx系列三: Nginx 高级数据结构
Nginx系列四: Nginx的配置指令和handler模块概述
Nginx系列五: handler 模块

文章目录

    • 1. 指令参数
    • 2. 指令上下文
    • 3. 模块描述

Nginx系列四: Nginx的配置指令和handler模块概述_第1张图片

nginx 的配置系统由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,全部位于 nginx 安装目录下的 conf 目录下 。配置文件中以#开始的行,或者是前面有若干空格或者 TAB,然后再跟#的行,都被认为是注释,也就是只对编辑查看文件的用户有意义,程序在读取这些注释行的时候,其实际的内容是被忽略的。由于除主配置文件 nginx.conf 以外的文件都是在某些情况下才使用的,而只有主配置文件是在任何情况下都被使用的。所以在这里我们就以主配置文件为例,来解释 nginx 的配置系统。在 nginx.conf 中,包含若干配置项。每个配置项由配置指令指令参数 2 个部分构成。指令参数也就是配置指令对应的配置值。

配置指令是一个字符串,可以用单引号或者双引号括起来,也可以不括。但是如果配置指令包含空格,一定要引起来。

1. 指令参数

指令的参数使用一个或者多个空格或者 TAB 字符与指令分开。指令的参数有一个或者多个TOKEN 串组成。 TOKEN 串之间由空格或者 TAB 键分隔。TOKEN 串分为简单字符串或者是复合配置块。复合配置块即是由大括号括起来的一堆内容。一个复合配置块中可能包含若干其他的配置指令。如果一个配置指令的参数全部由简单字符串构成,也就是不包含复合配置块,那么我们就说这个配置指令是一个简单配置项,否则称之为复杂配置项。例如下面这个是一个简单配置项:

error_page 500 502 503 504 /50x.html;

复杂配置块:

location / {
	root /home/nginx/build/html;
	index index.html index.htm;
}

2. 指令上下文

nginx.conf 中的配置信息,根据其逻辑上的意义,对它们进行了分类,也就是分成了多个作用域,或者称之为配置指令上下文。不同的作用域含有一个或者多个配置项。当前 nginx 支持的几个指令上下文:

指令上下文 描述
main nginx 在运行时与具体业务功能(比如 http 服务或者 email 服务代理)无关的一 些参数,比如工作进程数,运行的身份等。
http 与提供 http 服务相关的一些配置参数。例如:是否使用 keepalive 啊,是否使用 gzip 进行压缩等
server http 服务上支持若干虚拟主机。每个虚拟主机一个对应的 server 配置项,配置项 里面包含该虚拟主机相关的配置。在提供 mail 服务的代理时,也可以建立若干 server.每个 server 通过监听的地址来区分。
location http 服务中,某些特定的 URL 对应的一系列配置项
mail 实现 email 相关的 SMTP/IMAP/POP3 代理时,共享的一些配置项(因为可能实现 多个代理,工作在多个监听地址上)。

指令上下文,可能有包含的情况出现。例如:通常 http 上下文和 mail 上下文一定是出现在main 上下文里的。在一个上下文里,可能包含另外一种类型的上下文多次。例如:如果 http服务,支持了多个虚拟主机,那么在 http 上下文里,就会出现多个 server 上下文。我们来看一个示例配置:

user nobody;
worker_processes 1;
error_log logs/error.log info;
events {
	worker_connections 1024;
}
http {
	server {
	listen 80;
	server_name www.linuxidc.com;
	access_log logs/linuxidc.access.log main;
	location / {
		index index.html;
		root /var/www/linuxidc.com/htdocs;
		}
	}
	server {
	listen 80;
	server_name www.Androidj.com;
	access_log logs/androidj.access.log main;
	location / {
		index index.html;
		root /var/www/androidj.com/htdocs;
		}
	}
}
mail {
	auth_http 127.0.0.1:80/auth.php;
	pop3_capabilities "TOP" "USER";
	imap_capabilities "IMAP4rev1" "UIDPLUS";
	server {
		listen 110;
		protocol pop3;
		proxy on;
	}
	server {
		listen 25;
		protocol smtp;
		proxy on;
		smtp_auth login plain;
		xclient off;
	}
}

3. 模块描述

nginx 将各功能模块组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块,进行处理。每个模块实现特定的功能。例如,实现对请求解压缩的模块,实现SSI 的模块,实现与上游服务器进行通讯的模块,实现与 FastCGI 服务进行通讯的模块。有两个模块比较特殊,他们居于 nginx core 和各功能模块的中间。这两个模块就是 http 模块和 mail 模块。这 2 个模块在 nginx core 之上实现了另外一层抽象,处理与 HTTP 协议和 email相关协议(SMTP/POP3/IMAP)有关的事件,并且确保这些事件能被以正确的顺序调用其他的一些功能模块。目前 HTTP 协议是被实现在 http 模块中的,但是有可能将来被剥离到一个单独的模块中,以扩展 nginx 支持 SPDY 协议。

模块的分类

nginx 的模块根据其功能基本上可以分为以下几种类型 :

event module 搭建了独立于操作系统的事件处理机制的框架,及提供了各具体事件的处理。 包括 ngx_events_module, ngx_event_core_module 和 ngx_epoll_module 等。 nginx 具体使用何种事件处理模块,这依赖于具体的操作系统和编译选项。
phase handler 此类型的模块也被直接称为 handler 模块。主要负责处理客户端请求并产生待 响应内容,比如 ngx_http_static_module 模块,负责客户端的静态页面请求处 理并将对应的磁盘文件准备为响应内容输出。
output filter 也称为 filter 模块,主要是负责对输出的内容进行处理,可以对输出进行修改。 例如,可以实现对输出的所有 html 页面增加预定义的 footbar 一类的工作,或 者对输出的图片的 URL 进行替换之类的工作。
upstream upstream 模块实现反向代理的功能,将真正的请求转发到后端服务器上,并从 后端服务器上读取响应,发回客户端。 upstream 模块是一种特殊的 handler, 只不过响应内容不是真正由自己产生的,而是从后端服务器上读取的。
load balancer 负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出 来作为某个请求的转发服务器

Nginx请求处理

nginx 使用一个多进程模型来对外提供服务,其中一个 master 进程,多个 worker 进程。master 进程负责管理 nginx 本身和其他 worker 进程。所有实际上的业务处理逻辑都在 worker进程。 worker 进程中有一个函数,执行无限循环,不断处理收到的来自客户端的请求,并进行处理,直到整个 nginx 服务被停止。 worker 进程中, ngx_worker_process_cycle()函数就是这个无限循环的处理函数。在这个函数中,一个请求的简单处理流程如下:

  1. 操作系统提供的机制(例如 epoll, kqueue 等)产生相关的事件。
  2. 接收和处理这些事件,如是接受到数据,则产生更高层的 request 对象。
  3. 处理 request 的 header 和 body。
  4. 产生响应,并发送回客户端。
  5. 完成 request 的处理。
  6. 重新初始化定时器及其他事件。

为了更好的了解 nginx 中请求处理过程,我们以 HTTP Request 为例,来做一下详细地说明。从 nginx 的内部来看,一个 HTTP Request 的处理过程涉及到以下几个阶段。

  1. 初始化 HTTP Request(读取来自客户端的数据,生成 HTTP Request 对象,该对象含有该请求所有的信息)。
  2. 处理请求头。
  3. 处理请求体。
  4. 如果有的话,调用与此请求(URL 或者 Location)关联的 handler。
  5. 依次调用各 phase handler 进行处理。

在这里,我们需要了解一下 phase handler 这个概念。 phase 字面的意思,就是阶段。所以 phase handlers 也就好理解了,就是包含若干个处理阶段的一些 handler。在每一个阶段,包含有若干个 handler,再处理到某个阶段的时候,依次调用该阶段的 handler 对 HTTP Request进行处理。通常情况下,一个 phase handler 对这个 request 进行处理,并产生一些输出。通常 phase handler 是与定义在配置文件中的某个 location 相关联的。一个 phase handler 通常执行以下几项任务:

  1. 获取 location 配置。
  2. 产生适当的响应。
  3. 发送 response header。
  4. 发送 response body。

当 nginx 读取到一个 HTTP Request 的 header 的时候, nginx 首先查找与这个请求关联的虚拟主机的配置。如果找到了这个虚拟主机的配置,那么通常情况下,这个 HTTP Request 将会经过以下几个阶段的处理(phase handlers):

NGX_HTTP_POST_READ_PHASE          //读取请求内容阶段
NGX_HTTP_SERVER_REWRITE_PHASE     //Server 请求地址重写阶段
NGX_HTTP_FIND_CONFIG_PHASE        //配置查找阶段
NGX_HTTP_REWRITE_PHASE            //Location 请求地址重写阶段
NGX_HTTP_POST_REWRITE_PHASE       // 请求地址重写提交阶段
NGX_HTTP_PREACCESS_PHASE          //访问权限检查准备阶段
NGX_HTTP_ACCESS_PHASE            //访问权限检查阶段
NGX_HTTP_POST_ACCESS_PHASE       //访问权限检查提交阶段
NGX_HTTP_TRY_FILES_PHASE         //配置项 try_files 处理阶段
NGX_HTTP_CONTENT_PHASE           // 内容产生阶段
NGX_HTTP_LOG_PHASE               //日志模块处理阶段

在内容产生阶段,为了给一个 request 产生正确的响应, nginx 必须把这个 request 交给一个合适的 content handler 去处理。如果这个 request 对应的 location 在配置文件中被明确指定了一个 content handler,那么 nginx 就可以通过对 location 的匹配,直接找到这个对应的 handler,并把这个 request 交给这个 content handler 去处理。这样的配置指令包括像,perl, flv, proxy_pass, mp4 等。

如果一个 request 对应的 location 并没有直接有配置的 content handler,那么 nginx 依次尝试:

  1. 如果一个 location 里面有配置 random_index on,那么随机选择一个文件,发送给客户端。
  2. 如果一个 location 里面有配置 index 指令,那么发送 index 指令指明的文件,给客户端。
  3. 如果一个 location 里面有配置 autoindex on,那么就发送请求地址对应的服务端路径下的文件列表给客户端。
  4. 如果这个 request 对应的 location 上有设置 gzip_static on,那么就查找是否有对应的.gz文件存在,有的话,就发送这个给客户端(客户端支持 gzip 的情况下)。
  5. 请求的 URI 如果对应一个静态文件, static module 就发送静态文件的内容到客户端。

内容产生阶段完成以后,生成的输出会被传递到 filter 模块去进行处理。 filter 模块也是与 location 相关的。所有的 fiter 模块都被组织成一条链。输出会依次穿越所有的 filter,直到有一个 filter 模块的返回值表明已经处理完成。这里列举几个常见的 filter 模块,例如:

  1. server-side includes。
  2. XSLT filtering。
  3. 图像缩放之类的。
  4. gzip 压缩。

在所有的 filter 中,有几个 filter 模块需要关注一下。按照调用的顺序依次说明如下:

write: 写输出到客户端,实际上是写到连接对应的 socket 上。
postpone: 这个 filter 是负责 subrequest 的,也就是子请求的。
copy: 将一些需要复制的 buf(文件或者内存)重新复制一份然后交给剩余的 body filter 处理。

你可能感兴趣的:(Nginx,nginx)