NGINX在web性能上的表现尤为出众,这完全得益于其设计方式,许多web和应用服务器都是基于线程或进程这种简单的架构,NGINX用了一种精妙的事件驱动架构,在现代的硬件上,它可以处理成千上万的并发连接。

Inside NGINX中的信息图对高级别的进程架构和NGINX如何在单个进程中处理多个连接进行了深入探讨。本文更进一步地阐述了NGINX的所有工作原理。

背景——NGINX进程模型

要更好的理解这个设计,需要熟悉NGINX的运行过程。NGINX有一个主进程(该进程执行一些特权操作,例如读取配置以及绑定端口)以及若干worker进程和helper进程。

在这个4核服务器上,NGINX主进程创建了4个worker进程以及一对用来管理磁盘内容缓存的缓存helper进程。

架构为什么重要?

任何Unix应用的基础都是线程或进程。(从Linux操作系统的角度看,线程和进程几乎是一样的;最大的区别是内存共享的度。)一个线程或进程是一组自包含的指令,这些指令可由操作系统调度到某个CPU核心上运行。大部分复杂应用并行运行多个线程或进程一般有两个原因:

  • 可以同时使用多个CPU核心。
  • 线程和进程让并行操作变得简单(例如,同时处理多个连接)。

进程和线程会消耗资源。每个进程或线程都会使用内存以及其他操作系统资源,他们都需要切换CPU(称作上下文切换)。大部分现代的服务器都能同时处理几百个小的、活动的线程或进程,但是,一旦内存耗尽或是遇到高I/O负载导致大量上下文切换时性能就会急剧下降。

常规的网络应用设计都是为每个连接分配一个线程或进程。这种架构简单且容易实现,但是,当应用需要同时处理成千上万的连接时,扩展性就不好了。

NGINX是怎么运行的?

NGINX用了一个可预测的进程模型,支持众多硬件:

  • 主进程执行一些特权操作,比如读取配置以及绑定端口,然后创建少数子进程(下面的三种类型)。
  • 缓存加载进程在启动时运行,用于将磁盘上的缓存加载到内存中,随后退出。对这个进程的调度很保守,所以其资源需求比较低。
  • 缓存管理进程会周期性地运行,从磁盘缓存中删除条目以保证缓存没有超过配置的大小。
  • worker进程做了所有的工作!它们处理网络连接,从磁盘读取内容或往磁盘中写入内容,以及与上游服务器通信。

大部分场景中推荐的NGINX配置是 —— 每个CPU核心运行一个worker进程 —— 以充分利用硬件资源。在配置中加入worker_processes auto指令即可:

worker_processes auto;

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

每个worker进程都是单线程的并且是独立运行的,它们捕获新的连接然后进行处理。进程之间的共享缓存数据、会话持久数据以及其它共享资源的通信通过共享内存实现。

深入理解NGINX Worker进程

每个worker进程都是用NGINX配置进行初始化的,并且由主进程提供了一组监听套接字。

NGINX worker进程从等待监听套接字上的事件开始(accept_mutex和内核套接字切分(kernel socket sharding))。事件由新进来的连接进行初始化。这些连接被分配给一个状态机 —— HTTP状态机是最常用的,但NGINX也为流(原始TCP)流量以及一些邮件协议(SMTP,IMAP和POP3)实现了状态机。

状态机本质上是一组指令,由它们告诉NGINX如何处理请求。大部分执行与NGINX相同方法的web服务器也用的类似的状态机 —— 区别在于实现。

状态机的调度

将状态机想象成象棋规则。每个HTTP事务就是一盘象棋游戏。棋盘的一侧是web服务器 —— 一个可以快速做决定的象棋大师。另一侧是远程客户端 —— 正在相对较慢的网络中访问站点或应用的web浏览器。

然而,游戏的规则可能会非常复杂。比如,web服务器也许要与其它方(代理到上游应用)进行交流或是要与认证服务器对话。web服务器中的第三方模块甚至还可能扩展游戏规则。

阻塞模式的状态机

前面我们提到,一个线程或进程是一组自包含的指令,这些指令可由操作系统调度到某个CPU核心上运行。大部分web服务器以及web应用使用的是每个连接分配一个进程或每个连接分配一个线程的模式来处理的。每个进程或线程都包含了从开始到结束需要执行的指令。在服务器运行进程期间,大部分时间都是“阻塞的” —— 等待客户端完成其下一个动作。

  1. web服务器进程在监听套接字上监听新的连接(由客户端初始化的新游戏)。
  2. 当新游戏准备好后,就开始游戏,每个动作之后都会阻塞,等待客户端的响应。
  3. 一旦游戏结束,web服务器进程可能还要等等看是否这个客户端需要发起一轮新的游戏(这相当于keepalive连接)。如果连接被关闭(客户端离开或超时),web服务器进程返回去监听新的游戏请求。

