码迷,mamicode.com
首页 > 其他好文 > 详细

Nginx 事件基本处理流程分析

时间:2015-11-24 00:47:06      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:

说明:本文章重点关注事件处理模型,顺便介绍相关的结构体,其他的结构体不做介绍。有兴趣的同学可以去http://tengine.taobao.org/book/查找更多资料。Tengine应该是淘宝基于Nginx自己做的修改。这个地址的文档还在不断的完善更新中。

技术分享

 程序流程图:

技术分享

说明:

 

一、进程生成顺序

1.main(src/core/nginx.c)函数启动ngx_master_process_cycle,启动主服务进程。

2.ngx_master_process_cycle(src/os/unix/ngx_process_cycle.c)里面调用ngx_start_worker_processes.

3.ngx_start_worker_processes(src/os/unix/ngx_process_cycle.c)里面循环执行技术分享生成特定数量的进程池。

4.ngx_spawn_process(src/os/unix/ngx_process.c)根据指定的respawn选项fork子进程,相关子进程信息保存在全部ngx_processes数组(ngx_process_t    ngx_processes[NGX_MAX_PROCESSES])中,子进程的运行过程通过参数proc指定,这里是ngx_worker_process_cycle(src/os/unix/ngx_process_cycle.c)。在fork之前先通过socketpair生成master process和worker process间进行通信的channel[2]。

master_process进程作为Nginx的服务主进程,管理其他子进程的生存周期,包括cache_manager_processes子进程,全部worker_processes,信号处理,timer等。

 

二、timer定时器超时处理机制

上图中的左侧红色1,2,3步构成了timer和select/poll/epoll_wait等等待函数配合使用的基本流程,libevent里面的timer处理机制也是一样的,即:

1.从timer最小堆(一般使用红黑树代替)中取出最小的timer;

2.传入epoll_wait等I/O复用函数;

3.处理堆中的timer超时事件。

 

三、worker process I/O处理流程

每个worker process的运行过程ngx_worker_process_cycle如下:

 1 static void
 2 ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
 3 {
 4     ngx_int_t worker = (intptr_t) data;
 5 
 6     ngx_process = NGX_PROCESS_WORKER;
 7     ngx_worker = worker;
 8 
 9     ngx_worker_process_init(cycle, worker);
10 
11     ngx_setproctitle("worker process");
12 
13     for ( ;; ) {
14 
15         if (ngx_exiting) {
16             ngx_event_cancel_timers();
17 
18             if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
19             {
20                 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
21 
22                 ngx_worker_process_exit(cycle);
23             }
24         }
25 
26         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
27 
28         ngx_process_events_and_timers(cycle);
29 
30         if (ngx_terminate) {
31             ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
32 
33             ngx_worker_process_exit(cycle);
34         }
35 
36         if (ngx_quit) {
37             ngx_quit = 0;
38             ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
39                           "gracefully shutting down");
40             ngx_setproctitle("worker process is shutting down");
41 
42             if (!ngx_exiting) {
43                 ngx_exiting = 1;
44                 ngx_close_listening_sockets(cycle);
45                 ngx_close_idle_connections(cycle);
46             }
47         }
48 
49         if (ngx_reopen) {
50             ngx_reopen = 0;
51             ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
52             ngx_reopen_files(cycle, -1);
53         }
54     }
55 }

可以看出,里面除了exiting,terminate,quit和reopen等控制操作外,只有ngx_process_events_and_timers(src/event/ngx_event.c)。再看ngx_process_events_and_timers函数:

 1 void
 2 ngx_process_events_and_timers(ngx_cycle_t *cycle)
 3 {
 4     ngx_uint_t  flags;
 5     ngx_msec_t  timer, delta;
 6 
 7     if (ngx_timer_resolution) {
 8         timer = NGX_TIMER_INFINITE;
 9         flags = 0;
10 
11     } else {
12         timer = ngx_event_find_timer(); 
13         flags = NGX_UPDATE_TIME;
14 
15 #if (NGX_WIN32)
16 
17         /* handle signals from master in case of network inactivity */
18 
19         if (timer == NGX_TIMER_INFINITE || timer > 500) {
20             timer = 500;
21         }
22 
23 #endif
24     }
25 
26     if (ngx_use_accept_mutex) {
27         if (ngx_accept_disabled > 0) {
28             ngx_accept_disabled--;
29 
30         } else {
31             if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
32                 return;
33             }
34 
35             if (ngx_accept_mutex_held) {
36                 flags |= NGX_POST_EVENTS;
37 
38             } else {
39                 if (timer == NGX_TIMER_INFINITE
40                     || timer > ngx_accept_mutex_delay)
41                 {
42                     timer = ngx_accept_mutex_delay;
43                 }
44             }
45         }
46     }
47 
48     delta = ngx_current_msec;
49 
50     (void) ngx_process_events(cycle, timer, flags);
51 
52     delta = ngx_current_msec - delta;
53 
54     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
55                    "timer delta: %M", delta);
56 
57     ngx_event_process_posted(cycle, &ngx_posted_accept_events);
58 
59     if (ngx_accept_mutex_held) {
60         ngx_shmtx_unlock(&ngx_accept_mutex);
61     }
62 
63     if (delta) {
64         ngx_event_expire_timers();
65     }
66 
67     ngx_event_process_posted(cycle, &ngx_posted_events);
68 }

