IDC资讯

质量为本、客户为根、勇于拼搏、务实创新

< 返回IDC资讯列表

nginx实现高性能和可扩展性的方法

发布时间:2022-05-31

本文是为了和大家分享nginx实现高性能和可扩展性的方法的内容。桂哥网络觉得很实用,就分享给大家参考,跟着桂哥网络看了看。

NGINX的整体架构的特点是由一组进程协同工作:

主进程:负责执行特权操作,如读取配置文件、绑定套接字以及创建/通知信令子进程。

工作流程:负责接收和处理连接请求,读写磁盘,与上游服务器通信当NGINX活跃时,只有工作流程繁忙。

缓存加载进程:负责将磁盘缓存加载到内存中。这个过程在启动时运行,然后退出。

缓存管理器进程:负责对磁盘缓存的数据进行排序,确保不越界。该过程将间歇运行。

NGINX能够实现高性能和可扩展性的关键取决于两个基本的设计选型:

尽可能限制工作进程的数量,从而减少上下文切换带来的开销。默认和推荐的配置是让每个CPU内核对应一个工作进程,从而高效利用硬件资源。

工作进程使用一个线程,并以非阻塞方式处理多个并发连接。

NGINX的每个工作进程通过状态机处理多个连接请求,这个状态机被实现为非阻塞的工作方式:

每个工作进程需要处理几个套接字,包括监听套接字或连接套接字。

当侦听套接字接收到新请求时,它会打开一个新的连接套接字来处理与客户端的通信。

当事件到达连接套接字时,工作进程快速完成响应,并处理从任何其他套接字新接收的事件。

加勒特说,NGINX选择这种设计是为了使其从根本上区别于其他Web服务器。通常,Web服务器会选择将每个连接分配给一个独立线程的模式,这使得处理多个连接变得容易,因为每个连接可以被视为包含多个步骤的线性序列,但这将导致上下文切换的开销。事实上,在大多数情况下,工作线程被阻塞,等待客户端或其他上游服务器。当试图执行输入/输出操作的并发连接/线程的数量超过某个阈值时,或者内存耗尽时,就会出现上下文切换的成本。

另一方面,NGINX的设计是为了防止工作进程阻塞网络流量,除非没有工作要做。此外,每个新连接仅消耗少量资源,仅包括一个文件描述符和少量工作进程内存。

一般来说,系统调优后,NGINX的每个工作流程都可以处理上百个HTTP并发连接。

深入NGINX:我们如何设计它的性能和扩展性

NGINX之所以性能如此出众,是因为它背后的设计。许多网络服务器和应用服务器使用简单的线程或基于进程的架构,而NGINX作为一个复杂的事件驱动架构脱颖而出,它可以支持现代硬件上的数千个并发连接。

在NGINX内部,信息图涉及从高级流程架构的挖掘到NGINX的单个流程处理和多个连接的说明。今天桂哥网络解释了工作的细节。

设置场景——NGINX进程模型

设定场景?NGINX过程模型

为了更好地理解设计,你需要理解NGINX是如何工作的。NGINX有一个主进程(执行读取配置和绑定端口等特权操作)和一系列的工作进程和辅助进程。

在这个四核服务器,中,NGINX主进程创建了四个工作进程和两个缓存助手进程来管理磁盘上的内容缓存。

为啥架构很重要?

建筑为啥重要?

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

可以同时使用更多的电脑内核。

线程和进程使并行操作变得容易(例如,同时处理多个连接)。

进程和线程都消耗资源。它们都使用内存等OS资源,导致频繁的内核切换(一种叫做上下文切换的操作)。大多数现代服务器可以同时处理数百个小的活动线程或进程,但一旦内存耗尽或高I/O负载导致大量上下文切换,服务器的性能将严重下降。

对于网络应用程序,通常为每个连接分配一个线程或进程。这种体系结构易于实现,但是当应用程序需要处理数千个并发连接时,这种体系结构的可伸缩性会有问题。

NGINX是如何工作的?

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内部的工作进程

Inside the NGINX Worker Process

每一个NGINX的工作进程都是NGINX配置(NGINX configuration)初始化的,并被主进程设置了一组监听套接字(listen sockets)。

NGINX工作进程会监听套接字上的事件(accept_mutex和kernel socket sharding),来决定什么时候开始工作。事件是由新的连接初始化的。这些连接被会分配给状态机(state machine)——HTTP状态机是最常用的,但NGINX还为流(原生TCP)和大量的邮件协议(SMTP,IMAP和POP3)实现了状态机。

状态机本质上是一组告知NGINX如何处理请求的指令。大多数和NGINX具有相同功能的web服务器也使用类似的状态机——只是实现不同。

调度状态机

Scheduling the State Machine

把状态机想象成国际象棋的规则。每个HTTP事务(HTTP transaction)都是一局象棋比赛。棋盘的一边是web服务器——坐着一位可以迅速做出决定的大师级棋手。另一边是远程客户端——在相对较慢的网络中,访问站点或应用程序的web浏览器。

