深入理解|深入理解 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 如果有帮助,扫一下,请我喝杯小蓝咖啡吧
深入理解|深入理解 nginx和nginx-lua
文章图片
图片发自App

    推荐阅读