nginx中的event模块

event中将事件驱动模块,由于支持跨平台,抽象出了event模块。它支持的event类型有:

1、AIO(异步I/O)

2、/dev/poll(solaris和unix特有)

3、epoll(linux2.6特有)

4、eventport(solaris 10特有)

5、kqueue(BSD特有)

6、poll

7、rtsig(实时信号)

8、select

event模块的主要功能就是,监听accept后建立的连接,对读写事件进行添加删除。事件驱动模型和非阻塞I/O模型结合在一起使用。当I/O可读可写的时候,相应的读写事件就会被唤醒,此时会去处理事件的回调函数

对于Linux, nginx大部分event用epoll EPOLLET(边沿触发)的方法来唤醒事件,只有listen端口的读事件是EPOLLLT(水平触发),对于边沿触发,如果出现了可读事件,必须及时处理,否则可能会出现读事件不再触发而没有处理的情况。

event的结构体为:

typedef struct {
    ngx_int_t  (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t  (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t  (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t  (*add_conn)(ngx_connection_t *c);
    ngx_int_t  (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);

    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
    ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                   ngx_uint_t flags);

    ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    void       (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;


accept锁

当内核accpet一个连接时,会唤醒所有等待的进程,但实际上只有一个进程能获取连接,其它的进程都是无效唤醒的。

nginx的事件处理入口函数为ngx_process_events_and_timers(),其加锁过程为

if (ngx_use_accept_mutex) {
        if (ngx_accept_disabled > 0) {
            ngx_accept_disabled--;

        } else {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                return;
            }

            if (ngx_accept_mutex_held) {
                flags |= NGX_POST_EVENTS;

            } else {
                if (timer == NGX_TIMER_INFINITE
                    || timer > ngx_accept_mutex_delay)
                {
                    timer = ngx_accept_mutex_delay;
                }
            }
        }
    }

在ngx_trylock_accept_mutex里,如果获取到了锁,就将listen的端口读事件加到event处理,等到有新连接到来时就可以accept了

ngx_process_events函数是所有事件处理的入口,它会遍历所有的事件。抢到accept锁的进程与一般进程有些区别,加上了NGX_POST_EVENTS标志表示ngx_process_events只是将事件放到post_events事件的队列中,而不处理。直到ngx_accept_mutex锁去掉后才去处理事件。为什么这样?因为这样做可以减小该进程抢到锁后,从accept开始到结束的时间,以便其它进程继续接收新的连接,提高吞吐量。

ngx_posted_accept_events和ngx_posted_events 分别是accept延迟事件队列和普通延迟事件队列。其实ngx_posted_accept_events还是放在ngx_accept_mutex锁里面处理的,该队列处理的都是accept事件,它会把内核backlog里等待的连接都accept进来,注册到读写事件中。




你可能感兴趣的:(nginx中的event模块)