Nginx处理stale事件机制分析

Nginx为提高效率采用描述符缓冲池(连接池)来处理tcp连接,一个连接对应一个读事件和一个写事件,nginx在启动的时候会创建好所用连接和事件,当事件来的时候不用再创建,然而连接池的使用却存在stale事件的问题,以下将详细分析Nginx是如何处理stale事件的,该问题涉及到epoll、Nginx连接与事件的相关知识。

1     
Epoll的实现原理

epoll相关的系统调用有:epoll_create, epoll_ctl和epoll_wait。Linux-2.6.19又引入了可以屏蔽指定信号的epoll_wait:
epoll_pwait。至此epoll家族已全。其中:

a、epoll_create用来创建一个epoll文件描述符,

b、epoll_ctl用来添加/修改/删除需要侦听的文件描述符及其事件,在ngx_epoll_add_event/ngx_epoll_del_event/ngx_epoll_add_connection/ngx_epoll_del_connection中使用

c、epoll_wait/epoll_pwait接收发生在被侦听的描述符上的,用户感兴趣的IO事件,在ngx_epoll_process_event

d、epoll文件描述符用完后,直接用close关闭即可。事实上,任何被侦听的文件符只要其被关闭,那么它也会自动从被侦听的文件描述符集合中删除。

(1)epoll和select相比,最大不同在于:

1epoll返回时已经明确的知道哪个sokcet fd发生了事件,不用再一个个比对。这样就提高了效率。

2select的FD_SETSIZE是有限止的,而epoll是没有限止的只与系统资源有关。

(2)Epoll在Nginx中的使用:

1)ngx_epoll_init
通过epoll_create函数创建了epfd句柄,这是epoll的接口,之后所有的函数调用都要使用该epfd句柄。

2)之后在ngx_event_process_init中,通过epoll_ctl将监听套接字和其对应的事件类型添加到epfd句柄中。

通过这两步,就完成了epoll事件处理的三部曲中的前两部,接下来就是由epoll_wait等待事件的发生。

2     
Nginx的连接与事件

在Nginx中事件不需要创建,因为在Nginx启动时初始化ngx_cycle_t的过程中就分配了所有读、写事件的空间。这样,每个连接就对应了一个写事件和一个读事件。在Nginx中定义了两种连接:ngx_connection_t:被动连接,由客户端主动发起。ngx_peer_connection_t:主动连接。用于主动和上游服务器进行通信。当Nginx服务器接和客户端建立连接后,就会获得一个ngx_connection_t实体。和事件一样,连接不需要额外创建,它是从ngx_connection_t连接池中获得的,连接池在Nginx启动阶段就已经分配好了,由ngx_cycle_t结构体的connections成员和free_connections成员共同管理,free_connections相当于一个栈,每次从链表头插入,从链表头取(先进后出)。

3 如何处理stale事件

Nginx连接的文件描述符状态转移如下图所示

stale event(过期事件)有两种情况:

第一:在处理状态2的描述符集合前面的描述符时,将此组中后面的描述符也关闭了,那么后面的那个描述符就应该进入到了状态1,也就是空闲的描述符组,但是它仍然还存在于状态2集合中,因为它是由一次的epoll_wait返回的,我们没有办法在下次系统调用epoll_wait之前将它从此组中剔除。

在处理状态2的描述符的后续循环中仍然会处理它。此时就需要一个标志来标识此时的描述符状态:虽然仍在状态2的集合里面,但实际上已经进入状态1的状态了,通过将状态2集合中的fd置为-1(也就是starvation中提到的解决方法),来标识状态2集合内的描述符实际上已经回到了状态1的集合,在顺序处理的过程中,检查此标识,如果fd为-1那么就跳过不进行处理了。

第二、在状态2的描述符中有:#1, #2, ….. #40, ….,在处理#2的时候将#40关闭了,此时继续向下处理,但是还没到#40,此时又有新情况发生了,又来了新的连接,accept函数为他分配了新的描述符,恰好是#40,那么我们刚刚已经将#40的描述符的fd置为-1,现在它又被accept置为有效的值了,实际上已经进入了状态3。实际上此时的#40应该在下次epoll_wait的时候才返回,但是它现在还在我们的二组中,而还没处理到呢,一旦开始处理的时候,是不应该进行处理的,但是现在无法判断。

此种情况需要另一个标志instance来标识状态2和状态3的区别。在ngx_get_connection函数中获得一个新的connection的时候,将instance用上次值的反来初始化,假如此次初始化后的值为一bit位的x。

instance = rev->instance;

ngx_memzero(rev, sizeof(ngx_event_t));

ngx_memzero(wev, sizeof(ngx_event_t));

rev->instance = !instance;

wev->instance = !instance;

在epoll中添加(add_event)和删除(del_event),对应着描述符从状态1到状态3和从状态2或者状态3到状态1转换中,用event.data.ptr的最后一比特记录这个instance的值,这时这个值还是x。

ee.events = events | (uint32_t) flags;

ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);

在ngx_epoll_process_events中,c->fd == -1是第一种情况, rev->instance != instance是指第二种情况,instance代表是ngx_epoll_add_event将该事件添加到epoll中时所记录的值,rev->instance代表该连接connection自己的值,正常情况下,获得连接时rev->instance是刚释放连接取反,它先经过epoll_ctl添加进epoll时被记录,然后在处理事件的epoll_wait的返回后,取出instance,此时它与rev->instance是相等的,然而在第二种情况下发生了变化,重新获得了文件描述符#40的连接,rev->instance立刻取反,而此时添加动作还没来得及进行,即epoll_ctl的添加动作未发生,即这个新获得连接的标识没有被记录,此时的instance仍然是#40的第一次连接保持的值,当然两者是不相等,只有等到新连接被添加后,再次进行epoll_wait时instance才会被更新为rev->instance,即两者相等,才可以被处理,而本次的epoll_wait将跳过该事件。

