深入理解|深入理解 nginx和nginx-lua
最近一段时间,公司nginxlua遇到了各种奇怪问题,于是又读了一遍陶辉的书。
主要关注upstream 长连接和 nginx lua的cosocket方面
subrequest和upstream的区别
在开发nginx module时,我们最有可能遇到的一件事就是,在处理一个请求时,我们需要访问其他多个backend server网络资源,拉取到结果后分析整理成一个response,再发给用户。这个过程是无法使用nginx upstream机制的,因为upstream被设计为用来支持nginx reverse proxy功能,所以呢,upstream默认是把其他server的http response body全部返回给client。这与我们的要求不符,这个时候,我们可以考虑subrequest了,nginx http模块提供的这个功能能够帮我们搞定它。
upstream
keepalive
keepalive 指定的 数值 是 Nginx 每个 worker 连接后端的最大长连接数,而不是整个 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阶段执行ngx_http_proxy_handler,此函数类似test
ngx_http_proxy_handler891u->create_request = ngx_http_proxy_create_request;
?
|892u->reinit_request = ngx_http_proxy_reinit_request;
?
|893u->process_header = ngx_http_proxy_process_status_line;
?
|894u->abort_request = ngx_http_proxy_abort_request;
?
|895u->finalize_request = ngx_http_proxy_finalize_request;
?
rc = ngx_http_read_client_request_body(r,ngx_http_upstream_init);
145if(rb->rest == 0){?
|146/* the whole request body was pre-read */?
|147r->request_body_no_buffering = 0;
?
|148post_handler(r);
?
|149return NGX_OK;
?
|150}?
ngx_http_upstream_init
-> ngx_http_upstream_init_request
-> if(u->create_request(r)!= NGX_OK)
取上游地址
ngx_http_upstream_connect** 连接上游 **
|1538c->write->handler = ngx_http_upstream_handler;
?
|1539c->read->handler = ngx_http_upstream_handler;
?
|1540 ?
|1541u->write_event_handler = ngx_http_upstream_send_request_handler;
?
|1542u->read_event_handler = ngx_http_upstream_process_header;
?
ngx_http_upstream_send_request** 发送下游header+body给上游**
ngx_http_upstream_process_header** 接收上游header **
2338if (!r->subrequest_in_memory) {?
|2339ngx_http_upstream_send_response(r, u);
!!!!!!!!!!!!!!!!!!!!!!
|2340return;
?
|2341}?
u->read_event_handler = ngx_http_upstream_process_body_in_memory;
ngx_http_upstream_process_body_in_memory** 接收上游body **
发送上游header给下游
ngx_http_upstream_send_response
ngx_http_send_header
ngx_http_top_header_filter ( ngx_http_headers_module)
|2930u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
?
|2931r->write_event_handler =?
|2932ngx_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
【深入理解|深入理解 nginx和nginx-lua】ngx_http_upstream_process_header
-> |2300rc = u->process_header(r);
?
#0ngx_http_upstream_init(r=0x2038cb0)at src/http/ngx_http_upstream.c:503#10x00000000004697d7 in ngx_http_read_client_request_body(r=0x2038cb0,post_handler=0x4759c0 )at src/http/ngx_http_request_body.c:148#20x000000000049811d in ngx_http_proxy_handler(r=0x2038cb0)at src/http/modules/ngx_http_proxy_module.c:930#30x000000000045b7f4 in ngx_http_core_content_phase(r=0x2038cb0,ph=0x204e210)at src/http/ngx_http_core_module.c:1173#40x000000000045582d in ngx_http_core_run_phases(r=0x2038cb0)at src/http/ngx_http_core_module.c:862#50x0000000000460fd8 in ngx_http_process_request(r=0x2038cb0)at src/http/ngx_http_request.c:1950#60x0000000000461e96 in ngx_http_process_request_line(rev=0x2054670)at src/http/ngx_http_request.c:1049#70x000000000044a381 in ngx_epoll_process_events(cycle=0x202a460,timer=,flags=)at src/event/modules/ngx_epoll_module.c:902#80x000000000043fb4a in ngx_process_events_and_timers(cycle=0x202a460)at src/event/ngx_event.c:252#90x0000000000447f65 in ngx_worker_process_cycle(cycle=0x202a460,data=https://www.it610.com/article/)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_cycle222for (i = 0;
cycle->modules[i];
i++) {?
|223if (cycle->modules[i]->type != NGX_CORE_MODULE) {?
|224continue;
?
|225}?
|226 ?
|227module = cycle->modules[i]->ctx;
?
|228 ?
|229if (module->create_conf) {?
|230rv = module->create_conf(cycle);
?
|231if (rv == NULL) {?
|232ngx_destroy_pool(pool);
?
|233return NULL;
?
|234}?
|235cycle->conf_ctx[cycle->modules[i]->index] = rv;
?
|236}?
|237}?286for (i = 0;
cycle->modules[i];
i++) {?
|287if (cycle->modules[i]->type != NGX_CORE_MODULE) {?
|288continue;
?
|289}?
|290 ?
|291module = cycle->modules[i]->ctx;
?
|292 ?
|293if (module->init_conf) {?
|294if (module->init_conf(cycle,?
|295cycle->conf_ctx[cycle->modules[i]->index])?
|296== NGX_CONF_ERROR)?
|297{?
|298environ = senv;
?
|299ngx_destroy_cycle_pools(&conf);
?
|300return NULL;
?
|301}?
|302}?
|303}?/* handle the listening sockets */?ngx_master_process_cycle
ngx_start_worker_processes|357for (i = 0;
i < n;
i++) {?
|358 ?
|359ngx_spawn_process(cycle, ngx_worker_process_cycle,?
|360(void *) (intptr_t) i, "worker process", type);
?ngx_worker_process_cycle
ngx_worker_process_init929for (i = 0;
cycle->modules[i];
i++) {?
|930if (cycle->modules[i]->init_process) {?
|931if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {?
|932/* fatal */?
|933exit(2);
?
|934}?
|935}?
|936}?
ngx_listening_t --- 每个监听端口一个此结构
->ngx_connection_handler_pt 监听成功建立tcp连接后
events
#0ngx_epoll_process_events (cycle=0x202a460, timer=5000, flags=1) at src/event/modules/ngx_epoll_module.c:785
#10x000000000043fb4a in ngx_process_events_and_timers (cycle=0x202a460) at src/event/ngx_event.c:252
#20x0000000000447f65 in ngx_worker_process_cycle (cycle=0x202a460, data=https://www.it610.com/article/)
at src/os/unix/ngx_process_cycle.c:815
#30x00000000004461d4 in ngx_spawn_process (cycle=0x202a460, proc=0x447f20 , data=https://www.it610.com/article/0x0,
name=0x55b2ac"worker process", respawn=-3) at src/os/unix/ngx_process.c:198
#40x00000000004472bc in ngx_start_worker_processes (cycle=0x202a460, n=1, type=-3)
at src/os/unix/ngx_process_cycle.c:396
#50x0000000000448873 in ngx_master_process_cycle (cycle=0x202a460) at src/os/unix/ngx_process_cycle.c:135
#60x000000000041fec7 in main (argc=, argv=) 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_tngx_events_commands[] = {?
|82 ?
|83{ ngx_string("events"),?
|84NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,?
|85ngx_events_block,?
|860,?
|870,?
|88NULL },?
|89 ?
|90ngx_null_command?
|91 };
?
92 ngx_events_block940(*ctx)[cf->cycle->modules[i]->ctx_index] =?
|941m->create_conf(cf->cycle);
?|969rv = m->init_conf(cf->cycle,?
|970(*ctx)[cf->cycle->modules[i]->ctx_index]);
?ngx_event_process_init734for (i = 0;
i < cycle->listening.nelts;
i++) {?
|735 ?
|736 #if (NGX_HAVE_REUSEPORT)?
|737if (ls[i].reuseport && ls[i].worker != ngx_worker) {?
|738continue;
?
|739}?
|740 #endif?
|741 ?
|742c = ngx_get_connection(ls[i].fd, cycle->log);
?
|754rev = c->read;
?
|821rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept?
|822: ngx_event_recvmsg;
?|856if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {?
|857return NGX_ERROR;
?
|858}?
ngx_event_accept 没有post flag,不进入队列,立即执行
ngx_event_s
-> ngx_event_handler_pt
epoll
ngx_event_use|1037if (module->name->len == value[1].len) {?
|1038if (ngx_strcmp(module->name->data, value[1].data) == 0) {?
|1039ecf->use = cf->cycle->modules[m]->ctx_index;
?
|1040ecf->name = module->name->data;
?
|1041 ?
|1042if (ngx_process == NGX_PROCESS_SINGLE?
|1043&& old_ecf?
|1044&& old_ecf->use != ecf->use)?
|1045{?
|1046ngx_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 ?
|1055return NGX_CONF_ERROR;
?
|1056}?
|1057 ?
|1058return NGX_CONF_OK;
?
|1059}?
|1060}?
-179 static ngx_event_module_tngx_epoll_module_ctx = {?
|180&epoll_name,?
|181ngx_epoll_create_conf,/* create configuration */?
|182ngx_epoll_init_conf,/* init configuration */?
|183 ?
|184{?
|185ngx_epoll_add_event,/* add an event */?
|186ngx_epoll_del_event,/* delete an event */?
|187ngx_epoll_add_event,/* enable an event */?
|188ngx_epoll_del_event,/* disable an event */?
|189ngx_epoll_add_connection,/* add an connection */?
|190ngx_epoll_del_connection,/* delete an connection */?
|191 #if (NGX_HAVE_EVENTFD)?
|192ngx_epoll_notify,/* trigger a notify */?
|193 #else?
|194NULL,/* trigger a notify */?
|195 #endif?
|196ngx_epoll_process_events,/* process the events */?
|197ngx_epoll_init,/* init the events */?
|198ngx_epoll_done,/* done the events */?
|199}?
|200 };
?
201 ?
-202 ngx_module_tngx_epoll_module = {?
|203NGX_MODULE_V1,?
|204&ngx_epoll_module_ctx,/* module context */?
|205ngx_epoll_commands,/* module directives */?
|206NGX_EVENT_MODULE,/* module type */?
|207NULL,/* init master */?
|208NULL,/* init module */?
|209NULL,/* init process */?
|210NULL,/* init thread */?
|211NULL,/* exit thread */?
|212NULL,/* exit process */?
|213NULL,/* exit master */?
|214NGX_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
318rev = c->read;
?
|319rev->handler = ngx_http_wait_request_handler;
?
|320c->write->handler = ngx_http_empty_handler;
?
ngx_http_wait_request_handler
|505rev->handler = ngx_http_process_request_line;
?
|506ngx_http_process_request_line(rev);
?
ngx_http_process_request_headers
ngx_http_process_request
|1944c->read->handler = ngx_http_request_handler;
?
|1945c->write->handler = ngx_http_request_handler;
?
http upstream 如果有帮助,扫一下,请我喝杯小蓝咖啡吧
文章图片
图片发自App
推荐阅读
- 深入理解Go之generate
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- 由浅入深理解AOP
- 逻辑回归的理解与python示例
- 【1057快报】深入机关,走下田间,交通普法,共创文明
- 生发知识,带你深入了解
- 「按键精灵安卓版」关于全分辨率脚本的一些理解(非游戏app)
- 深入理解|深入理解 Android 9.0 Crash 机制(二)
- 不理解句意,你还想做对所有GRE填空题()
- 深入浅出谈一下有关分布式消息技术(Kafka)