第三节目录
一、模块体系
nginx 的核心设计思想就是模块化,它内部由核心模块和其他功能模块组成。这种结构使 nginx 具有高性能、高可靠性、高扩展性和灵活性的特点。
核心模块:主要负责维护一个运行循环,在这个循环中执行网络请求处理的不同阶段,并且在不同处理阶段都会调用相应的功能模块。
功能模块:主要负责网络读写数据、服务器内部操作等。
将它们按照功能划分,可以分成如下细分模块:
- 核心模块:这是 nginx 运行的基石,负责最基本的进程管理、配置解析和底层框架等,维护 nginx 的整个生命周期和运行环境。例如 ngx_core_module、ngx_conf_module、ngx_error_log_module 等
- 事件模块:实现了 nginx 事件驱动、非阻塞的 I/O 模型,负责监听和处理网络事件(如连接建立、数据读/写),是 nginx 高性能和高并发能力的直接来源。它独立于操作系统的事件处理框架,不同操作系统事件驱动模块不同。例如 ngx_event_module、ngx_epoll_module(适用于 Linux)、ngx_kqueue_module(适用于 MacOS) 等。
- Handler 模块:位于 HTTP 处理链的核心位置,负责根据请求 url 执行具体的业务逻辑,它们种类最丰富,负责生成响应内容,如读取静态文件、转发请求到上游服务器、内部重定向等。如 ngx_http_static_module、ngx_http_fastcgi_module 等。
- Filter 模块:工作在 handler 处理模块之后,负责对阶段处理模块生成的响应头和响应体进行修改、转换或压缩,即对即将将发送给客户端的响应数据进行优化或格式化,同时它也是链式运行的,可以多个过滤模块顺序执行。例如 ngx_http_gzip_filter_module、ngx_http_handers_filter_module、ngx_http_chunked_filter_module 等。
- 负载均衡模块:与反向代理配合使用,专门负责选择 upstream 服务器组中的最佳后端服务器,提高系统的伸缩性和可靠性,确保后端服务健康。例如 ngx_http_upstream_module、ngx_http_upstream_least_conn_module 等。
- 其他辅助模块:这类模块功能多样,主要提供各种辅助、安全、缓存和配置增强功能。例如 ngx_http_access_module(安全与访问控制)、ngx_http_stub_status_module(nginx 状态监控)、ngx_http_log_module(日志访问)、ngx_http_map_module(变量映射)等。
nginx 支持动态加载模块,你可以选择性的将某些模块编译为动态链接库(
.so文件),通过动态模块进行加载,而无需将模块编译到 nginx 可执行文件中。
- 前一节提到过,开启
--with-compat选项将允许 nginx 可执行文件加载未来的动态模块,--add-dynamic-module=xxx选项可以将模块 xxx 编译为动态模块。- 在 nginx.conf 文件最外层中使用
load_module指令加载外部动态模块(只能在最外层中引入动态模块)- 使用动态模块非常方便后期维护,需要升级或替换模块时只需要替换对应的
.so文件即可,然后重载配置即可。
nginx 存在一个 njs 模块,支持用户通过 JavaScript 编写模块,这显著降低了用户使用 C 语言开发模块的难度和必要性。(后续的 NJS 篇会学习到)

