1.Nginx架构
Nginx 的代码是由一个核心和一系列的模块组成。
核心主要用于提供 WebServer 的基本功能,以及 Web 和 Mail 反向代理的功能;还用于启用网络协议,创建必要的运行时环境以及确保不同的模块之间平滑地进行交互。不过,大多跟协议相关的功能和应用特有的功能都是由 nginx 的模块实现的。
这些功能模块大致可以分为事件模块、阶段性处理器、输出过滤器、变量处理器、协议、upstream 和负载均衡几个类别,这些共同组成了 nginx 的 http 功能。事件模块主要用于提供 OS 独立的(不同操作系统的事件机制有所不同)事件通知机制如 kqueue 或 epoll 等。协议模块则负责实现 nginx 通过 http、tls/ssl、smtp、pop3 以及 imap 与对应的客户端建立会话。在 Nginx 内部,进程间的通信是通过模块的 pipeline 或 chain 实现的;换句话说,每一个功能或操作都由一个模块来实现。例如:压缩、通过 FastCGI 或 uwsgi 协议与 upstream 服务器通信、以及与 memcached 建立会话等。
2.Nginx进程
首先我们要知道,nginx 是以多进程的方式来工作的,当然 nginx 也是支持多线程的方式的。nginx 启动后,在 unix 系统中会以 daemon 的方式在后台运行,后台进程包含一个 master 进程和多个 worker 进程(你可以理解为工人和管理员)。这里就主要讲解 nginx 的多进程模式。
在这之前我们看看 nginx 处理连接过程:
nginx 不会为每个连接派生进程或线程,而是由 worker 进程通过监听共享套接字接收新请求,并且使用高效的循环来处理数千个连接。Nginx 不使用仲裁器或分发器来分发连接,这个工作由操作系统内核机制完成。监听套接字在启动时就完成初始化,worker 进程通过这些套接字接收、读取请求和输出响应。
接下来就是 master 与 worker 的功能与协作:
2.1 master与worker
master:
当 nginx 在启动后,会有一个 master
进程和多个 worker
进程。master 进程主要用来管理 *worker *进程,master 要做的就是:接收来自外界的信号,向各 worker 进程发送信号,监控 worker 进程的运行状态,当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程。
主要完成如下工作:
- 读取并验证配置信息;
- 创建、绑定及关闭套接字;
- 启动、终止 worker 进程及维护 worker 进程的个数;
- 无须中止服务而重新配置工作;
- 控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本;
- 重新打开日志文件;
- 编译嵌入式 perl 脚本
worker:
对于基本的网络事件,则是放在 worker 进程中来处理了。多个 worker 进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个 worker 进程中处理,一个 worker 进程,不可能处理其它进程的请求(一对一)。然而 nginx 没有专门地仲裁或连接分布的 worker,这项工作是由操作系统内核机制完成的。在启动时,创建一组初始的监听套接字,HTTP 请求和响应之时,worker 连续接收、读取和写入套接字。
2.2 worker 进程主要完成的任务包括
- 接收、传入并处理来自客户端的连接;
- 提供反向代理及过滤功能;
- nginx 任何能完成的其它任务
2.3 nginx 的进程模型,可以由下图来表示
2.4看一看一个完整的请求是怎样通过互相的协作来实现的
既然 worker
进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供 80
端口的 http
服务时,一个连接请求过来,每个进程都有可能处理这个连接。那么问题来了,到底最后怎样处理,是由什么决定的呢?首先,每个 worker
进程都是从 master
进程 fork
过来,在 master
进程里面,先建立好需要 listen
的 socket
(listenfd)之后,然后再 fork
出多个 worker
进程。所有 worker
进程的 listenfd
会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有 worker
进程会在注册 listenfd
读事件前抢 accept_mutex
,抢到互斥锁的那个进程注册 listenfd
读事件,然后在读事件里调用 accept
接受该连接。当一个 worker
进程在 accept
这个连接之后,就开始读取请求、解析请求、处理请求。产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到:一个请求,完全由 worker
进程来处理,而且只在一个 worker
进程中处理。
也许你还有个疑问,那就是 nginx 采用多 worker 的方式来处理请求,每个 worker 里面只有一个主线程,那能够处理的并发数很有限啊,多少个 worker 就能处理多少个并发,何来高并发呢?然而,这就是 nginx 的高明之处,nginx 采用了异步非阻塞的方式来处理请求,也就是说,nginx 是可以同时处理成千上万个请求的。
这里补充一下异步非阻塞
异步的概念是和同步相对的,也就是不同事件之间不是同时发生的。非阻塞的概念是和阻塞对应的,阻塞是事件按顺序执行,每一事件都要等待上一事件的完成,而非阻塞是如果事件没有准备好,这个事件可以直接返回,过一段时间再进行处理询问,这期间可以做其他事情。
3.Nginx模块
nginx 真正的魅力在于它的模块,整个应用程序建立在一个模块化系统之上,在编译时,可以对每一个模块进行启用或者禁用,需要什么就定制什么。对 nginx 模块的基本原理总结一下,基本就是:在特定地方调用函数。(Nginx 本身支持多种模块,如 HTTP 模块、EVENTS 模块和 MAIL 模块,这里只简单讲述 HTTP 的模块及其中的命令) 下面是配置文件结构图:
Nginx
本身做的工作实际很少,当它接到一个 HTTP
请求时,它仅仅是通过查找配置文件将此次请求映射到一个 locationblock
,而此 location
中所配置的各个指令则会启动不同的模块去完成工作,因此模块可以看做 Nginx
真正的劳动工作者。通常一个 location
中的指令会涉及一个 handler
模块和多个 filter
模块(当然,多个 location
可以复用同一个模块)。handler
模块负责处理请求,完成响应内容的生成,而 filter
模块对响应内容进行处理。因此 Nginx
模块开发分为 handler
开发和 filter
开发(本文不考虑 load-balancer 模块)。下图展示了一次常规请求和响应的过程:
4.常见模块
4.1http index模块
模块功能及注意: 定义将要被作为默认页的文件。 文件的名字可以包含变量。 文件以配置中指定的顺序被 nginx 检查。 列表中的最后一个元素可以是一个带有绝对路径的文件。
4.2http log 模块
4.3Access模块
此模块提供了一个简易的基于主机的访问控制.
4.4Rewrite模块
功能描述:执行 URL
重定向,允许你去掉带有恶意的 URL
,包含多个参数(修改).利用正则的匹配,分组和引用,达到目的 配置范例:该模块允许使用正则表达式改变 URL
,并且根据变量来转向以及选择配置
4.5Proxy模块
功能描述:此模块能代理请求到其它服务器.也就是说允许你把客户端的 HTTP 请求转到后端服务器
4.6upstream模块
功能简介:该指令使请求被上行信道之间的基于客户端的 IP 地址分布