1.函数开头7-24行计算定时器timer,用于后面的ngx_process_events(50行)函数,最终用于各种I/O复用函数的timeout参数,如epoll_wait的timeout参数。ngx_process_events是一个宏,#define ngx_process_events   ngx_event_actions.process_events(src/event/ngx_event.h)。全局变量ngx_event_actions在各个event module的init方法里面设置,如ngx_epoll_init(src/event/modules/ngx_epoll_module.c)中ngx_event_actions = ngx_epoll_module_ctx.actions;。而各个module的init方法的调用需要通过Nginx指定使用哪种类型的module来设置。相关初始设置在ngx_event_core_init_conf(src/event/ngx_event.c)里面指定。

2.63-65行处理timer超时事件。

以epoll module为例,ngx_process_events最终指向ngx_epoll_process_events(src/event/modules/ngx_epoll_module.c)。

  1 static ngx_int_t
  2 ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
  3 {
  4     int                events;
  5     uint32_t           revents;
  6     ngx_int_t          instance, i;
  7     ngx_uint_t         level;
  8     ngx_err_t          err;
  9     ngx_event_t       *rev, *wev;
 10     ngx_queue_t       *queue;
 11     ngx_connection_t  *c;
 12 
 13     /* NGX_TIMER_INFINITE == INFTIM */
 14 
 15     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
 16                    "epoll timer: %M", timer);
 17 
 18     events = epoll_wait(ep, event_list, (int) nevents, timer);
 19 
 20     err = (events == -1) ? ngx_errno : 0;
 21 
 22     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
 23         ngx_time_update();
 24     }
 25 
 26     if (err) {
 27         if (err == NGX_EINTR) {
 28 
 29             if (ngx_event_timer_alarm) {
 30                 ngx_event_timer_alarm = 0;
 31                 return NGX_OK;
 32             }
 33 
 34             level = NGX_LOG_INFO;
 35 
 36         } else {
 37             level = NGX_LOG_ALERT;
 38         }
 39 
 40         ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
 41         return NGX_ERROR;
 42     }
 43 
 44     if (events == 0) {
 45         if (timer != NGX_TIMER_INFINITE) {
 46             return NGX_OK;
 47         }
 48 
 49         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
 50                       "epoll_wait() returned no events without timeout");
 51         return NGX_ERROR;
 52     }
 53 
 54     for (i = 0; i < events; i++) {
 55         c = event_list[i].data.ptr;
 56 
 57         instance = (uintptr_t) c & 1;
 58         c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
 59 
 60         rev = c->read;
 61 
 62         if (c->fd == -1 || rev->instance != instance) {
 63 
 64             /*
 65              * the stale event from a file descriptor
 66              * that was just closed in this iteration
 67              */
 68 
 69             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
 70                            "epoll: stale event %p", c);
 71             continue;
 72         }
 73 
 74         revents = event_list[i].events;
 75 
 76         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
 77                        "epoll: fd:%d ev:%04XD d:%p",
 78                        c->fd, revents, event_list[i].data.ptr);
 79 
 80         if (revents & (EPOLLERR|EPOLLHUP)) {
 81             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
 82                            "epoll_wait() error on fd:%d ev:%04XD",
 83                            c->fd, revents);
 84         }
 85 
 86 #if 0
 87         if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
 88             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
 89                           "strange epoll_wait() events fd:%d ev:%04XD",
 90                           c->fd, revents);
 91         }
 92 #endif
 93 
 94         if ((revents & (EPOLLERR|EPOLLHUP))
 95              && (revents & (EPOLLIN|EPOLLOUT)) == 0)
 96         {
 97             /*
 98              * if the error events were returned without EPOLLIN or EPOLLOUT,
 99              * then add these flags to handle the events at least in one
100              * active handler
101              */
102 
103             revents |= EPOLLIN|EPOLLOUT;
104         }
105 
106         if ((revents & EPOLLIN) && rev->active) {
107 
108 #if (NGX_HAVE_EPOLLRDHUP)
109             if (revents & EPOLLRDHUP) {
110                 rev->pending_eof = 1;
111             }
112 #endif
113 
114             rev->ready = 1;
115 
116             if (flags & NGX_POST_EVENTS) {
117                 queue = rev->accept ? &ngx_posted_accept_events
118                                     : &ngx_posted_events;
119 
120                 ngx_post_event(rev, queue);
121 
122             } else {
123                 rev->handler(rev);
124             }
125         }
126 
127         wev = c->write;
128 
129         if ((revents & EPOLLOUT) && wev->active) {
130 
131             if (c->fd == -1 || wev->instance != instance) {
132 
133                 /*
134                  * the stale event from a file descriptor
135                  * that was just closed in this iteration
136                  */
137 
138                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
139                                "epoll: stale event %p", c);
140                 continue;
141             }
142 
143             wev->ready = 1;
144 
145             if (flags & NGX_POST_EVENTS) {
146                 ngx_post_event(wev, &ngx_posted_events);
147 
148             } else {
149                 wev->handler(wev);
150             }
151         }
152     }
153 
154     return NGX_OK;
155 }

可以看出,前面计算得到的timer传进了epoll_wait里面。其实这个timer的值是通过函数 ngx_event_find_timer从全部的timer组成的最小堆(Nginx里面使用RB tree实现,我猜是红黑树查询插入删除开销比堆小)里面取出来的最小timer值。 epoll_wait之后就是常见的事件处理了。可以对事件立即处理(调用handler)或者将事件插入请求队列(调用ngx_post_event)。

 

注:引用本人文章请注明出处,谢谢。

Nginx 事件基本处理流程分析

标签:

原文地址:http://www.cnblogs.com/NerdWill/p/4989859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!