nginx 模块化协作
二、进程模型
(1)Master 进程模型
master 进程是 nginx 启动后第一个运行的进程,它不负责处理任何客户端请求,而是承担起整个系统的管理、协调和守护职责:
系统初始化:
- 加载配置文件:这一阶段负责读取和校验 nginx.conf 配置文件,如果配置存在语法错误,master 进程会立即报错并退出;
- 创建运行环境:前一步成功后,master 进程开始初始化日志文件、监听套接字等,确保环境就绪;
- 加载相应模块:最后如果配置了动态模块,则 master 进程继续加载这些共享对象。
worker 进程管理:
- 创建和控制: master 进程会根据配置(worker_processes 指令),通过 fork() 系统调用创建和启动一组 worker 进程;
- 进程守护:master 进程持续监控 worker 进程的运行状态,如果某个 worker 进程意外退出,则 master 会立即自动重启一个新的 worker 进程来替换它,确保服务的持续可用性和高可靠性;
- 信号处理:master 进程是 nginx 接收外部信号(如 kill 命令发送的信号)的唯一入口,负责将这些信号转化为对 worker 进程的相应操作。
接受和分发信号 :master 进程拦截操作系统信号,并根据信号类型执行相应的操作,通常涉及对 worker 进程的控制。如 HUP(平滑重载)、QUIT(平滑退出)、USE1(重开日志文件)、USE2(平滑升级)、INT(快速退出)等。
重载与升级:
- 平滑重载:master 接收到 HUP 信号后,会加载新的配置文件并启动一组新的 worker 进程,再通知旧 worker 进程停止连接并处理完当前任务后平滑退出;
- 平滑升级:master 能够协调新旧的 nginx 可执行文件,确保在一个新的 nginx 版本启动时,旧的 worker 可以继续服务请求,直到所有连接都迁移到新版本。
总结:master 进程就像一个项目经理,它规划环境、招聘(启动 worker)、监督(守护 worker)、处理外部指令(接受并分发信号),并确保项目的平稳过渡(重载和升级)。
(2)Worker 进程模型
worker 进程是 nginx 进程模型中真正处理客户端请求和网络 I/O 的核心执行者。它们与 master 进程协调工作。worker 进程的数量通常等于或略高于 CPU 核心数,它们共同监听 master 进程初始化好的同一个套接字,所有的 worker 地位平等、独立运行、平等竞争资源。
对于 CPU 密集型任务,worker 进程数量应该和 CPU 核心数量相同;对于 I/O 密集型任务,worker 数量可以略高于 CPU 核心数量(如 1.5~2 倍之间)。总的来说,worker 数量的选择都将根据内存大小、内容类型、硬件配置等综合来选择。
nginx 的精明之处就在于,它将内存用在 "刀刃上",不会去创建新进程或线程来徒耗硬件资源,nginx 只会检查内存等硬件状态,初始化新的上下文并添加到队列中等待异步处理。所以即使在系统负载很极端的情况下,nginx 往往也能游刃有余。
下面为每一个 worker 的工作机制:
监听与接受新连接:
- 惊群问题:每个 worker 进程同时监听同一个端口,当新连接到达时,操作系统可能会唤醒多个 worker 进程,这就是所谓的惊群问题。对于这一问题 nginx 则采用了如 epoll 的 EPOLLEXCLUSIVE 的优化连接来接收,确保只有一个 worker 进程能成功接收并处理该新连接;
- 独占连接:一旦 worker 进程成功接受一个连接,该连接就完全归属这个 worker 进程,直到连接关闭。
事件循环:
- 等待事件:调用 I/O 多路复用接口(如 epoll、kqueue),阻塞等待网络事件(如数据可读、可写、连接关闭)发生;
- 事件处理:一旦接口返回有事件发生,worker 进程立即处理这些事件。如如读取请求头、执行模块逻辑、发送响应等;
- 非阻塞:在处理一个连接的 I/O 操作时,如果操作不能立即完成(如等待后端服务器响应),worker 进程不会阻塞,而是将该连接的状态保存起来,然后返回到事件循环,处理下一个就绪的事件。
请求处理:
- 读取请求:接收客户端发送的请求行、请求头和请求体;
- 模块加载:按照 nginx 的处理阶段顺序,依次调用配置中注册在该阶段的模块函数。如 rewrite 重写模块、access 认证模块等;
- Handler 执行:执行负责生成内容的 handler 模块;
- Filter 过滤:响应内容生成后,经过一系列 filter 模块的处理。如 gzip 压缩、header 注入等;
- 发送响应:将最终的响应数据发送回客户端。
总结: worker 进程是 nginx 中真正的牛马,它通过事件循环和非阻塞 I/O 机制,高效、独立地完成请求的接收、处理和响应工作。

Master 与 Worker 进程架构
三、事件模型
传统服务器(如 apache 的 prefork 模式)采用 进程/线程阻塞 模型,即每个新连接都需要创建一个新的进程或线程来处理,并且在进行 I/O 操作(如磁盘读写、网络等待)时,该进程或线程会被阻塞,这导致资源消耗大、并发能力受限。
而 nginx 采用异步非阻塞 I/O,当 worker 进程发起一个 I/O 操作时,如果数据尚未准备好,则调用会立即返回,进程不会停下来等待;worker 进程发起 I/O 请求后,会继续处理其他连接或任务。当 I/O 操作完成(数据准备好)时,系统会通知 worker 进程,这就称为事件。
nginx 的事件驱动模型主要由以下三部分组成:
I/O 多路复用: 这是实现异步非阻塞的核心技术,它允许一个 worker 进程监视多个文件描述符(每个连接和套接字都是一个 fd),并在任何 fd 准备好进行 I/O 操作时,通知该进程。(系统会选择最优方案:epoll [ 性能最好,适用 Linux ]、kqueue [ 使用 FreeBSD & MacOS ]、/dev/poll [ 适用 Solaris ]、select & poll [ 性能最差,作为兜底方案 ])
事件管理: nginx 抽象了连接和事件的概念
- 连接对象:代表一个网络连接,存储连接的 FD、对端地址等信息
- 读写事件对象:每个连接对象包含一个读事件和一个写事件,它们是 nginx 注册到 I/O 多路复用机制中的具体项,事件对象存储了对应的 回调函数,指示事件发生时应该执行哪个模块逻辑。
事件循环: nginx 工作核心,从上到下无限循环
- 收集事件:worker 进程将所有当前活跃的连接注册到 I/O 多路复用机制中;
- 等待事件:进程进入阻塞状态,等待操作系统通知是否有 I/O 事件发生;
- 处理事件:一旦有事件发生(连接、数据读写、缓冲区读写等),进程就被唤醒,并得到一个 "就绪" 事件列表;
- 分发处理:根据不同事件类型,调用注册好的事件处理函数来处理对应连接,执行相应模块逻辑;
- 返回循环:处理完成后,进程立即回到第一步,等待新事件,绝不空闲。
事件的处理过程不能过长,否则其他事件得不到及时处理,就会严重影响 nginx 事件循环的整体效率。所以对于占用 CPU 事件过长的任务,nginx 会将它拆分,在多个小事件中完成它。