然而,比赛的规则可能会很复杂。例如,web服务器可能需要与各方沟通(代理一个上游的应用程序),或者和认证服务器交流。web服务器的第三方模块也可以拓展比赛规则。

阻塞状态机

A Blocking State Machine

回忆一下我们之前对进程和线程的描述:是一组操作系统可调度的、运行在CPU内核上的独立指令集。大多数web服务器和web应用都使用一个连接 /一个进程或一个连接/一个线程的模型来进行这局国际象棋比赛。每个进程或线程都包含一个将比赛玩到最后的指令。在这个过程中,进程是由服务器来运行的,它的大部分时间都花在“阻塞(blocked)”上,等待客户端完成其下一个动作。

1.web服务器进程(web server process)在监听套接字上,监听新的连接(客户端发起的新比赛)。

2.一局新的比赛发起后,进程就开始工作,每一步棋下完后都进入阻塞状态,等待客户端走下一步棋。

3.一旦比赛结束,web服务器进程会看看客户是不是想开始新的比赛(这相当于一个存活的连接)。如果连接被关闭(客户端离开或者超时),web服务器进程会回到监听状态,等待全新的比赛。

记住重要的一点:每一个活跃的HTTP连接(每局象棋比赛)都需要一个专用的进程或线程(一位大师级棋手)。这种架构非常易于扩展第三方模块 (“新规则”)。然而,这里存在着一个巨大的不平衡:一个以文件描述符(file descriptor)和少量内存为代表的轻量级HTTP连接,会映射到一个单独的进程或线程——它们是非常重量级的操作系统对象。这在编程上是方便的,但它造成了巨大的浪费。

NGINX是真正的大师

NGINX is a True Grandmaster

也许你听说过车轮表演赛,在比赛中一个象棋大师要在同一时间对付几十个对手。

Kiril Georgiev在保加利亚首都索菲亚同时对阵360名棋手,最终取得284胜,70平,6负的战绩。

这就是NGINX工作进程玩“国际象棋”的方式。每一个工作进程都是一位大师(记住:通常情况下,每个工作进程占用一个CPU内核),能够同时对战上百棋手(实际上是成千上万)。

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

2.事件发生在套接字上,工作进程会处理这些事件。

●监听套接字上的事件意味着:客户端开始了一局新的游戏。工作进程创建了一个新的连接套接字。

●连接套接字上的事件意味着:客户端移动了棋子。工作进程会迅速响应。

工作进程从不会在网络上停止,它时时刻刻都在等待其“对手”(客户端)做出回应。当它已经移动了这局比赛的棋子,它会立即去处理下一局比赛,或者迎接新的对手。

为啥它会比阻塞式多进程的架构更快?

Why Is This Faster than a Blocking, Multi-Process Architecture?

NGINX的规模可以很好地支持每个工作进程上数以万计的连接。每个新连接都会创建另一个文件描述符,并消耗工作进程中少量的额外内存。每一个连接的额外消耗都很少。NGINX进程可以保持固定的CPU占用率。当没有工作时,上下文切换也较少。

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

如果想了解更多,请查看由NGINX公司发展和联合创始人副总裁Andrew Alexeev编写的有关NGINX体系结构的文章。

通过适当的系统调优,NGINX能大规模地处理每个工作进程数十万并发的HTTP连接,并且能在流量高峰期间不丢失任何信息(新比赛开始)。

配置更新和NGINX升级

Updating Configuration and Upgrading NGINX

仅包含少量工作进程的NGINX进程架构,使得配置、甚至是二进制文件本身的更新都非常高效。

更新NGINX的配置,是一个非常简单的、轻量级的、可靠的操作。运行nginx ?s reload命令即可,该命令会检查磁盘上的配置,并给主进程发送一个SIGHUP信号。

当主进程接收到SIGHUP信号后,会做两件事:

1.重新加载配置,fork一套新的工作进程。这些新的工作进程会立即开始接受连接和处理流量(traffic)(使用新的配置)。

2.发出信号,通知旧的工作进程安静地退出。这些旧进程不会再接受新的连接了。只要它们处理的HTTP请求结束了,它们就会干净地关闭连接。一旦所有的连接都被关闭,工作进程也就退出了。

这个过程会导致CPU占用率和内存使用的一个小高峰,但相比于从活动连接中加载资源,这个小高峰可忽略不计。你可以在一秒内重新加载配置多次。极少情况下,一代又一代工作进程等待连接关闭时会出现问题,但即便出现问题,它们也会被立即解决掉。

NGINX的二进制升级过程更加神奇——你可以飞速地升级NGINX本身,服务器不会有任何的丢连接、宕机、或服务中断等情况。

二进制升级过程与配置更新相似。新的NGINX主进程与原来的主进程并行,它们共享监听套接字。两个进程都是活跃的(active),它们各自的工作进程处理各自的流量(traffic)。然后,你可以通知旧的主进程与其工作进程完美退出。

在Controlling NGINX中,整个过程有更详细的描述。

感谢各位的阅读!关于“nginx实现高性能和可扩展性的方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!


TikTok千粉号购买平台:https://tiktokusername.com/