简介
本文会从Nginx内部结构——非阻塞式,以及进程结构角度分析,并与阻塞-多进程结构对比,探究为何Nginx性能如此突出。
1) NGINX流程模型
NGINX有一个主进程(执行特权操作,如读取配置和绑定到端口)以及许多辅助进程。
在这台四核服务器上,NGINX主进程创建了四个工作进程和几个缓存帮助程序,用于管理磁盘内容缓存。
2) 为什么使用Nginx
任何Unix应用程序的基本基础都是线程或进程。(从Linux OS的角度来看,线程和进程几乎是相同的;主要区别在于它们共享内存的程度。)线程或进程是操作系统可以调度在CPU上运行的一组独立的指令。核心。大多数复杂的应用程序并行运行多个线程或进程,原因有两个:
进程和线程消耗资源。它们每个都使用内存和其他OS资源,并且需要在内核之间进行交换(称为上下文切换)。大多数现代服务器可以同时处理数百个小型活动线程或进程,但是一旦内存耗尽或高I / O负载导致大量上下文切换,性能就会严重下降。
设计网络应用程序的常用方法是为每个连接分配一个线程或进程。该体系结构简单易实现,但是当应用程序需要处理数千个同时连接时,它无法扩展。
3) NGINX如何工作?
NGINX使用的是可预测的,并且转换成可用硬件资源的process模型:
在大多数情况下,建议使用NGINX配置成,每个CPU内核运行一个工作进程,以最有效地利用硬件资源。可以通过auto在worker_processes伪指令上设置参数来配置它:
当NGINX服务器处于活动状态时,只有worker进程处于繁忙状态。每个worker进程以非阻塞方式处理多个连接,从而减少了上下文切换的数量。
每个worker进程都是单线程的,并且独立运行,获取新连接并进行处理。进程可以使用共享内存进行通信,以共享缓存数据,会话持久性数据和其他共享资源。
4) NGINX Worker流程内部
每个NGINX worker进程都使用NGINX配置初始化,并且由master进程提供一组侦听socket。
首先,NGINX worker进程等待socket(accept_mutex和内核socket分片)中的事件。事件由新的传入连接启动。这些连接被分配给状态机 ,HTTP状态机是最常用的,另外NGINX还为流交换(例如TCP)和许多邮件协议(SMTP,IMAP和POP3)实现状态机。
状态机本质上是一组指令,用于告诉NGINX如何处理请求。大多数执行与NGINX相同功能的Web服务器都使用类似的状态机,区别在于怎么实现。
5) 调度状态机
将状态机想像成国际象棋的规则。每个HTTP事务都是一个国际象棋游戏。棋盘的一侧是Web服务器-一个可以非常快速地做出决策的大师。另一端是远程客户端,即通过相对较慢的网络访问站点或应用程序的Web浏览器。
但是,游戏规则可能非常复杂。例如,Web服务器可能需要与其他方通信(代理上游应用程序)或与身份验证服务器对话。Web服务器中的第三方模块甚至可以扩展游戏规则。
什么是阻塞状态机
回忆一下我们对进程或线程的描述,它们是操作系统可以调度在CPU内核上运行的一组独立的指令。大多数Web服务器和Web应用程序都使用每个连接进程或每个连接线程模型来进行下棋游戏。每个进程或线程都包含从头至尾玩一个游戏的指令。在服务器运行该过程的过程中,它大部分时间都处于“阻塞”状态——等待客户端完成下一步操作。
要记住的重要一点是,每个活动的HTTP连接(每个象棋游戏)都需要一个专用的进程或线程(特级大师)。该体系结构很容易利用第三方模块(“新规则”)进行扩展。但是,这存在巨大的不平衡:由文件描述符和少量内存表示的,相当轻量级的HTTP连接,映射到单独的线程或进程,线程或进程是一个非常大的系统对象。这在编程上很方便,但是非常浪费资源。
非阻塞式的NGINX 是真正的大师
也许您听说过同时进行的展览游戏,其中一位国际象棋大师同时玩几十个对手?
Kiril Georgiev在保加利亚的索非亚同时对弈360人。他的最终得分是284胜70平6负。
这就是NGINX工作进程玩“棋”的方式。每个worker(记住-每个CPU内核通常只有一个工作人员)是一个大师,可以同时玩数百(实际上是数十万)个游戏。
worker从不阻塞网络流量,而等待其“对手”(客户端)做出响应。做出动作后,worker会立即进入其他等待处理动作的游戏,或者欢迎新玩家加入。
为什么这比阻塞-多进程结构要快?
NGINX很好地扩展以支持每个worker进程数十万个连接。每个新连接都会创建另一个文件描述符,并在worker进程中消耗少量额外的内存。每个连接几乎没有额外的开销。NGINX进程可以保持固定到CPU。上下文切换相对较少,并且只发生在没有工作要做时。
在阻塞式结构中,每个进程连接方法,每个连接都需要大量的额外资源和开销,并且上下文切换(从一个进程交换到另一个进程)非常频繁。
有关更详细的说明,请查看NGINX,Inc.公司开发副总裁兼联合创始人Andrew Alexeev 撰写的有关NGINX体系结构的文章。
通过适当的系统调整,NGINX可以扩展为在每个worker进程中处理数十万个并发HTTP连接,并且可以吸收流量峰值(大量新游戏涌入)而不会错过任何一个。
6) 更新配置并升级NGINX
NGINX的进程结构只有少量的worker进程,因此可以非常高效地更新配置,甚至包括NGINX二进制文件本身。
更新NGINX配置是一个非常简单,轻巧且可靠的操作。它通常只需要运行nginx -s reload命令,该命令检查磁盘上的配置并向主进程发送SIGHUP信号。
当主进程收到SIGHUP时,它将执行以下两项操作:
这种重新加载过程可能会导致CPU和内存使用量的小幅上升,但是与从活动连接中加载资源相比,这通常是不明显的。您可以每秒多次重载配置(许多NGINX用户正是这样做的)。极罕见的情况是,当有许多代的NGINX worker进程等待连接关闭时出现问题,但即使这样也能很快解决。
NGINX的二进制升级过程实现了高可用性的圣杯——您可以动态升级软件,而不会出现连接断开,停机或服务中断的情况。
二进制升级过程在方法上类似于平稳重新加载配置。一个新的NGINX master进程与原始master进程并行运行,并且它们共享侦听socket。这两个进程都处于活动状态,并且它们各自的worker进程都处理流量。然后,您可以指示旧的master进程 及其worker进程 正常退出。
整个过程在“ 控制NGINX”中有更详细的描述。
7)结论
该内部NGINX信息图表提供的NGINX如何功能的高度概括,但是这背后简单的解释是,经过十多年的创新和优化,使NGINX对范围广泛的硬件提供最佳的性能,同时保持安全性和可靠性现代Web应用程序要求。
如果您想了解有关NGINX中优化的更多信息,请查看以下重要资源:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。