nginx 事件循环机制
四、NGINX 缓存机制
nginx 的缓存机制非常强大和灵活,主要用于缓存后端服务器的响应内容,这可以显著提高网站性能、减轻后端服务器负载。
nginx 缓存机制基于文件系统,它将后端服务器返回的响应内容存储在本地磁盘上或远程存储上,配置指定的键后(没错,缓存是可以配置为键值对的),worker、cache loader 等进程都可以通过键来读取缓存。
缓存流程:
- 缓存前处理:当前端 nginx 收到响应后,优先检查缓存条件(
proxy_cache_valid指令)确认是否允许被缓存,通过检查后再生成键(通常是根据 url 等哈希值计算出一个唯一键),最后确认临时文件的路径(确保写入过程的原子性); - 数据临时写入:上一步完成后,nginx 将为本次响应创建临时文件并同步写入,同一时刻 worker 进程也会将这个响应发回客户端;
- 正式缓存:上一步完成后,nginx 将正式更新缓存,首先在共享内存中(
keys_zone定义的区域)创建新索引或更新旧索引(记录键、缓存事件等原信息),任何 nginx 将临时文件进行重命名(采用 os 的原子调用rename())并重命名到最终的缓存地,至此整个缓存流程完成。 - 后续处理:
- cache loader 加载器:在 nginx 启动时,它扫描磁盘上的缓存目录,将缓存索引重新加载到共享内存中;
- cache manager 管理器:在 Nginx 运行时,它会周期性地执行清理任务。(如,清理过期缓存、控制缓存大小等)
总结: 检查条件 → \rightarrow → 写入临时文件 → \rightarrow → 原子性重命名到正式缓存目录 → \rightarrow → 注册到共享内存 → \rightarrow → worker 收到相同请求时直接读缓存返回响应

nginx 缓存决策流程
五、NGINX 内存与资源管理
nginx 之所以能在大并发下保持极低的资源消耗(往往几万并发只占用几十 MB 内存),除了依靠事件驱动外,其独特的内存管理和资源调度机制功不可没。
内存池机制:
在 C 语言下,频繁的 malloc 和 free 不仅代码容易出错导致内存泄漏,还会产生大量内存碎片,降低系统性能。nginx 为了解决这个问题,设计了内存池机制:
- 按需分配:nginx 不会为每一个细小的对象单独申请内存,它会为每一个连接、每一个请求预先申请一大块连续的内存作为内存池;
- 统一管理:在处理请求的过程中,所有需要的内存(如存储 HTTP 头、变量等)都直接从这个池子里 "切" 一块拿走,不需要调用系统的内存分配函数;
- 集中销毁:这是最精髓的地方,当连接关闭或请求结束时,nginx 不需要逐一释放零散内存,而是直接销毁整个内存池。
共享内存:
前文提到 worker 进程是相互独立的、内存隔离的,但在实际业务中它们往往需要共享数据,如限流计数(不让每个 worker 单独计算)、ssl 会话缓存、upstream 负载状态等。为应对上述情况,nginx 使用共享内存来实现 worker 间的通信,并引入了 slab 内存分配器来管理这块公共区域:
- Slab 分配器:它将共享内存划分为不同大小的 "槽位",并通过红黑树进行快速检索,这使多个 worker 可以高效、"无锁"(细粒度锁,并非完全无锁)的读写共享数据。(当你配置
limit_req_zone进行限流,或者使用upstream_zone共享后端健康状态时,底层都在使用这套机制)
缓冲区管理:
nginx 作为反向代理,夹在客户端和上游服务器中间,但往往这两端的网速是不对等的(例如:后端服务器在内网,速度极快;而客户端在公网,可能是弱网环境)。所以 nginx 又通过缓冲区充当了 "蓄水池" 的角色,实现了全异步的数据流转:
- 请求缓冲:默认情况下,nginx 会先将客户端的请求体完整读取到内存缓冲区中(如果请求体太大超过了内存限制,nginx 会自动将其写入临时磁盘文件),这么做可以让后端服务器瞬间读取完整的请求并处理,而不需要陪着慢速客户端耗时间,从而提升后端效率;
- 响应缓冲:当后端服务器快速吐出响应时,nginx 会先将响应存入缓冲区,然后按照客户端的网速慢慢发送给客户端,这使得后端应用服务器(如 Tomcat)处理完请求后能立即脱身去处理下一个请求,极大提高后端服务器效率。