关于nginx架构探究(4)
- 事件管理机制
Nginx是以事件驱动的,也就是说Nginx内部流程的向前推进基本都是靠各种事件的触发来驱动,否则Nginx将一直阻塞在函数epoll_wait()或suspend函数,Nginx事件一般分为I/O事件和定时事件,当一个事件到来后,监听FD的工作进程就开始处理事件,并执行回调函数,开始处理与响应。
I/O多路复制机制,Nginx封装了各种系统平台下的I/O事件处理机制,使得在跨平台时高效运行。下图列举了一些常见的I/O事件处理机制:
上图中,epoll模型是目前最高效的机制,它相比与select模型而言,最大的好处是不会随着被监控描述符数目的增加而导致效率急速下降。select模型是采用遍历扫描来判断每个描述符是否有事件发生,当监控的描述符数目越多,自然好事越大,而且由于受系统默认限制,select模型最多只能同时监控1024个描述符。相反,epoll模型同时监控的描述符个数不受限制;其次,epoll模型对事件的响应是触发式的,也即无需扫描,而只需对有事件发生的描述符做处理。epoll模型有两种触发方式,水平触发和边缘触发。
水平触发:支持阻塞和非阻塞状态,当描述符从未就绪变为就绪时,内核通过epoll告诉进程该描述符有事件发生,之后如果进程一直不对这个就绪状态做出任何操作,则内核会持续通知,直到事件处理完成。
边缘触发:高速工作方式(只支持非阻塞),当描述符从未就绪变为就绪时,内核通过epoll告诉进程该描述符有事件发生,之后就算进程一直不对这个就绪状态做任何操作,它也不提示,它只读一次。
- 进程负载均衡机制
说到I/O复用,自然有另一个问题,那就是负载均衡,如何调度进程。在一般情况下,配置Nginx执行时,工作进程都会有多个,由于各个工作进程相互独立的接受客户端请求、处理、响应,所以就可能会出现负载不均衡的情况,比如极端情况可能会是1个工作进程当前有3000个请求等待处理;而另一个进程当前却只有300个请求等待处理,这时候就设计到I/O负载均衡。如果进程并没有处于过载状态,那么就会去争用锁(争用套接字的控制权),如果争锁成功,就会把争取到的套接字加入自己的监控机制里,争锁失败就会把监听套接口从自己的监听事件中去掉。此时设置的监控机制的阻塞点的超时时间限制在一个比较短的范围内,超时更快,那么就更频繁的从阻塞中跳出来,也即有更多的机会去争抢互斥锁。当进程过载时,所做的工作就是计数,使ngx_accept_disabled减1,直到为0(当一个进程的活动连接数超过最大可承受连接数的7/8,此值将大于0,此时发生过载),那么此进程有可以去争锁。拥有锁的进程必须尽量缩短自身持锁时间,以让其他进程拥有更多机会。如果在处理新建连接事件的过程中,在监听套接口上又来了新的请求,此时此新的请求只有等到下次被进程争取倒锁并被加入监控机制中时才会被抓取出来。在同一时刻,监听套接口只能被一个进程监控,但是可以被多个进程拥有。
- 超时管理机制
另一个和事件有关的问题是超时Nginx的超时管理机制,事件超时意味着等待的事件没有在指定的时间内到达,Nginx有必要对这些可能发生超时的事件进行统一的管理 ,并在发生事件超时时做出相应的处理,比如回收资源,返回错误等。超时管理要解决两个问题:第一,超时事件对象的组织,Nginx采用的是红黑树;第二,超时事件对象的超时检测。Nginx提供了两种方案,一种是定时检测机制,每过一段时间对红黑树管理的超时事件进行扫描;另一种是先计算出距离当前最快发生超时的时间是多长(假定epoll_wait最长阻塞t秒)后去进行一次检测,然后更新当前时间。当某个进程初时化时,都需要建立一棵超时红黑树,当需要对某一事件进行超时监控时,就会把它加入到超时红黑树中。
上面提到的超时检测的两种方案中,方案一也就是定时去查看超时红黑树,是否有超时事件,该方案简单直观、容易理解 ,但是可能导致一些超时事件得不到及时的处理,我们只能通过具体的环境来修改定时时间。第二种方案由于是利用最快发生的事件的时刻减去当前时刻,这种方案在客户端请求较多的情况下,有可能要不停的去调用时间系统函数,从而影响性能。对于超时事件,直接将其移出红黑树,设置其超时标记,并调用该事件对应的回调函数进行处理。
- 请求处理与响应
Nginx在请求前都需要配置Nginx服务器,这里面主要包括server、location等内容,那和当有多个server上下文的时候,一个server配置至少一个监听套接口(对于只有端口没有Ip地址的server除外),所有的listen配置都以[port,addr]的形式组织在http核心配置的数组内,如果有server没有配置端口将启用默认端口。当FD与server绑定后,接下来要做的就是将监听套接口所对应的事件对象加入到Nginx的事件监控机制里(如果没有启动accept_mutex),那么就直接加入 ,否则就要先抢锁,然后抢到锁的才能加入到自己的事件监控机制内。需要注意的是主进程在创建完工作进程后并没有关闭这些监听套接口,但主进程却没有进行accept()客户端连接请求,因为如果工作进程down掉后,主进程会创建新的工作进程,并把这些监听套接口传递过去。
当有客户端发起连接请求,监控监听套接口的事件管理机制就会捕获到可读事件,工作进程便执行相应的回调函数,工作进程每次捕获到监听套接口上的事件后,只接受一个客户端请求,其它请求将等到再一次触发事件时才被接受。http的请求部分是调用回调函数(在handler模块处理)后,将请求发送到静态处理部分或后端服务器,在请求的数据返回时还需要经过filter模块的过滤然后才以字符串的形式存储在新申请的缓存中,将数据送到out发送链中。
在请求的过程中,还涉及到子请求,所谓子请求并不是由客户端直接发起的,它是由于Nginx在处理客户端请时,根据自身逻辑而内建的新请求,如下图所示:
子请求拥有主请求的几乎所有的特征,它的存在是为了提高并发能力,进一步提高效率。如果某个客户端的请求访问了多处资源(比如访问了a.html,b.html,c.html),那么针对每一处资源访问建立一个子请求并让它们同时进行,效率自然高很多。虽然一个进程只能处理一个请求,但是如果多个进程可以分别处理几个子请求,那从宏观上来讲,提高了请求的并发处理能力。目前官方提高的Nginx模块代码仅在filter阶段发起子请求,而此时的父请求的结果数据已经产生,如果在handler阶段发起子请求,由于此时父请求的结果数据还未产生,所以在数据同步方面需要做一些处理。那么多个子请求的顺序如何组织,才能将它当作最终的响应数据发回给客户端 ,否则客户端所请求的数据就不是原本正确的结果。
子请求的管理可以采用树加链表的形式,如下图所示,子请求以链表的形式链接:
每一个被触发的子请求会立即从链表中移除,但因最终的数据组合问题又有可能被停止而最终重新加入到链表中(虽然被触发了,但是迟迟数据没有返回,最后又没法被重新触发,所以需要Nginx重新将其加入到链表中)。
- 定位机制
Nginx里面location的存储是在队列里面,但是在匹配location时采用完全匹配,所以将队列里面的值以树的形式进行存储。在server定位中需要注意的是,如果有虚拟主机的存在,需要HTTP中带有host请求头,这样才能根据server内容做进一步的虚拟主机的物理定位 。
关于nginx架构探究(4)的更多相关文章
- 关于nginx架构探究(1)
nginx的架构主要是有一个主监控进程:master;三个工作进程:worker:还有Cache的两个进程.back-end-server是后端服务器,主要是处理后台逻辑.nginx作为代理服务器需要 ...
- 关于nginx架构探究(3)
Nginx 模块综述 Nginx 所有的代码都是以模块的新式组织的,包括核心模块和功能模块.Nginx加载模块的时候不想Apache一样动态加载,它是直接被编译到二进制执行文件中,所以,如果想要加载新 ...
- 关于nginx架构探究(2)
nginx 数据结构 1.Hash table nginx 对虚拟主机的管理使用到了HASH数据结构,假设配置文件里有如下的配置. Server{ listen 192.168.0.1 server_ ...
- Nginx学习笔记(一) Nginx架构
Nginx架构 Nginx全程是什么? Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. ...
- Nginx架构的企业级应用
Nginx架构的企业级应用 ==================================================== 实现HA高可用集群 实现LB负载均衡集群 Nginx实现反向代理 ...
- [转载] 深入 nginx 架构
原文: http://www.cnbeta.com/articles/402709.htm 了解 nginx 架构帮助我们学习如何开发高性能 web 服务. 为了更好地理解设计,你需要了解NGINX是 ...
- nginx架构与基础概念
1 Nginx架构 Nginx 高性能,与其架构有关. Nginx架构: nginx运行时,在unix系统中以daemon形式在后台运行,后台进程包含一个master进程和多个worker ...
- Nginx从入门到放弃-第5章 Nginx架构篇
5-1 Nginx常见问题_架构篇介绍 5-2 Nginx常见问题_多个server中虚拟主机读取的优先级 5-3 Nginx常见问题_多个location匹配的优先级1 5-4 Nginx常见问题_ ...
- 转:初探nginx架构(一)
来源:http://tengine.taobao.org/book/chapter_02.html 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢? ...
随机推荐
- 关于开发板不能ping通外网IP
最近在做远程监控的项目,打算用开发板给一个网站发送数据包.不过发现开发板只能ping通同一局域网内的ip,外网的ip不能ping通.纠结了半天发现是网关没有设置的原因.下面来说说如何解决这个问题. 首 ...
- UVA11995【I can guess the data structrue!!】【水】+UVA11991【map用法】
先看UVA11995 两份代码一份直接用C写的,一份用STL写的 #include <iostream> #include <stdio.h> #include <str ...
- 297 - Quadtrees (UVa)
Quadtrees A quadtree is a representation format used to encode images. The fundamental idea behind t ...
- motan源码分析二:使用spi机制进行类加载
在motan的源码中使用了很多的spi机制进行对象的创建,下面我们来具体分析一下它的实现方法. 1.在实际的jar包的\META-INF\services目录中引入相关的文件,例如下图中,我解压了co ...
- HTML5 Canvas渐进填充与透明
详细解释HTML5 Canvas中渐进填充的参数设置与使用,Canvas中透明度的设置与使 用,结合渐进填充与透明度支持,实现图像的Mask效果. 一:渐进填充(Gradient Fill) Canv ...
- swift学习资料初探
1. http://code.csdn.net/news/2820075
- Android Toast 自定义
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- ASCII码表及键盘码表。
ASCII码表 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 0 NUT 32 (space) 64 @ 96 . 1 SOH 33 ...
- Java线程的相关方法
~ start() 启动线程方法 ~ run() 调用start()方法时,真正执行的就是该方法的方法体 ~ sleep() 让当前线程睡眠,睡眠到期自动苏醒,并进入可运行状态,而不是运行状态 ...
- Zend框架2入门(一) (转)
By Rob Allen, www.akrabat.com 修订0.1.2文件版权所有? 2011本教程的目的是给创建一个简单的数据库的介绍使用Zend Framework 2驱动的应用程序使用模型 ...