Nginx的核心原理
本节为大家介绍Nginx的核心原理,包含Reactor模型、Nginx的模块化设计、Nginx的请求处理阶段。
虽然本节的知识有一定的理论深度,但是与另一个有名的Java底层通信框架Netty在原理上有很多相似的地方。如果大家了解Netty的原理和Reactor模式,阅读本节将会更加轻松和愉快。
Reactor模型
Nginx对高并发IO的处理使用了Reactor事件驱动模型。Reactor模型的基本组件包含事件收集器、事件发送器、事件处理器3个基本单元,其核心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程/进程阻塞在多路复用器上,一旦有I/O事件到来或者准备就绪(文件描述符或Socket可读、写),多路复用器返回并将事先注册的相应I/O事件分发到对应的处理器中。
在Reactor模式中,事件收集器、事件发送器、事件处理器这3个基本单元的职责分别如下:
(1)事件收集器:负责收集Worker进程的各种I/O请求。
(2)事件发送器:负责将I/O事件发送到事件处理器。
(3)事件处理器:负责各种事件的响应工作。
Nginx的Reactor模型的设计大致如图7-3所示。
图7-3 Nginx的Reactor模型的设计
事件收集器将各个连接通道的IO事件放入一个待处理事件列,通过事件发送器发送给对应的事件处理器来处理。而事件收集器之所以能够同时管理上百万连接通道的事件,是基于操作系统提供的“多路IO复用”技术,常见的包括select、epoll两种模型。
正是由于Nginx使用了高性能的Reactor模式,因此是目前并发能力很高的Web服务器之一,成为迄今为止使用广泛的工业级Web服务器。当然,Nginx也解决了著名的网络读写的C10K问题。什么是C10K问题呢?
网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这类问题就被称为C10K问题。
Nginx的两类进程
一般来说,Nginx在启动后会以daemon方式在后台运行,其后台进程有两类:一类称为Master进程(相当于管理进程);另一类称为Worker进程(工作进程)。Nginx的进程结构大致如图7-4所示。
图7-4 Nginx的进程结构图
Nginx启动方式有两种:
(1)单进程启动:此时系统中仅有一个进程,该进程既充当Master管理进程角色,又充当Worker工作进程角色。
(2)多进程启动:此时系统有且仅有一个Master管理进程,至少有一个Worker工作进程。
一般来说,单进程模式用于调试。在生产环境下一般会配置成多进程模式,并且Worker工作进程的数量和机器CPU核数配置不一样多。了解Worker工作进程之前,首先了解一下Master管理进程的主要工作,主要有以下两点:
(1)Master管理进程主要负责调度Worker工作进程,比如加载配置、启动工作进程、接收来自外界的信号、向各Worker进程发送信号、监控Worker进程的运行状态等。所以Nginx启动后,我们能够看到至少有两个Nginx进程。
(2)Master负责创建监听套接口,交由Worker进程进行连接监听。
接下来介绍Nginx的Worker进程。Worker进程主要用来处理网络事件,当一个Worker进程在接收一条连接通道之后,就开始读取请求、解析请求、处理请求,处理完成产生数据后,再返回给客户端,最后断开连接通道。
各个Worker进程之间是对等且相互独立的,它们同等竞争来自客户端的请求,一个请求只可能在一个Worker进程中处理。这都是典型的Reactor模型中Worker进程(或者线程)的职能。
如果启动了多个Worker进程,那么每个Worker子进程独自尝试接收已连接的Socket监听通道,accept操作默认会上锁,优先使用操作系统的共享内存原子锁,如果操作系统不支持,就使用文件上锁。
经过配置,Worker进程的接收操作也可以不使用锁,在多个进程同时接收时,当一个连接进来的时候多个工作进程同时被唤起,则会导致惊群问题。而在上锁的场景下,只会有一个Worker阻塞在accept上,其他的进程会因为不能获取锁而阻塞,所以上锁的场景不存在惊群问题。
Nginx的模块化设计
Nginx服务器被分解为多个模块,模块之间严格遵循“高内聚,低耦合”的原则,每个模块都聚焦于一个功能。高度模块化的设计是Nginx的架构基础。
什么是