关键的一点在于每个活动的HTTP连接(每盘象棋游戏)都需要一个专门的进程或线程(一个象棋大师)。这种架构在扩展第三方模块(“新的规则”)时非常简单方便。然而,存在一个巨大的失衡问题:相当轻量级的HTTP连接,本由一个文件描述符和少量的内存来表示,却映射到了一个单独的线程或进程这种非常重量级的操作系统对象。编程是便利了,但却是个很大的浪费。

NGINX是真大师

也许你已经听过simultaneous exhibition游戏,一个象棋大师同时与几十个对手对战。

这就是NGINX worker进程下“象棋”的方式。每个worker进程(记住 —— 通常是每个CPU核心一个worker进程)都是一个大师,可以同时处理几百盘(实际上是成千上万)游戏。

  1. worker进程等待监听和连接套接字上的事件。
  2. 套接字上发生事件后,worker进程开始进行处理:
    • 监听套接字上的事件意味着有个客户端发起了一盘新的象棋游戏。worker进程创建出一个新的连接套接字。
    • 连接套接字上的事件意味着客户端开始有新的动作了。worker进程就迅速响应。

worker进程永远不会因为网络拥堵而阻塞来等待“对手”(客户端)的响应。当处理完一个动作,worker进程立即去处理其他游戏中等待处理的动作,或是迎接新玩家的到来。

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

NGINX的可伸缩性非常好,每个worker进程可以支撑成千上万个连接。每个新的连接会创建一个文件描述符以及消耗worker进程中少量的额外内存。每个连接的额外开销极少。NGINX进程可以绑定到CPU。上下文切换是比较罕见的,只有没有任务要处理时才会发生。

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

更多细节解释,看看这篇有关NGINX架构的文章。

通过适当的系统调优,NGINX worker进程可以处理成千上万的并发HTTP连接,能够承受流量峰值(新游戏蜂拥而至)还不会错过一个请求。

配置更新与NGINX升级

NGINX这种使用少数worker进程的进程架构,可以非常高效的进行配置更新甚至是更新NGINX介质本身。

更新NGINX配置是个很简单、轻量级且可靠的操作。通常只是意味着去运行一下nginx –s reload命令,这个命令会去检查磁盘上的配置,给主进程发送一个SIGHUP信号。

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

  1. 重新加载配置,然后fork出一组新的worker进程。这些新的worker进程会立马开始接受连接并处理(用的是新的配置)。
  2. 发信号让旧的worker进程优雅退出。旧的worker进程停止接受新的连接。一旦每个当前的HTTP请求完成,worker进程将利索地结束连接(也就是,没有lingering keeplive)。一旦所有连接都关闭了,worker进程就可以退出了。

这个配置加载进程会造成CPU和内存使用上的一个小峰值,但相比活动的连接带来的资源负载,这是极其微小的。可以每秒重新加载配置多次(有许多NGINX用户的确是这么干的)。多代NGINX worker进程都在等待连接关闭极少会造成问题,但即便有问题也会很快解决。

NGINX介质升级过程达到了高可用性的标准 —— 可以直接对线上运行的NGINX升级,而不会丢失任何连接,也不会有停机时间与服务中断。

介质升级过程与重新加载配置的过程类似。一个新的NGINX主进程会与旧的主进程并行运行,它们共享监听套接字。两个进程都是活动的,并且各自对应的worker进程都还在处理请求。随后可以发信号让旧的主进程及其worker进程优雅退出。

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

总结

这篇深入NGINX信息图从高层次概述了NGINX的功能,但是在这个简单解释的背后,是十多年的创新与优化,才使NGINX在保证安全和可靠性的同时,在众多硬件上都能发挥出最佳性能。

如果想更多地了解NGINX的优化,下面这些资源不错:

  • Installing and Tuning NGINX for Performance (webinar; slides at Speaker Deck)
  • Tuning NGINX for Performance
  • The Architecture of Open Source Applications – NGINX
  • Socket Sharding in NGINX Release 1.9.1 (using the SO_REUSEPORT socket option)

