vlambda博客
学习文章列表

Nginx之基础概念整理

    Nginx服务器以其功能丰富著称于世。它既可以作为HTTP服务器, 也可以作为反向代理服务器或者邮件服务器;能够快速响应静态页面(HTML) 的请求;支持FastCGI、SSL、VirtualHost、URLRewrite、HTTP Basic Auth、Gzip等大量使用功能;并且支持更多的第三方功能模块的扩展。Nginx提供的基本功能服务从大体上归纳为基本HTTP服务、高级HTTP服务和邮件服务等三大类。

  1. 基本HTTP服务:可以作为HTTP代理服务器和反向代理服务器, 支持通过缓存加速访问, 可以完成简单的负载均衡和容错, 支持包过滤功能, 支持SSL等。

    1. 处理静态文件(如 HTML 静态网页及请求);处理索引文件以及支持自动索引。

    2. 打开并自行管理文件描述符缓存。

    3. 提供反向代理服务,并且可以使用缓存加速反向代理,同时完成简单负载均衡及容错。

    4. 提供远程 FasCGI 服务的缓存机制,加速访问,同时完成简单的负载均衡以及容错。

    5. 使用Nginx模块化特性提供过滤器功能。Nginx基本过滤器包括gzip压缩、ranges支持、chunked响应、XSLT、SSI 以及图像缩放等。其中,针对包含多个 SSI 的页面,经由 FastCGil或反向代理,SSI过滤器可以并行处理。

    6. 支持 HTTP 下的安全套接层安全协议 SSL。

  2. 高级 NTTP 服务:可以进行自定义配置,支持虚拟主机,支持 URL 重定向,持网络监控,支持流媒体传输等。

    1. 支持基于名字和 IP 的虚拟主机设置。

    2. 支持 HTTP/1.0 中的 KEEP-Alive 模式和管线(PipeLined)模型连接。

    3. 支持重新加载配置以及在线升级时,无须中断正在处理的请求。

    4. 自定义访问日志格式,带缓存的日志写操作以及快速日志轮转。

    5. 提供 3xx ~ 5xx 错误代码重定向功能。

    6. 支持重写(Rewrite)模块扩展。

    7. 支持 HTTP DAV 模块,从而为 Htp WebDAV 提供 PUT、DELETE、MKCOL、COPY 以及MOVE 方法。

    8. 支持 FLV 流和 MP4 流传输。

    9. 支持嵌入 Perl 语言。

  3. 邮件服务器:Nginx 作为邮件代理服务器是最早开发这个产品的目的之一,它支持 IMAP/POP3 代理服务功能、支持内部 SMTP 代理服务功能。

    1. 支持使用外部 HTTP 认证服务器重定向用户到 IMAPPOP3 后端,并支持 IMAP 认证方式(LOGN、AUTH LOGINPLAINCRAM-MDS)和 POP3 认证方式(USER/PASS、APOP、AUTH LOGINPLAINCRAM-MD5 )。

    2. 支持使用外部 HTTP 认证服务器认证用户后重定向连接到内部 SMTP 后端,并支持 SMTP认证方式(AUTH LOGINPLAINCRAM-MD5)

    3. 支持邮件代理服务下的安全套接层安全协议 SSL。

    4. 支持纯文本通信协议的扩展协议,STARTTLS。

核心功能

HTTP代理和反向代理

    代理服务和反向代理服务是Nginx服务器作为 Web 服务器的主要功能之一,尤其是反向代理服务是应用十分广泛的功能。在提供反向代理服务方面,Nginx 服务器转发前端请求性能稳定,并且后端转发与业务配置相互分离,配置相当灵活。

    Nginx 服务器的反向代理服务功能并不只有这些,它提供的配套功能相当丰富。首先,它支持判断表达式。通过使用正则表达式进行相关配置,可以实现根据不同的表达式,采取不同的转发策略,相关内容将在下一章节中详细阐述。Nginx 服务器的反向代理服务功能并不只有这些,它提供的配套功能相当丰富。首先,它支持判断表达式。通过使用正则表达式进行相关配置,可以实现根据不同的表达式,采取不同的转发策略。其次,它对后端返回情况进行了异常判断,如果返回结果不正常,则重新请求另—台主机(即将前端请求转向另—后端 IP),并自动剔除返回异常的主机)它还支持错误页面跳转功能。