for (i = 0; i < events; i++) {

c = event_list[i].data.ptr;

instance = (uintptr_t) c & 1;

c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

rev = c->read;

if (c->fd == -1 || rev->instance != instance) {

/*

* the stale event from a file descriptor

* that was just closed in this iteration

*/

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,

"epoll: stale event %p", c);

continue;

}

参考:http://blog.csdn.net/nestler/article/details/37570401

http://wap.blog.163.com/w2/blogDetail.do?u=http://blog.163.com/lnwdl/blog/static/3883041220132721710725

Nginx处理stale事件机制分析,布布扣,bubuko.com

时间: 2024-12-24 22:46:02

Nginx处理stale事件机制分析的相关文章

QT开发(六十三)——QT事件机制分析

QT开发(六十三)--QT事件机制分析 一.事件机制 事件是由系统或者QT平台本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事件则是由系统自动发出,如计时器事件. 事件的出现,使得程序代码不会按照原始的线性顺序执行.线性顺序的程序设计风格不适合处理复杂的用户交互,如用户交互过程中,用户点击"打开文件"将开始执行打开文件的操作,用户点击"保存文件"将开始执

Spring 中的事件机制

说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎么实现的呢?说listener之前,我们先从设计模式开始讲起. 观察者模式 观察者模式一般包含以下几个对象: Subject:被观察的对象.它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify().目标类可以是接口,也可以是抽象类或具体类. ConcreteSubject:具体的

Cocos2d-X3.0 刨根问底(七)----- 事件机制Event源码分析

这一章,我们来分析Cocos2d-x 事件机制相关的源码, 根据Cocos2d-x的工程目录,我们可以找到所有关于事件的源码都存在放在下图所示的目录中. 从这个event_dispatcher目录中的文件命名上分析 cocos2d-x与事件相关的类一共有四种, Event, EventListener,EventDispatcher, Touch分别为 事件,事件侦听器,事件分发器,触摸 我们先从Event类开始. 打开CCEvent.h文件 /** * Base class of all ki

PHP实现事件机制实例分析

PHP实现事件机制实例分析 内置了事件机制的语言不多,php也没有提供这样的功能.事件(Event)说简单了就是一个Observer模式,实现起来很容易.但是有所不同的是,事件的监听者谁都可以加,但是只能由直接包含它的对象触发.这就有一点点难度了.php有一个debug_backtrace函数,可以得到当前的调用栈,由此可以找到判断调用事件触发函数的对象是不是直接包含它的对象的办法. <?php /** * 事件 * @edit http://www.lai18.com * @author xi

从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法

本篇文章假设读者没有任何的触摸事件基础知识,所以我们会从最基本的触摸事件分发处说起. ScrollView为什么会出现嵌套EditText出现滑动事件冲突呢?相信你会有这种疑问,我们来看这么一种情况: 有一个固定高度的EditText,假设它只能显示3行文本,但是,我们在其中输入的文本多余三行时,那么这时就需要可以在EditText内部进行小幅滚动了.那么将这个EditText放入了ScrollView当中, 并且ScrollView内容过多以致ScrollView也可以滑动,这时候就会出现Ed

Android笔记:触摸事件的分析与总结----TouchEvent处理机制

   其他相关博文:    Android笔记:触摸事件的分析与总结----MotionEvent对象    Android笔记:触摸事件的分析与总结----TouchEvent处理机制 Android中的事件类型分为按键事件和屏幕触摸事件.TouchEvent是屏幕触摸事件的基础事件,要深入了解屏幕触摸事件的处理机制,就必须掌握TouchEvent在整个触摸事件中的转移和处理过程.此处将对TouchEvent处理机制的学习做个小小的总结和备记. 当屏幕中包含一个ViewGroup,而这个Vie

事件拦截机制分析(Android群英传)

内容是博主照着书敲出来的,博主码字挺辛苦的,转载请注明出处,后序内容陆续会码出. 当Android系统捕获到用户的各种输入事件后,如何准确地传递给真正需要这个事件的控件呢?Android给我们提供了一整套完善的事件传递.处理机制,来帮助开发者完成准确的事件分配与处理. 要了解触摸事件的拦截机制,首先要了解什么是触摸事件?顾名思义,触摸事件就是捕获触摸屏幕后产生的事件.当点击一个按钮时,通常就会产生两个或者三个事件--按钮按下,这是事件一:如果不小心滑动一点,这就是事件二:当手抬起,这是事件三.A

聊一聊Android的事件机制

侯 亮 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和事件机制,前者用于跨进程通信,后者用于进程内部通信. 从技术实现上来说,事件机制还是比较简单的.从大的方面讲,不光是Android平台,各种平台的消息机制的原理基本上都是相近的,其中用到的主要概念大概有: 1)消息发送者: 2)消息队列: 3)消息处理循环. 示意图如下: 图中表达的基本意思是,消息发送者通过某种方式,将消息发送到某个消息队列里,同时还有一个消息处理循环,不断从消息队列里摘取消息,并进一步解析处理.

从Chrome源码看浏览器的事件机制

.aligncenter { clear: both; display: block; margin-left: auto; margin-right: auto } .crayon-line span::after { content: " " } p { font-size: 15px; text-indent: 2em } #colorbox.crayon-colorbox,#cboxOverlay.crayon-colorbox,.crayon-colorbox #cboxWr