窥探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 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

linux系统被入侵后处理实战

作者 李振良 | 来源 51cto 糖豆贴心提醒,本文阅读时间8分钟,文末有秘密! ? 事件背景 操作系统:Ubuntu12.04_x64 运行业务:公司...

4565
来自专栏kevin-blog

ubuntu实现定时弹窗

最近在头条上看到,长期久坐8小时以上会影响生育能力,突然有点慌,作为一个IT工作者,8小时....然后我这人没有喝水的习惯,经常专注电脑,就想着,有没有什么办法...

1071
来自专栏FreeBuf

论如何反击用AWVS的黑客

前言 我的博客经常被师傅们用各种扫描器扫,每天都想尽办法来钓我鱼。虽然这是一种示好方式,但是久了,老是不给回礼就显得不礼貌了。所以我就稍微改造了一下博客。 这篇...

2959
来自专栏木头编程 - moTzxx

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

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

2362
来自专栏BeJavaGod

什么是分布式系统中的幂等性

最近很多人都在谈论幂等性,好吧,这回我也来聊聊这个话题,光看着俩字,一开始的确有点一头雾水,语文不好嘛,词太专业嘛,对吧 现如今我们的系统大多拆分为分布式SOA...

3603
来自专栏zhangdd.com

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

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

2112
来自专栏coding

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

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

711
来自专栏腾讯云安全的专栏

避免 MongoDB 被勒索详解,腾讯云上更安全

2624
来自专栏网站漏洞修补

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

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

1405
来自专栏逍遥剑客的游戏开发

LG WebOS TV降级方法

4819

扫码关注云+社区