负载均衡

    负载均衡,一般包含两方面的含义。一方面是,将单一的重负载分担到多个网络节点上做并行处理,每个节点处理结束后将结果汇总返回给用户,这样可以大幅提高网络系统的处理能力;第二个方面的含义是,将大量的前端并发访问或数据流量分担到多个后端网络节点上分别处理,这样可以有效减少前端用户等待响应的时间。Web服务器、FTP服务器、企业关键应用服务器等网络应用方面谈到的负载均衡问题,基本隶属于后一方面的含义。(因此,Nginx 服务器的负载均衡主要是对大量前端访和流量进行分流,以保证前端用户访问效率。可以说,在绝大多数的 Nginx应用中,都会或多或少涉及它的负载均衡服务。

    Nginx 服务器的负载均衡策略可以划分为两大类:即内置策略和扩展策略。内置策略主要包含轮询、加权轮询和 IP hash 三种;扩展策略主要通过第三方模块实现,种类比较丰富,常见的有 url hash、fair等。在默认情况下,内置策略会被编译进 Nginx 内核,使用时只需要在 Nginx服务器配置中设置相关参数即可;扩展策略不会编译进 Nginx 内核,需要手动将第三方模块编译到 Nginx 内核。

  • 轮训策略:

轮询策略比较简单,就是将每个前端请求按顺序(时间顺序或者排列次序)逐一分配到不同的后端节点上,对于出现问题的后端节点自动排除。

  • 加权轮训策略

加权轮询策略,顾名思义,就是在基本的轮询策略上考虑各后端节点接受请求的权重,指定各后端节点被轮询到的几率。加权轮询策略主要用于后端节点性能不均的情况。根据后端节点性能的实际情况,我们可以在 Nginx 服务器的配置文件中调整权值,使得整个网络对前端请求达到最佳的响应能力。

  • IP hash策略

IP hash 策略,是将前端的访问 IP 进行 hash 操作,然后根据 hash 结果将请求分配给不同的后端节点。事实上,这种策略可以看作是一种特殊的轮询策略。通过 Nginx 的实现,每个前端访问 IP 会固定访问一个后端节点。这样做的好处是避免考虑前用户的 Session 在后端多个节点上共享的问题。

  • URL hash策略

扩展策略中的url hash在形式上和IP hash相近,不同之处在于,IP hash策略是对前端访问IP进行了hash操作,而url hash策略是对前端请求的url进行了hash操作。url hash策略的优点在手,如果后端有缓存服务器,它能够提高缓存效率,同时也解决了session 的问题;但其缺点是,如果后端节点出现异常,它不能自动排除该节点。在实际使用过程中如果后端节点出现异常会导致 Nginx返回503错误。

  • Fail 策略

    第三方模块 fair 则是从另—个角度来实现 Nginx 服务器负载均衡策略的,该模块将前端请求转发到一个最近负载最小的后台节点。那么,负载最小怎么判断呢?Nginx通过后端节点对请求的响应时间来判断负载情况。响应时间短的节点负载相对就轻。得出判断结果后,Nginx 就将前端请求转发到选中的负载最轻的节点。

web 缓存

    Squid在Web服务器领域中是一款相当流行的开源代理服务器和Web缓存服务器。作为网页服务器的前置缓存服务器,在很多优秀的站点中,它被用以缓存前端请求,从而提高 Web服务器的性能;而且,它还可以缓存万维网、域名系统或者其他网络搜索等,为一个集体提供网络资源共享服务。

    Nginx 服务器从 0.7.48 版本开始,也支持了和 Squid 类似的缓存功能。Nginx服务器的 Web缓存服务主要由 Prowy Cacteg相关指令集和FeasCGI_ Cache相关指令集构成。经过开源社区的发展到Nginx0.8.32版本以后,Phoxy_Cache 和 FastCGIL Cache 两部分的功能已经比较完善,再配合第三方的ngx_cache purge模块,Nginx服务器已经具备了 Squid所拥有的 Web缓存加速功能和清除指定 URL缓存的功能;同时,Nginx服务器对多核 CPU 的调度比 Squid 更胜一筹,性能高于 Squid,而在反向代理、负载均衡等其他方面,Nginx 也不逊于 Squid。这使得 Ngix 服务器可以同时作为负载均衡服务器和 Web 缓存服务器来使用,基本可以取代 Squid。

Web服务请求处理机制

    Web 服务器和客户端是一对多的关系,Web 服务器必须有能力同时为多个客户端提供服务。一般来说,完成并行处理请求工作有三种方式可供选择:多进程方式、多线程方式和异步方式。

多进程方式

    多进程方式是指,服务器每当接收到一个客户端时,就由服务器主进程生成一个子进程出来和该客户端建立连接进行交互,直到连接断开,该子进程就结束了。多进程方式的优点在于,设计和实现相对简单,各个子进程之间相互独立,处理客户端请求的过程彼此不受到干扰,并且当一个子进程产生问题时,不容易将影响漫延到其他进程中,这保证了提供服务的稳定性。当子线程退出时,其占用资源会被操作系统回收,也不会留下任何垃圾。而其缺点也是很明显的。操作系统中生成一个子进程需要进行内存复制等操作,在资源和时间上会产生一定的额外开销,因此,如果 Web 服务器接收大量并发请求,就会对系统资源造成压力,导致系统性能下降。

多线程方式

    多线程方式和多进程方式相似,它是指,服务器每当接收到一个客户端时,会由服务器主进程派生一个线程出来和该客户端进行交互。

    由于操作系统产生一个线程的开销远远小于产生一个进程的开销,所以多线程方式在很大程度上减轻了 Web 服务器对系统资源的要求。该方式使用线程进行任务调度,开发方面可以遵循一定的标准,这相对来说比较规范和有利于协作。但在线程管理方面,该方式有一定的不足。多个线程位于同一个进程内,可以访问同样的内存空间,彼此之间相互影响;同时,在开发过程中不可避免地要由开发者自己对内存进行管理,其增加了出错的风险。服务器系统需要长时间连续不停地运转,错误的逐渐积累可能最终对整个服务器产生重大影响。

异步方式

    网络通信中的同步机制和异步机制是描述通信模式的概念。在同步机制中,所有的请求在服务器端得到同步,发送方和接收方对请求的处理步调是一致的;在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完成后通知发送方。

同步机制:是指发送方发送请求后,需要等待接收到接收方发回的响应后,才接着发送下一个请求;

异步机制:和同步机制正好相反,在异步机制中,发送方发出一个请求后,不等待接收方响应这个请求,就继续发送下个请求。

阻塞和非阻塞用来描述进程处理调用的方式,在网络通信中,主要指网络套接字 Socket 的阻塞和非阻塞方式,而 Socket 的实质也就是 IO 操作。

阻塞方式:Socket 的阻塞调用方式为,调用结果返回之前,当前线程从运行状态被挂起,一直等到调用结果返回之后,才进入就绪状态,获取 CPU 后继续执行;

非阻塞方式:Socket的非阻塞调用方式和阻塞调用方式正好相反,在非阻塞方式中,如果调用结果不能马上返回,当前线程也不会被挂起,而是立即返回执行下一个调用。

在网络通信中,这两对概念相组合,就会产生四个新的概念,同步阻塞、异步阻塞、同步非阻塞、异步非阻塞。

同步阻塞方式:发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。

同步非阻塞方式:发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的IO操作如果不能马上得到结果,就立即返回,去做其他事情,但由于没有得到请求处理结果不响应发送方,发送方一直等待。一直到IO操作完成后,接收方获得结果响应发送方后,接收方才进入下一次请求过程。在实际中不使用这种方式。

异步阻塞方式:发送方向接收方发送请求后,不用等待响应,可以接着进行其他工作;接方处理请求时进行的IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。这种方式在实际中也不使用。

异步非阻塞方式:发送方向接收方发送请求后,不用等待响应,可以继续其他工作;接收方处理请求时进行的IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方。这种方式是发送方和接收方通信效率最高的一种。

同步与异步是相对于客户端来说的,阻塞与非阻塞是相对于服务 来说的。

Nginx处理机制

    服务器的一个显著优势是能够同时处理大量并发请求。它结合多进程机制和异步机制对外提供服务。异步机制使用的是异步非阻塞方式。

    Nginx 服务器启动后,可以产生一个主进程(master process)和多个工作进程(woniker processes ),其中可以在配置文件中指定产生的工作进程数量。Nginx 服务器的所有工作进程都用于接收和处理客户端的请求。这类似于 Apache 使用的改进的多进程机制,预先生成多个工作进程,等待处理客户端请求。

    每个工作进程使用了异步非阻塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求以后,调用 IO 进行处理,如果不能立即得到结果,就去处理其他的请求;而客户端在此期间 也无需等待响应,可以去处理其他的事情;当 IO 调用返回结果时,就会通知此工作进程;该进程得 到通知,暂时挂起当前处理的事务,去响应客户端请求。

    客户端请求数量增长,网络负载繁重时,Nginx 服务器使用多进程机制能够保证不增长对系统资源的压力;同时使用异步非阻塞方式减少了工作进程在 IO 调用上的阻塞延迟,保证了不降低对请求的处理能力。

工作原理

    Nginx 服务器启动后,产生一个主进程(mpaster progess),主进程执行一系列工作后产生一个或者多个工作进程(woniker processes)。主进程主要进行 Nginx 配置文件解析、数据结构初始化、模块配置和注册、信号处理,网络监听生成、工作进程生成和管理等工作;工作进程主要进行进程初始化、模块调用和请求处理等工作,是Nginx 服务器提供服务的主体。

在客户端请求动态站点的过程中,Nginx 服务器还涉及和后端服务器的通信。Nginx 服务器将接收到的 Web 请求通过代理转发到后端服务器,由后端服务器进行数据处理和页面组织,然后将结果返回。

    另外,Nginx 服务器为了提高对请求的响应效率,进一步降低网络压力,采用了缓存机制,将历史应答数据缓存到本地。在每次 Nginx服务器启动后的一段时间内,会启动专门的进程对本地缓存的内容重建索引,保证对缓存文件的快速访问。

进程管理

    Nginx 服务器有三大类进程:—类是主进程,另一类是由主进程生成的工作进程,还有刚才提到的用于为缓存文件建立索引的进程。

主进程(Master Process)

    Nginx 服务器启动时运行的主要进程。它的主要功能是与外界通信和对内部其他进程进行管理,具体来说有以下几点:

  • 读取 Nginx 配置文件并验证其有效性和正确性。

  • 建立、绑定和关闭 Socket。

  • 按照配置生成、管理和结束工作进程。

  • 接收外界指令,比如重启、升级及退出服务器等指令。

  • 不中断服务,实现平滑重启,应用新配置。

  • 不中断服务,实现平滑升级,升级失败进行回滚处理。

  • 开启日志文件,获取文件描述符。

  • 编译和处理 Perl 脚本。

工作进程(Worker Process)

    由主进程生成,生成数量可以通过 Nginx 配置文件指定,正常情况下生存于主进程的整个生命周期,该进程的主要工作有以下几项:

  • 接收客户端请求。

  • 将请求依次送人各个功能模块进行过滤处理。

  • IO调用,获取响应数据。

  • 与后端服务器通信,接收后端服务器处理结果。

  • 数据缓存,访问缓存索引、查询和调用缓存数据。

  • 发送请求结果,响应客户端请求。

  • 接收主程序指令,比如重启、升级和退出等指令。

    工作进程完成的工作还有很多,我们在这里列出了主要的几项。从这些工作中可以看到,该进程是Nginx 服务器提供 Web 服务、处理客户端请求的主要进程,完成了 Nginx 服务器的主体工作。因此,在实际使用中,作为服务器管理者,我们应该重点监视工作进程的运行状态,保证 Nginx 服务器对外提供稳定的 Web 服务。

缓存进程

    主要由缓存索引重建(Cache Loader)和缓存索引管理(Cache Manager)两类进程完成工作。缓存索引重建进程是在 Nginx 服务启动一段时间之后(默认是1 分钟)由主进程生成,在缓存元数据重建完成后就自动退出;缓存索引管理进程一般存在于主进程的整个生命周期,负责对缓存索引进行管理。

    缓存索引重建进程完成的主要工作是,根据本地磁盘上的缓存文件在内存中建立索引元数据库。该进程启动后,对本地磁盘上存放缓存文件的目录结构进行扫描,检查内存中已有的缓存元数据是否正确,并更新索引元数据库。缓存索引管理进程主要负责在索引元数据更新完成后,对元数据是否过期做出判断。这两个进程维护的内存索引元数据库,为工作进程对缓存数据的快速查询提供了便利。

进程交互

    Nginx服务器在使用Master-Worker模型时,会涉及主进程与工作进程(Master-Worker)之间的交互和工作进程(Worker-Woniker)之间的交互。这两类交互都依赖于管道(channel)机制,交互的准备工作都是在工作进程生成时完成的。

Master-Worker交互

    工作进程是由主进程生成的(使用了fork函数)。Nginx.服务器启动以后,主进程根据配置文件决定生成的工作进程的数量,然后建立一张全局的工作进程表用于存放当前未退出的所有工作进程。

    在主进程生成工作进程后,将新生成的工作进程加入到工作进程表中,并建立一个单向管道并将其传递给该工作进程。该管道与普通的管道不同,它是由主进程指向工作进程的单向管道,包含了主进程向工作进程发出的指令、工作进程 ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。

    主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令。每个工作进程都有能力捕获管道中可读事件,当管道中有可读事件时,工作进程从管道读取并解析指令,然后采取相应的措施。这样就完成了 Master-Worker 的交互。

Worker-Worker交互

    Wonker-Worker交互在实现原理上和Master-Worker 交互基本是一样的。只要工作进程之间能够得到彼此的信息,建立管道,即可通信。由于工作进程之间是相互隔离的,因此一个进程要想知道另—个进程的信息,只能通过主进程来设置了。

    为了达到工作进程之间交互的目的,主进程在生成工作进程后,在工作进程表中进行遍历,将该新进程的 ID 以及针对该进程建立的管道句柄传递给工作进程表中的其他进程,为工作进程之间的交互做准备。每个工作进程捕获管道中可读事件,根据指令采取响应的措施。

    当工作进程 W1 需要向 W2 发送指令时,首先在主进程给它的其他工作进程信息中找到 W2 的进程 ID,然后将正确的指令写人指向 W2 的通道。工作进程 W2 捕获到管道中的事件后,解析指令并采取相应措施。这样就完成了 Worker-Worker 交互。