[译]深入 NGINX: 为性能和扩展所做之设计相关推荐

  1. NGINX应用性能优化指南(第六部分):连接优化

    [编者的话]本文是"NGINX应用性能优化指南"系列文章的第六篇,主要介绍了如何从连接优化方面实现NGINX应用性能优化.\ 注:本文最初发布于MaxCDN博客,InfoQ中文站在 ...

  2. 为什么Nginx的性能要比Apache高很多?

    为什么Nginx的性能要比Apache高很多? 这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的sele ...

  3. nginx php7提速,nginx+php7-fpm 性能提升几倍跟踪实践结果并优化

    nginx+php7-fpm 性能提升几倍跟踪实践结果并优化 nginx+php7-fpm 性能提升几倍,跟踪实践结果并优化 历史ubuntu服务器使用的apache+php5,现在使用nginux+ ...

  4. 为什么Nginx的性能要比Apache高得多?

    为什么Nginx的性能要比Apache高得多?这得益于Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的selec ...

  5. Nginx配置性能优化(转)

    大多数的Nginx安装指南告诉你如下基础知识--通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了.而且,在大多数情况下,一个常规安装的nginx对你的网站来说已经能 ...

  6. Nginx配置性能优化的方法

    大多数的Nginx安装指南告诉你如下基础知识--通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了.而且,在大多数情况下,一个常规安装的Nginx对你的网站来说已经能 ...

  7. 测试nignx php请求并发数,Nginx 高级篇(八)ab 压力测试即 nginx 的性能统计模块...

    我们总得要对自己的网站或者接口做压力测试的,总不能写好了代码不做测试就上线啊,谁知道你的网站或者接口能承受多少的并发和访问量,压力测试我们可以使用apache的ab小工具来搞或者使用github上提供 ...

  8. 中小型超市系统中的分类/产品属性/扩展属性的数据库设计

    中小型商城系统中的分类/产品属性/扩展属性的数据库设计 正文: 之前发表过一篇"商城系统中[商品扩展属性]的表单生成及客户端验证",部分童鞋对于后台数据库的设计比较感兴趣,于是今天 ...

  9. 数据库的这些性能优化,你做了吗

    转载自   数据库的这些性能优化,你做了吗 在互联网项目中,当业务规模越来越大,数据也越来越多,随之而来的就是数据库压力会越来越大. 我们可能会采取各种方式去优化,比如之前文章提到的缓存方案,SQL优 ...

最新文章

  1. P3952 NOIP2017 时间复杂度
  2. BB之Uncaught exception:net.rim.device.api....错误的解决之道
  3. k8s安装工具:sealos设计原理及离线包结构分析
  4. 系统设计原则的重要性_设计原则的重要性及其对好的设计的影响
  5. ARIMA模型建模步骤
  6. Java整数类的compareTo()方法和示例
  7. 关闭 IOS8 最近使用 最近联系人
  8. 人生---新---起点……
  9. 多领域中文语音识别数据集 WenetSpeech 正式发布——有效下载教程
  10. java quartz定时_Java初级面试题之Quartz定时任务
  11. 隐藏在计算机软硬件,隐匿在计算机软硬件背后的语言
  12. 家用投影机预埋布线图_家庭影院装修如何布线(装修前必看·附图)
  13. Please change your current directory to a writable directory outside of the MATLAB installation area
  14. Python小爬虫之协程爬虫快速上手
  15. c语言怎么取字符串首字母,C语言 字符串首字母转换成大写简单实例
  16. linux系统日志文件介绍
  17. css中一个一个字显示效果
  18. iap进入app后 按复位按钮进入iap无法再进app问题
  19. Openlayers 图层的常用操作
  20. [Bug集合]ASSERTION FAILED Call to publish() on an invalid Publisher

热门文章

  1. javascript---淡入淡出的效果轮换转播后续
  2. 探寻C++最快的读取文件的方案
  3. IDES SAP SEM 4.0/SAP BW 3.50 笔记本安装手册
  4. Linux 基金会成立持续交付基金会
  5. The log scan number (620023:3702:1) passed to log scan in database 'xxxx' is not valid
  6. selenium+python自动化82-只截某个元素的图
  7. PHP在线支付类集锦(银联支付宝手机支付宝微信等)
  8. [转]Linux下的动态连接库及其实现机制
  9. 主域控制器硬件损坏,你会怎么解决?(四)
  10. 负载均衡和故障转移的使用案例