Nginx架构概述

来源:互联网 发布:linux用户修改密码 编辑:程序博客网 时间:2024/05/16 02:48

原文链接

传统的基于进程和线程的模型在处理并发连接的时候针对每个连接会调用一个独立的进程或线程,并且阻塞在网络或I/O操作上面。根据应用程序的不同,它们对内存和CPU的使用效率非常低。产生一个新的进程或线程需要一个新的运行时环境,包括堆和栈的分配,以及运行时的上下文。因此需要额外的CPU开销来创建这些环境,过多的线程以及上下文切换最终会导致性能的下降。所有这些状况在Apache上都可以见到。因此,这是一个在提供丰富普遍适用的功能特性以及服务器资源优化之间的权衡。 

Nginx从一开始就旨在成为一个专门的工具来提高服务器的性能,密度和以及资源利用率,同时保证网站的动态增长,因此Nginx采取了不同的模型。它的设计灵感来自于各种各样的操作系统中不断发展的基于事件的机制。因此,模块化,事件驱动,异步,单线程,非阻塞的架构成为了nginx的基石。 

Nginx大量使用多路复用和事件通知,并将特定任务分配到独立的进程。Nginx通过一个高效率的、数量有限的单线程进程的运行环--worker来处理连接。正是在内部有这些worker,Nginx才能处理每秒成千上万的并发连接。 

代码结构:

Nginx的worker代码包括核心(core)模块和功能(functional)模块。Nginx的核心模块式负责维持运行环和在每个请求处理阶段执行适当部分模块代码。模块构成了大部分展示和应用层的功能。模块读取和写入到网络和存储设备,转换内容,出站过滤,应用服务端包含的动作,当代理激活时向上游服务器传递请求。 

Nginx的模块架构允许开发者在无需改动Nginx核心的情况下来扩展web服务器的特性集合。Nginx模块有不同功能,如核心模块,事件模块,阶段处理模块,协议模块,变量处理模块,过滤器模块,上游模块和负载均衡模块。 

当处理各种各样诸如接受,处理,管理网络连接和内容检索等动作时,Nginx使用事件通知机制和Linxu,Solaris以及类BSD操作系统中大量的磁盘I/O性能优化机制,诸如kqueue,epoll,event ports。我们的目标是向操作系统提供尽可能多的入站和出战流量,磁盘操作,socket的读取和写入,超时等及时的异步反馈信息(hints)。Nginx对多路复用和高级I/O操作使用不同的方法,很大程度上是针对运行在类Unix操作系统上的优化。


Worker模型

如前所述,Nginx不会对每个连接产生一个新的进程或线程。相反,worker从一个共享的“监听”socket接受新的请求,在每个worker内部执行高效的运行环来处理成千上万的连接。在Nginx内部没有对连接的专门仲裁和分发;这些工作是有操作系统内核来完成的。在启动时,一组初始的监听socket被创建。在处理HTTP请求和响应的时候,worker不断的接受,读取,写入这些socket。 

运行环是nginx worker代码里最复杂的部分。它包含了复杂的内部调用并在很大程度上依赖异步任务处理的思想。异步操作是通过模块化,事件通知,回调函数和微调定时器的广泛使用来实现的。总体而言,关键的思想就是尽可能的使用非阻塞。Nginx只有在没有磁盘没有足够的存储性能时才会阻塞。 

由于Nginx对每个连接不会产生一个进程或线程,因此在绝大多数情况下,内存使用率非常保守并且非常的高效。因为没有持续的进程或线程的创建和销毁模式,所以Nginx也非常节省CPU的资源。Nginx所做的工作就是检查网络和存储的状态,初始化新的连接并将其接入运行环,直到异步完成处理时才将该连接释放并将其移除运行环。Nginx对系统调用的谨慎使用和对诸如pool,slab memory分配器接口支持的精准实现,使得Nginx即使在极度恶劣的工作环境中都能够占用较少的CPU资源。 

