最近一段時間,公司nginxlua遇到了各種奇怪問題幌衣,于是又讀了一遍陶輝的書。
主要關注upstream 長連接和 nginx lua的cosocket方面
subrequest和upstream的區(qū)別
在開發(fā)nginx module時,我們最有可能遇到的一件事就是泪漂,在處理一個請求時,我們需要訪問其他多個backend server網(wǎng)絡資源歪泳,拉取到結果后分析整理成一個response萝勤,再發(fā)給用戶。這個過程是無法使用nginx upstream機制的呐伞,因為upstream被設計為用來支持nginx reverse proxy功能敌卓,所以呢,upstream默認是把其他server的http response body全部返回給client伶氢。這與我們的要求不符趟径,這個時候瘪吏,我們可以考慮subrequest了,nginx http模塊提供的這個功能能夠幫我們搞定它蜗巧。
upstream
keepalive
keepalive 指定的 數(shù)值 是 Nginx 每個 worker 連接后端的最大長連接數(shù)掌眠,而不是整個 Nginx 的。 而且這里的后端指的是「所有的后端」幕屹,而不是每一個后端(已驗證)蓝丙。
https://skyao.gitbooks.io/learning-nginx/content/documentation/keep_alive.html
buffering
Syntax: proxy_buffering on | off;
Default: proxy_buffering on;
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
ngx_http_proxy_pass
clcf->handler = ngx_http_proxy_handler;
content階段執(zhí)行ngx_http_proxy_handler,此函數(shù)類似test
ngx_http_proxy_handler
891 u->create_request = ngx_http_proxy_create_request;?
| 892 u->reinit_request = ngx_http_proxy_reinit_request;?
| 893 u->process_header = ngx_http_proxy_process_status_line;?
| 894 u->abort_request = ngx_http_proxy_abort_request;?
| 895 u->finalize_request = ngx_http_proxy_finalize_request;?
rc = ngx_http_read_client_request_body(r,ngx_http_upstream_init);
145 if(rb->rest == 0){?
| 146 /* the whole request body was pre-read */?
| 147 r->request_body_no_buffering = 0;?
| 148 post_handler(r);?
| 149 return NGX_OK;?
| 150 }?
ngx_http_upstream_init
-> ngx_http_upstream_init_request
-> if(u->create_request(r)!= NGX_OK)
取上游地址
ngx_http_upstream_connect ** 連接上游 **
| 1538 c->write->handler = ngx_http_upstream_handler;?
| 1539 c->read->handler = ngx_http_upstream_handler;?
| 1540 ?
| 1541 u->write_event_handler = ngx_http_upstream_send_request_handler;?
| 1542 u->read_event_handler = ngx_http_upstream_process_header;?
ngx_http_upstream_send_request ** 發(fā)送下游header+body給上游**
ngx_http_upstream_process_header ** 接收上游header **
2338 if (!r->subrequest_in_memory) {?
| 2339 ngx_http_upstream_send_response(r, u); !!!!!!!!!!!!!!!!!!!!!!
| 2340 return;?
| 2341 }?
u->read_event_handler = ngx_http_upstream_process_body_in_memory;
ngx_http_upstream_process_body_in_memory ** 接收上游body **
發(fā)送上游header給下游
ngx_http_upstream_send_response
ngx_http_send_header
ngx_http_top_header_filter ( ngx_http_headers_module)
| 2930 u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;?
| 2931 r->write_event_handler =?
| 2932 ngx_http_upstream_process_non_buffered_downstream;?
接收上游body
ngx_http_upstream_process_non_buffered_upstream
ngx_http_upstream_process_non_buffered_request
返回上游body 給下游
ngx_http_upstream_process_non_buffered_downstream
ngx_http_upstream_process_non_buffered_request
Q: 為何nginx無法透傳上游返回的header?
A: 因為在分析上游headers時香嗓,將header放在了headers_in迅腔,目前沒有module可以直接返回所有的上游header
ngx_http_upstream_send_request_handler
ngx_http_upstream_send_request
-> ngx_http_upstream_reinit
ngx_http_upstream_process_header
-> | 2300 rc = u->process_header(r);?
#0 ngx_http_upstream_init(r=0x2038cb0)at src/http/ngx_http_upstream.c:503
#1 0x00000000004697d7 in ngx_http_read_client_request_body(r=0x2038cb0,
post_handler=0x4759c0 )at src/http/ngx_http_request_body.c:148
#2 0x000000000049811d in ngx_http_proxy_handler(r=0x2038cb0)at src/http/modules/ngx_http_proxy_module.c:930
#3 0x000000000045b7f4 in ngx_http_core_content_phase(r=0x2038cb0,ph=0x204e210)
at src/http/ngx_http_core_module.c:1173
#4 0x000000000045582d in ngx_http_core_run_phases(r=0x2038cb0)at src/http/ngx_http_core_module.c:862
#5 0x0000000000460fd8 in ngx_http_process_request(r=0x2038cb0)at src/http/ngx_http_request.c:1950
#6 0x0000000000461e96 in ngx_http_process_request_line(rev=0x2054670)at src/http/ngx_http_request.c:1049
#7 0x000000000044a381 in ngx_epoll_process_events(cycle=0x202a460,timer=,
flags=)at src/event/modules/ngx_epoll_module.c:902
#8 0x000000000043fb4a in ngx_process_events_and_timers(cycle=0x202a460)at src/event/ngx_event.c:252
#9 0x0000000000447f65 in ngx_worker_process_cycle(cycle=0x202a460,data=)
at src/os/unix/ngx_process_cycle.c:815
#10 0x00000000004461d4 in ngx_spawn_process(cycle=0x202a460,proc=0x447f20 ,data=0x0,
name=0x55b2ac "worker process",respawn=-3)at src/os/unix/ngx_process.c:198
#11 0x00000000004472bc in ngx_start_worker_processes(cycle=0x202a460,n=1,type=-3)
at src/os/unix/ngx_process_cycle.c:396
上下文
r->module->ctx 一個http請求設置在某個模塊的ctx
core
main
ngx_init_cycle
222 for (i = 0; cycle->modules[i]; i++) {?
| 223 if (cycle->modules[i]->type != NGX_CORE_MODULE) {?
| 224 continue;?
| 225 }?
| 226 ?
| 227 module = cycle->modules[i]->ctx;?
| 228 ?
| 229 if (module->create_conf) {?
| 230 rv = module->create_conf(cycle);?
| 231 if (rv == NULL) {?
| 232 ngx_destroy_pool(pool);?
| 233 return NULL;?
| 234 }?
| 235 cycle->conf_ctx[cycle->modules[i]->index] = rv;?
| 236 }?
| 237 }?
286 for (i = 0; cycle->modules[i]; i++) {?
| 287 if (cycle->modules[i]->type != NGX_CORE_MODULE) {?
| 288 continue;?
| 289 }?
| 290 ?
| 291 module = cycle->modules[i]->ctx;?
| 292 ?
| 293 if (module->init_conf) {?
| 294 if (module->init_conf(cycle,?
| 295 cycle->conf_ctx[cycle->modules[i]->index])?
| 296 == NGX_CONF_ERROR)?
| 297 {?
| 298 environ = senv;?
| 299 ngx_destroy_cycle_pools(&conf);?
| 300 return NULL;?
| 301 }?
| 302 }?
| 303 }?
/* handle the listening sockets */?
ngx_master_process_cycle
ngx_start_worker_processes
| 357 for (i = 0; i < n; i++) {?
| 358 ?
| 359 ngx_spawn_process(cycle, ngx_worker_process_cycle,?
| 360 (void *) (intptr_t) i, "worker process", type);?
ngx_worker_process_cycle
ngx_worker_process_init
929 for (i = 0; cycle->modules[i]; i++) {?
| 930 if (cycle->modules[i]->init_process) {?
| 931 if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {?
| 932 /* fatal */?
| 933 exit(2);?
| 934 }?
| 935 }?
| 936 }?
ngx_listening_t --- 每個監(jiān)聽端口一個此結構
-> ngx_connection_handler_pt 監(jiān)聽成功建立tcp連接后
events
#0 ngx_epoll_process_events (cycle=0x202a460, timer=5000, flags=1) at src/event/modules/ngx_epoll_module.c:785
#1 0x000000000043fb4a in ngx_process_events_and_timers (cycle=0x202a460) at src/event/ngx_event.c:252
#2 0x0000000000447f65 in ngx_worker_process_cycle (cycle=0x202a460, data=<value optimized out>)
at src/os/unix/ngx_process_cycle.c:815
#3 0x00000000004461d4 in ngx_spawn_process (cycle=0x202a460, proc=0x447f20 <ngx_worker_process_cycle>, data=0x0,
name=0x55b2ac "worker process", respawn=-3) at src/os/unix/ngx_process.c:198
#4 0x00000000004472bc in ngx_start_worker_processes (cycle=0x202a460, n=1, type=-3)
at src/os/unix/ngx_process_cycle.c:396
#5 0x0000000000448873 in ngx_master_process_cycle (cycle=0x202a460) at src/os/unix/ngx_process_cycle.c:135
#6 0x000000000041fec7 in main (argc=<value optimized out>, argv=<value optimized out>) at src/core/nginx.c:381
ngx_event_accept
ngx_event_accept
c = ngx_get_connection(s, ev->log);
c->fd = s;
ls->handler(c); = ngx_http_init_connection
- 81 static ngx_command_t ngx_events_commands[] = {?
| 82 ?
| 83 { ngx_string("events"),?
| 84 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,?
| 85 ngx_events_block,?
| 86 0,?
| 87 0,?
| 88 NULL },?
| 89 ?
| 90 ngx_null_command?
| 91 };?
92
ngx_events_block
940 (*ctx)[cf->cycle->modules[i]->ctx_index] =?
| 941 m->create_conf(cf->cycle);?
| 969 rv = m->init_conf(cf->cycle,?
| 970 (*ctx)[cf->cycle->modules[i]->ctx_index]);?
ngx_event_process_init
734 for (i = 0; i < cycle->listening.nelts; i++) {?
| 735 ?
| 736 #if (NGX_HAVE_REUSEPORT)?
| 737 if (ls[i].reuseport && ls[i].worker != ngx_worker) {?
| 738 continue;?
| 739 }?
| 740 #endif?
| 741 ?
| 742 c = ngx_get_connection(ls[i].fd, cycle->log);?
| 754 rev = c->read;?
| 821 rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept?
| 822 : ngx_event_recvmsg;?
| 856 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {?
| 857 return NGX_ERROR;?
| 858 }?
ngx_event_accept 沒有post flag,不進入隊列靠娱,立即執(zhí)行
ngx_event_s
-> ngx_event_handler_pt
epoll
ngx_event_use
| 1037 if (module->name->len == value[1].len) {?
| 1038 if (ngx_strcmp(module->name->data, value[1].data) == 0) {?
| 1039 ecf->use = cf->cycle->modules[m]->ctx_index;?
| 1040 ecf->name = module->name->data;?
| 1041 ?
| 1042 if (ngx_process == NGX_PROCESS_SINGLE?
| 1043 && old_ecf?
| 1044 && old_ecf->use != ecf->use)?
| 1045 {?
| 1046 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,?
| 1047 "when the server runs without a master process "?
| 1048 "the \"%V\" event type must be the same as "?
| 1049 "in previous configuration - \"%s\" "?
| 1050 "and it cannot be changed on the fly, "?
| 1051 "to change it you need to stop server "?
| 1052 "and start it again",?
| 1053 &value[1], old_ecf->name);?
| 1054 ?
| 1055 return NGX_CONF_ERROR;?
| 1056 }?
| 1057 ?
| 1058 return NGX_CONF_OK;?
| 1059 }?
| 1060 }?
- 179 static ngx_event_module_t ngx_epoll_module_ctx = {?
| 180 &epoll_name,?
| 181 ngx_epoll_create_conf, /* create configuration */?
| 182 ngx_epoll_init_conf, /* init configuration */?
| 183 ?
| 184 {?
| 185 ngx_epoll_add_event, /* add an event */?
| 186 ngx_epoll_del_event, /* delete an event */?
| 187 ngx_epoll_add_event, /* enable an event */?
| 188 ngx_epoll_del_event, /* disable an event */?
| 189 ngx_epoll_add_connection, /* add an connection */?
| 190 ngx_epoll_del_connection, /* delete an connection */?
| 191 #if (NGX_HAVE_EVENTFD)?
| 192 ngx_epoll_notify, /* trigger a notify */?
| 193 #else?
| 194 NULL, /* trigger a notify */?
| 195 #endif?
| 196 ngx_epoll_process_events, /* process the events */?
| 197 ngx_epoll_init, /* init the events */?
| 198 ngx_epoll_done, /* done the events */?
| 199 }?
| 200 };?
201 ?
- 202 ngx_module_t ngx_epoll_module = {?
| 203 NGX_MODULE_V1,?
| 204 &ngx_epoll_module_ctx, /* module context */?
| 205 ngx_epoll_commands, /* module directives */?
| 206 NGX_EVENT_MODULE, /* module type */?
| 207 NULL, /* init master */?
| 208 NULL, /* init module */?
| 209 NULL, /* init process */?
| 210 NULL, /* init thread */?
| 211 NULL, /* exit thread */?
| 212 NULL, /* exit process */?
| 213 NULL, /* exit master */?
| 214 NGX_MODULE_V1_PADDING?
| 215 };?
cycle
ngx_cycle_t
conf_ctx
http
ngx_http_block
ngx_http_optimize_servers
ngx_http_init_listening
ngx_http_add_listening
ls->handler = ngx_http_init_connection
ngx_http_init_connection
318 rev = c->read;?
| 319 rev->handler = ngx_http_wait_request_handler;?
| 320 c->write->handler = ngx_http_empty_handler;?
ngx_http_wait_request_handler
| 505 rev->handler = ngx_http_process_request_line;?
| 506 ngx_http_process_request_line(rev);?
ngx_http_process_request_headers
ngx_http_process_request
| 1944 c->read->handler = ngx_http_request_handler;?
| 1945 c->write->handler = ngx_http_request_handler;?
http upstream
如果有幫助沧烈,掃一下,請我喝杯小藍咖啡吧