前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >窥探Nginx内部实现:如何为性能和规模进行设计

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

作者头像
用户1263954
发布2018-01-30 15:21:54
9640
发布2018-01-30 15:21:54
举报
文章被收录于专栏:IT技术精选文摘

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应用程序需要的安全性和可靠性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT技术精选文摘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档