窥探Nginx内部实现:如何为性能和规模进行设计

NGINX在网络性能方面处于领先地位,这一切都是由于软件的设计方式。尽管许多Web服务器和应用程序服务器使用简单的线程或基于进程的架构,但NGINX具有复杂的事件驱动架构,使其能够在现代硬件上扩展到数十万个并发连接。

NGINX内部信息图从高层面的进程架构中阐述了NGINX如何在单个进程中处理多个连接。本文进一步从细节上解释了这一切。

设置场景 - NGINX进程模型

为了更好的理解这个设计,你需要了解NGINX如何运行。 NGINX具有主进程(执行诸如读取配置和绑定到端口的特权操作)以及多个工作者进程和辅助进程。

在这个四核服务器上,NGINX主进程创建了四个工作者进程和一些管理磁盘内容缓存的缓存辅助进程。

为什么架构很重要?

任何Unix应用程序的基础是线程或进程。 (从Linux操作系统的角度来看,线程和进程大致相同,主要区别在于它们共享内存的程度。)线程或进程是一组独立的指令,操作系统可以将其调度运行在CPU的某个核上。大多数复杂应用程序并行运行多个线程或进程出于两个原因:

他们可以同时使用更多的计算内核。

线程和进程使并行执行操作非常容易(例如,同时处理多个连接)。 进程和线程消耗资源。它们各自使用内存和其他操作系统资源,并且它们需要与内核交换(一个称为上下文切换的操作)。大多数现代服务器可以同时处理数百个小型,活跃的线程或进程,但是一旦内存耗尽,或者当高I / O负载导致大量的上下文切换时,性能会严重恶化。

设计网络应用程序的常用方法是为每个连接分配线程或进程。这种架构简单易用,但是当应用程序需要处理数千个并发连接时,它不易扩展。

NGINX如何工作?

NGINX使用已优化的可预测的进程模型用于可用的硬件资源:

主进程执行特权操作,如读取配置和绑定到端口,然后创建少量子进程(接下来的三种类型)。

缓存加载程序进程在启动时运行,将基于磁盘的缓存加载到内存中,然后退出。保守调度,资源需求低。

缓存管理器进程定期运行,并从磁盘缓存中删除条目,以使其保持在配置的大小之内。

工作者进程完成所有工作!它们处理网络连接,读取内容和磁盘写入,并与上游服务器进行通信。

在大多数情况下,推荐使用NGINX配置 - 每个CPU内核运行一个工作者进程 - 最有效地利用硬件资源。您可以通过在worker_processes指令上设置auto参数进行配置:

当NGINX服务器处于活动状态时,只有工作者进程在忙。每个工作者进程以非阻塞方式处理多个连接,减少上下文切换的次数。

每个工作者进程都是单线程的,独立运行,接受新连接并处理它们。这些进程可以使用共享内存来共享缓存数据、会话持久性数据和其他共享资源。

Nginx工作者进程内部

每个NGINX工作者进程都使用NGINX配置进行初始化,并由主进程提供一组监听套接字。

NGINX工作者进程首先等待监听套接字上的事件(accept_mutex和内核socket分片)。事件由新的传入连接发起。这些连接被分配给状态机 - HTTP状态机是最常用的,但NGINX还实现了流(原始TCP)流量和多个邮件协议(SMTP,IMAP和POP3)的状态机。

状态机本质上是告诉NGINX如何处理请求的一组指令。与NGINX执行功能相同的大多数Web服务器使用类似的状态机 - 区别只在于实现。

调度状态机

想象下国家象棋的规则。每个HTTP事务都是一个象棋游戏。在棋盘的一边是网络服务器 - 一个可以很快做出决定的大师。另一方面是远程客户端 - 通过较慢网络访问站点或应用程序的Web浏览器。

但是,游戏规则可能非常复杂。例如,Web服务器可能需要与其他方(代理上游应用程序)通信或与认证服务器通信。 Web服务器中的第三方模块甚至可以扩展游戏的规则。

阻塞状态机

回想一下我们对一个进程或线程的描述,作为操作系统可以安排在CPU内核上运行的独立指令集。大多数Web服务器和Web应用程序使用每个连接进程或线程模式来玩下棋游戏。每个进程或线程都包含将游戏玩到最后的指令。在服务器运行的过程中,它的大部分时间花费在阻塞上 - 等待客户端完成下一步。

Web服务器进程监听套接字上的新连接(由客户端发起的新游戏)。

当它得到一个新游戏,它玩这个游戏,阻塞每次移动以等待客户的回应。

一旦游戏完成,Web服务器进程可能会等待客户端是否要开始一个新的游戏(这对应于一个keepalive连接)。如果连接关闭(客户端消失或发生超时),则Web服务器进程将返回并监听新游戏。

要记住的一点是,每个活跃的HTTP连接(每个象棋游戏)需要一个专门的进程或线程(一个大师)。该架构简单易用,可扩展至第三方模块(“新规则”)。然而,有一个巨大的不平衡:由文件描述符和少量内存表示的相当轻量级的HTTP连接映射到一个单独的线程或进程(一个非常重的操作系统对象)中。它易于编程,但非常浪费。

NGINX是一位真正的大师

也许你听说过一位国际象棋大师同时与数十名对手下棋的游戏?

这就是一个NGINX工作者进程如何“下棋”。每个工作者进程(记住 - 每个CPU核通常有一个工作者进程)是一个可以同时玩数百(实际上是成千上万的)游戏的大师。

工作者进程在监听和连接套接字上等待事件。

事件发生在套接字上,工作者进程处理它们:

监听器上的事件意味着客户端已经开始了一个新的象棋游戏。工作者进程创建一个新的连接套接字。

