为了更好地理解设计,你需要了解NGINX是如何工作的。NGINX之所以能在性能上如此优越,是由于其背后的设计。许多web服务器和应用服务器使用简单的线程的(threaded)、或基于流程的(process-based)架构, NGINX则以一种复杂的事件驱动(event-driven)的架构脱颖而出,这种架构能支持现代硬件上成千上万的并发连接。
Inside NGINX infographic涉及了从高层次进程架构的挖掘,到NGINX的单进程处理多连接的图解。本篇文章讲解了这些工作细节。
设置场景——NGINX进程模型
-1920617532.png
为了更好地理解设计,你需要了解NGINX是如何工作的。NGINX有一个主进程(master process)(执行特权操作,如读取配置、绑定端口)和一系列工作进程(worker process)和辅助进程(helper process)。
这个四核服务器内,NGINX主进程创建了4个工作进程和2个缓存辅助进程(cachehelper processes)来管理磁盘内容缓存(on-disk content cache)。
为什么架构很重要?
任何Unix应用程序的根本基础都是线程或进程(从Linux操作系统的角度看,线程和进程基本上是相同的,主要区别是他们共享内存的程度)。进程或线程,是一组操作系统可调度的、运行在CPU内核上的独立指令集。大多数复杂的应用程序都并行运行多个线程或进程,原因有两个:
可以同时使用更多的计算机内核。
线程和进程使并行操作很容易实现(例如,同时处理多个连接)。
进程和线程都消耗资源。它们都使用内存和其他OS资源,导致内核频繁切换(被称作上下文切换(context switch)的操作)。大多数现代服务器可以同时处理数百个小的、活跃的(active)线程或进程,但一旦内存耗尽,或高I/O负载导致大量的上下文切换时,服务器的性能就会严重下降。 对于网络应用,通常会为每个连接(connection)分配一个线程或进程。这种架构易于实现,但是当应用程序需要处理成千上万的并发连接时,这种架构的扩展性就会出现问题。
NGINX是如何工作的?
NGINX使用一个了可预见式的(predictable)进程模型,调度可用的硬件资源:
1. 主进程执行特权操作,如读取配置和绑定端口,还负责创建子进程(下面的三种类型)。
2. 缓存加载进程(cache loader process)在启动时运行,把基于磁盘的缓存(disk-based cache)加载到内存中,然后退出。对它的调度很谨慎,所以其资源需求很低。
3. 缓存管理进程(cache manager process)周期性运行,并削减磁盘缓存(prunes entries from the disk caches),以使其保持在配置范围内。
4. 工作进程(worker processes)才是执行所有实际任务的进程:处理网络连接、读取和写入内容到磁盘,与上游服务器通信等。
多数情况下,NGINX建议每1个CPU核心都运行1个工作进程,使硬件资源得到最有效的利用。你可以在配置中设置如下指令: worker_processes auto,当NGINX服务器在运行时,只有工作进程在忙碌。每个工作进程都以非阻塞的方式处理多个连接,以削减上下文切换的开销。 每个工作进程都是单线程且独立运行的,抓取并处理新的连接。进程间通过共享内存的方式,来共享缓存数据、会话持久性数据(session persistence data)和其他共享资源。
NGINX内部的工作进程
每一个NGINX的工作进程都是NGINX配置(NGINX configuration)初始化的,并被主进程设置了一组监听套接字(listen sockets)。
-469944474.png
NGINX工作进程会监听套接字上的事件(accept_mutex和kernel socketsharding),来决定什么时候开始工作。事件是由新的连接初始化的。这些连接被会分配给状态机(statemachine)—— HTTP状态机是最常用的,但NGINX还为流(原生TCP)和大量的邮件协议(SMTP,IMAP和POP3)实现了状态机。
646475436.png
状态机本质上是一组告知NGINX如何处理请求的指令。大多数和NGINX具有相同功能的web服务器也使用类似的状态机——只是实现不同。
调度状态机
把状态机想象成国际象棋的规则。每个HTTP事务(HTTP transaction)都是一局象棋比赛。棋盘的一边是web服务器——坐着一位可以迅速做出决定的大师级棋手。另一边是远程客户端——在相对较慢的网络中,访问站点或应用程序的web浏览器。 然而,比赛的规则可能会很复杂。例如,web服务器可能需要与各方沟通(代理一个上游的应用程序),或者和认证服务器交流。web服务器的第三方模块也可以拓展比赛规则。
阻塞状态机
回忆一下我们之前对进程和线程的描述:是一组操作系统可调度的、运行在CPU内核上的独立指令集。大多数web服务器和web应用都使用一个连接/一个进程或一个连接/一个线程的模型来进行这局国际象棋比赛。每个进程或线程都包含一个将比赛玩到最后的指令。在这个过程中,进程是由服务器来运行的,它的大部分时间都花在“阻塞(blocked)”上,等待客户端完成其下一个动作。