由于Nginx会产生多个worker来处理连接,它在多核系统上扩展的很好。一般情况下,一个核心对应一个worker可以充分利用多核架构,并且阻止了线程竞争和锁死。在单线程的worker进程下不会产生资源匮乏,并且资源控制机制是独立的。该模型还允许在物理存储设备上有更多的扩展性,得到更多的磁盘利用率,避免的磁盘I/O阻塞。其结果是,服务器的资源能够被在共享工作平台上的多个worker更有效的利用。 

对于不同磁盘使用率和CPU负载模式,Nginx应该可以调整worker的数目。建议如下:如果负载模式是CPU密集的(如大量的TCP/IP处理,SSL或者压缩),worker的数量应该和CPU核心的数量一致。如果负载模式是磁盘I/O密集的(例如存储不同内容的服务,大量的代理),worker的数量可能是CPU核心数目的1.5到2倍。 

目前Nginx面临的一个大问题是如何解决磁盘I/O的阻塞问题。当前版本中,如果没有足够的存储性能来满足worker的磁盘操作,worker会阻塞在磁盘的读取和写入上。一系列的机制和配置文件中的指令来减轻磁盘I/O阻塞的情况。值得注意的是,选项sendfile和AIO的组合可以大幅度提升磁盘性能。Nginx应该可以根据数据集的大小和可用的内存,以及底层的存储架构进行定制的安装。Nginx中的另一个问题是对嵌入脚本的支持。 

Nginx进程角色

Nginx在内存中运行着多个进程;有一个主进程和几个worker进程。还有一些特殊目的的进程,特别是缓存加载进程和缓存管理进程。在1.x的Nginx版本中,所有的进程都是单线程的。所有的进程基本上都使用内存共享来进行进程间通信。主进程以root用户运行,缓存加载进程、缓存管理和worker进程以低特权用户运行。 

主进程负责执行以下任务:

  • 读取并验证配置
  • 创建,绑定并关闭套接字
  • 开始、终止并保持配置中的work进程数目
  • 在线重新配置
  • 在线升级
  • 重新打开日志文件
  • 编译内嵌的Perl脚本 

Worker进程接受、处理来自客户端的连接,并提供反向代理和过滤功能以及几乎所有其它nginx能够完成的任务。为了监控一个Nginx接口,系统管理员应该对worker进行监控,因为它们是反应了实际中Web服务器的日常操作过程。 

缓存加载进程负责检查磁盘上的缓存项并用缓存元数据填充Nginx内存数据库。从本质上讲,缓存加载进程替Nginx提供一个存储在磁盘上目录结构中的文件实例。当需要使用时,它遍历目录,检查缓存元数据,更新共享内存中的相关条目,准备好一切。当它退出时一切都会被清理。 

缓存管理进程主要负责缓存过期和失效。在Nginx操作的时候它驻留在内存中,如果失败了由主进程启动。 

Nginx缓存概述:

Nginx中的缓存是在文件系统上实现的一个阶层存储形式。缓存的键值是可配置的,不同的特定请求参数可以用来控制进入缓存。缓存键值和元数据都存储在共享内存中,缓存加载进程,缓存管理进程和worker进程都能访问。目前的版本中除了操作系统的虚拟文件系统的优化机制外,在内存中没有缓存任何文件。每个缓存的响应都放在文件系统的不同文件里。通过Nginx的配置指令可以控制阶层结构。当响应被写入缓存目录结构时,文件的路径和名字都来自代理URL的MD5哈希。 

放置在缓存中的内容过程如下:当Nginx读取来自从上游服务器的响应时,内容首先被写入到一个缓存目录结构之外的临时文件中。当Nginx完成该请求的处理时,它会重新命名该临时文件并将其移动到缓存目录下。如果代理的临时文件目录在另外一个文件系统上,则会复制该文件,因此建议在同一个文件系统上保存临时和缓存目录(注:这样就不需要额外的拷贝)。当明确需要删除文件时,从缓存目录中删除文件也是非常安全的。有一些第三方的扩展模块使得Nginx可以远程控制缓存内容,进一步的计划是将该功能融入主分支内。


原创粉丝点击