连接套接字上的事件意味着客户端已经进行了新的移动。工作者进程迅速回应。 一名工作者进程绝对不会阻塞网络流量,等待其“对手”(客户端)回应。当移动时,工作者进程立即进入其他游戏,等待处理的游戏,或者在门口欢迎新玩家。

为什么比阻塞多进程架构更快?

NGINX可以很好地扩展,以支持每个工作者进程处理成千上万的连接。每个新连接创建一个文件描述符,并在工作者进程中消耗少量额外的内存。每个连接几乎没有额外的开销。 NGINX进程可以保持固定到某CPU上。上下文切换相对不频繁,当没有工作要做的时候发生。

在阻塞模式中,每个连接一进程的方法中,每个连接需要大量额外的资源和开销,并且上下文切换(从一个进程交换到另一个进程)是非常频繁的。

有关更详细的解释,请参阅NGINX公司企业开发副总裁兼联合创始人Andrew Alexeev,了解有关NGINX架构的文章。

通过适当的系统调优,NGINX可以扩展以处理每个工作者进程处理数十万个并发HTTP连接,并可以吸收流量尖峰(新游戏的涌入),而不会丢失节拍。

更新配置和升级NGINX

具有少量的工作者进程的NGINX的进程架构,可以非常有效地更新配置,甚至是NGINX二进制本身。

更新NGINX配置是一种非常简单,轻便,可靠的操作。它通常只是运行nginx -s reload命令,它检查磁盘上的配置,并向主进程发送SIGHUP信号。

当主进程收到SIGHUP时,它会执行两件事情:

重新加载配置并分配一组新的工作者进程。这些新的工作者进程立即开始接受连接并处理流量(使用新的配置设置)。

指示旧工作者进程正常退出。旧工作者进程停止接受新连接。在当前的HTTP请求完成后,旧工作者进程就会优雅地关闭连接(也就是说,没有任何延续的keepalive)。一旦所有连接都关闭,旧工作者进程就会退出。

这种重新加载过程可能导致CPU和内存使用量的小幅上升,但与活动连接的资源负载相比,通常是不可察觉的。您可以每秒重新加载配置多次(而且许多NGINX用户都这么做)。极少的情况下会发生当有许多代的工作者进程等待连接的关闭时会出现问题,但即使是这样,问题也会很快得到解决。

NGINX的二进制升级过程实现了高可用性 - 您可以即时升级软件,而不会出现连接中断,停机或服务中断.

二进制升级过程与配置的优雅重新加载方法相似。新的NGINX主进程与原始主进程并行运行,它们共享监听套接字。这两个进程都是活动的,它们各自的工作进程处理流量。然后,您可以向旧的主进程及其工作者进程通知其正常退出。

整个过程在控制NGINX(http://nginx.org/en/docs/control.html?_ga=2.35636327.714852172.1503922208-47523059.1503406449)中有更详细的描述。

结论

NGINX内部信息图提供了NGINX功能的高级概述,但是这个简单的解释背后是十多年的创新和优化,使NGINX能够在广泛的硬件上提供最佳性能,同时保持现代Web应用程序需要的安全性和可靠性。

原文发布于微信公众号 - IT技术精选文摘(ITHK01)

原文发表时间:2017-09-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏zhangdd.com

ntp服务器查看状态命令ntpstat及ntpq -p 说明及差别详解

NTP服务器【Network Time Protocol(NTP)】是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)...

35320
来自专栏信安之路

线下赛ASP靶机漏洞利用分析

继上次发表 记一次线下赛靶机攻击过程 后,看到反响不错,特此再写一篇,关于一台 ASP 靶机漏洞利用过程。

53800
来自专栏coding

RabbitMQ实战1.消息代理01.消息代理02.安装RabbitMQ03.生产者-消费者模式04.队列操作

肯定不是,这种直接与生产者交易的成本太大了!大到不可承受。因此有了中间商的存在。中间商将生产者与消费者的所有环节都透明化,使最终的交易流程极其简单。

9110
来自专栏FreeBuf

没有外部工具,如何快速发现Windows中毒了

从事应急响应工作几年之后,我认为总结一份快速确定计算机是否被感染木马和病毒的“方法论”是十分有用的。这显然不是那么简单的,可我却发现感染几乎存在于所有不复杂的攻...

22550
来自专栏后端技术探索

大众点评新开源项目-Camel(干货)

Camel 是大众点评开发的软负载一体解决方案,承担了F5四层硬负载后的软负载工作。Camel已成为大众点评网络流量中必不可缺的一层。

22530
来自专栏网站漏洞修补

解决ecshop漏洞修补针对于外贸网站的漏洞修复

由于8月份的ECSHOP通杀漏洞被国内安全厂商爆出后,众多使用ecshop程序源码的用户大面积的受到了网站被篡改,最明显的就是外贸站点被跳转到一些仿冒的网站上去...

18650
来自专栏逢魔安全实验室

渗透基础-SSH后门分析总结

? ? 对于UNIX系统来说,ssh服务端作为最广泛应用的远程管理服务并且有一定对外开放的必然性,必然引起黑客关注,所以ssh类的后门也是uni...

82840
来自专栏安恒信息

Hacking Team 病毒测试环境分析

0x00 前言 安恒研究团队在Hacking Team泄露的文件中除了发现大量的后门、木马等攻击的源码,还发现了两个用于病毒安全性测试的源代码,分别是test...

40450
来自专栏java一日一条

Nginx引入线程池 性能提升9倍

正如我们所知,NGINX采用了异步、事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作...

10310
来自专栏木头编程 - moTzxx

微信公众平台开发[3] —— 微信公众号支付功能(PHP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

41220

扫码关注云+社区

领取腾讯云代金券