为了解决 10,000 个同时连接的 C10K 问题,nginx 的编写考虑了不同的架构——一种更适合同时连接数和每秒请求数的非线性可扩展性。nginx 是基于事件的,因此它不遵循 Apache 为每个网页请求生成新进程或线程的风格。最终结果是,即使负载增加,内存和 CPU 使用率仍可管理。nginx 现在可以在具有典型硬件的服务器上提供数万个并发连接。
模块化架构
nginx 代码库由一个核心和多个模块组成。nginx的核心负责提供web服务器的基础,web和邮件反向代理功能;它支持使用底层网络协议,构建必要的运行时环境,并确保不同模块之间的无缝交互。但是,大多数特定于协议和应用程序的功能是由 nginx 模块完成的,而不是核心。下图是整体架构:
在内部,nginx 通过管道或模块链处理连接。换句话说,对于每个操作,都有一个模块在做相关的工作;例如,压缩、修改内容、执行服务器端包括、通过 FastCGI 或 uwsgi 协议与上游应用服务器通信,或与 memcached 通信。
有几个 nginx 模块位于核心和真正的“功能”模块之间。这些模块是 http
和mail
。这两个模块在核心组件和低级组件之间提供了额外的抽象级别。在这些模块中,实现了与相应应用层协议(如 HTTP、SMTP 或 IMAP)相关联的事件序列的处理。结合nginx核心,这些上层模块负责维护对各个功能模块的正确调用顺序。虽然 HTTP 协议目前作为http
模块的一部分实现,但由于需要支持其他协议,如 SPDY(参见“SPDY:一种用于更快网络的实验性协议”)。
功能模块可以分为事件模块、阶段处理程序、输出过滤器、变量处理程序、协议、上游和负载均衡器。大多数这些模块补充了 nginx 的 HTTP 功能,尽管事件模块和协议也用于mail
. 事件模块提供特定的操作系统相关事件通知机制,如kqueue
或epoll
。nginx 使用的事件模块取决于操作系统能力和构建配置。协议模块允许 nginx 通过 HTTPS、TLS/SSL、SMTP、POP3 和 IMAP 进行通信。
多路复用和事件驱动
nginx 大量使用多路复用和事件通知,并将特定任务专门用于分离进程。在称为worker
s的有限数量的单线程进程中,在高效运行循环中处理连接。每个worker在nginx内每秒可以处理数千个并发连接和请求。
多阶段异步处理
nginx响应HTTP请求处理周期如下所示:
- 客户端发送 HTTP 请求。
- nginx 核心根据与请求匹配的配置位置选择适当的阶段处理程序。
- 如果配置为这样做,负载平衡器会选择上游服务器进行代理。
- 阶段处理程序完成其工作并将每个输出缓冲区传递给第一个过滤器。
- 第一个过滤器将输出传递给第二个过滤器。
- 第二个过滤器将输出传递给第三个(依此类推)。
- 最终响应被发送到客户端。
该请求大致分为 7 个阶段,这些阶段是可以重复发生的。异步处理和多阶段是相辅相成的,只有把请求分为多个阶段,才有所谓的异步处理。当一个时间被分发到事件消费者中进行处理时,事件消费者处理完这个事件只相当于处理完 1 个请求的阶段。什么时候可以处理下一个阶段呢?异步操作是通过模块化、事件通知、回调函数的广泛使用和微调定时器来实现的。
多进程
nginx 在内存中运行多个进程;有一个主进程master和多个worker
进程。还有一些特殊用途的进程,特别是缓存加载器和缓存管理器。所有进程在 nginx 1.x 版本中都是单线程的。所有进程主要使用共享内存机制进行进程间通信。worker
进程接受、处理和处理来自客户端的连接,提供反向代理和过滤功能,并完成 nginx 能够完成的几乎所有其他工作。
worker
进程接受来自共享“监听”套接字的新请求,并在每个套接字内部执行一个高效的运行循环worker
来处理每个worker
. worker
nginx 中没有专门的仲裁或连接到的分配;这项工作是由操作系统内核机制完成的。启动时,会创建一组初始侦听套接字。worker
然后在处理 HTTP 请求和响应的同时不断接受、读取和写入套接字。
优点:
- 很好地跨多个内核扩展,单独的
worker
每个内核允许充分利用多核架构,并防止线程抖动和锁定; - 没有资源匮乏,资源控制机制在单线程
worker
进程中被隔离; - 此模型还允许跨物理存储设备实现更高的可扩展性,促进更多磁盘利用率并避免磁盘 I/O 阻塞;
缓存
nginx 中的缓存是在文件系统上以分层数据存储的形式实现的。缓存键是可配置的,并且可以使用不同的特定于请求的参数来控制进入缓存的内容。缓存键和缓存元数据存储在共享内存段中,缓存加载器、缓存管理器和worker
s 可以访问它们。