nginx事件模組 -- 第三篇
阿新 • • 發佈:2018-12-24
微信公眾號:鄭爾多斯
關注可瞭解更多的Nginx
知識。任何問題或建議,請公眾號留言;
關注公眾號,有趣有內涵的文章第一時間送達!
內容回顧
前面的幾篇文章中,我們介紹了nginx
的事件模組的基礎知識。我們知道nginx
中包含了三個與事件相關的module
,分別為ngx_event_module
,ngx_event_core_module
,ngx_epoll_module
。我們也分別分析了這三個模組的配置檔案的解析過程,從本篇文章開始,將詳細分析nginx
的事件處理過程,比如如何新增事件,刪除事件,處理事件等。
事件處理的概述
事件處理模組的主要解決的問題是如何收集,分發以及管理事件。在nginx
master
程序和worker
程序通訊也是使用事件機制來完成的,但是我們的關注點主要在前兩種事件,第三種事件以後會分析。前面我們分析了nginx
是如何解析配置檔案中與事件有關的配置項的,我們知道,當遇到events{}
的時候,表示開始處理事件配置項了。
事件和連線
作為web伺服器,每一個使用者請求至少對應一個TCP
連線,每個連線都包含一個毒事件和一個寫事件。這樣epoll就可以根據觸發的事件型別來排程相應的模組進行處理。Nginx
連線分為主動連線和被動連線。分別用ngx_connection_t
和ngx_peer_connection_t
主動連線: 客戶端發起,伺服器被動接受的連線
被動連線:Nginx
作為客戶端,向上遊伺服器發起的連線
本系列文章所介紹的連線都是被動連線,即Nginx
作為伺服器被動的接受客戶端發起的連線。
Nginx連線池
為了提高效率,Nginx
在啟動的時候,會建立好連線池和對應的讀寫事件,並且將每個連線都和對應的讀寫事件對應起來。這樣的話,在後面使用到連線的時候,只需要從連線池中獲取一個空閒的連線就行了。那麼Nginx
是在什麼時候建立了連線池和讀寫事件呢?
前面兩篇文章我們介紹了ngx_events_module
, ngx_event_core_module
, ngx_epoll_module
create_conf()
, init_conf()
方法。我們知道ngx_module_t
結構體有中有許多鉤子函式,其中有一個鉤子函式為init_process()
,這個方法會在Nginx
啟動過程中呼叫。在master/worker
模式下,當建立了worker
程序之後,會在worker
程序的初始化過程中呼叫init_process()
。通過原始碼可以發現,與事件機制相關的三個模組中,只有
ngx_event_core_module
有一個init_process()
鉤子函式,為ngx_event_process_init()
。其他兩個模組都沒有對應的鉤子函式。具體的呼叫過程如下: 呼叫init_process()方法
ngx_event_process_init
下面我們就分析一下這個ngx_event_process_init()
這個方法。
1static ngx_int_t
2ngx_event_process_init(ngx_cycle_t *cycle)
3{
4 ngx_uint_t m, i;
5 ngx_event_t *rev, *wev;
6 ngx_listening_t *ls;
7 ngx_connection_t *c, *next, *old;
8 ngx_core_conf_t *ccf;
9 ngx_event_conf_t *ecf;
10 ngx_event_module_t *module;
11
12 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
13 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
14
15 if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
16 ngx_use_accept_mutex = 1;
17 ngx_accept_mutex_held = 0;
18 ngx_accept_mutex_delay = ecf->accept_mutex_delay;
19
20 } else {
21 ngx_use_accept_mutex = 0;
22 }
23
24 ngx_queue_init(&ngx_posted_accept_events);
25 ngx_queue_init(&ngx_posted_events);
26
27 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
28 return NGX_ERROR;
29 }
30
31 for (m = 0; cycle->modules[m]; m++) {
32 if (cycle->modules[m]->type != NGX_EVENT_MODULE) {
33 continue;
34 }
35
36 if (cycle->modules[m]->ctx_index != ecf->use) {
37 continue;
38 }
39
40 module = cycle->modules[m]->ctx;
41
42 if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
43 /* fatal */
44 exit(2);
45 }
46
47 break;
48 }
49
50#if !(NGX_WIN32)
51
52 if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
53 struct sigaction sa;
54 struct itimerval itv;
55
56 ngx_memzero(&sa, sizeof(struct sigaction));
57 sa.sa_handler = ngx_timer_signal_handler;
58 sigemptyset(&sa.sa_mask);
59
60 if (sigaction(SIGALRM, &sa, NULL) == -1) {
61 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
62 "sigaction(SIGALRM) failed");
63 return NGX_ERROR;
64 }
65
66 itv.it_interval.tv_sec = ngx_timer_resolution / 1000;
67 itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000;
68 itv.it_value.tv_sec = ngx_timer_resolution / 1000;
69 itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000;
70
71 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
72 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
73 "setitimer() failed");
74 }
75 }
76
77 if (ngx_event_flags & NGX_USE_FD_EVENT) {
78 struct rlimit rlmt;
79
80 if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
81 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
82 "getrlimit(RLIMIT_NOFILE) failed");
83 return NGX_ERROR;
84 }
85
86 cycle->files_n = (ngx_uint_t) rlmt.rlim_cur;
87
88 cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n,
89 cycle->log);
90 if (cycle->files == NULL) {
91 return NGX_ERROR;
92 }
93 }
94
95#else
96
97 if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
98 ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
99 "the \"timer_resolution\" directive is not supported "
100 "with the configured event method, ignored");
101 ngx_timer_resolution = 0;
102 }
103
104#endif
105
106 cycle->connections =
107 ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
108 if (cycle->connections == NULL) {
109 return NGX_ERROR;
110 }
111
112 c = cycle->connections;
113
114 cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
115 cycle->log);
116 if (cycle->read_events == NULL) {
117 return NGX_ERROR;
118 }
119
120 rev = cycle->read_events;
121 for (i = 0; i < cycle->connection_n; i++) {
122 rev[i].closed = 1;
123 rev[i].instance = 1;
124 }
125
126 cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
127 cycle->log);
128 if (cycle->write_events == NULL) {
129 return NGX_ERROR;
130 }
131
132 wev = cycle->write_events;
133 for (i = 0; i < cycle->connection_n; i++) {
134 wev[i].closed = 1;
135 }
136
137 i = cycle->connection_n;
138 next = NULL;
139
140 do {
141 i--;
142
143 c[i].data = next;
144 c[i].read = &cycle->read_events[i];
145 c[i].write = &cycle->write_events[i];
146 c[i].fd = (ngx_socket_t) -1;
147
148 next = &c[i];
149 } while (i);
150
151 cycle->free_connections = next;
152 cycle->free_connection_n = cycle->connection_n;
153