深入理解 nginx和nginx-lua

最近一段時間,公司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

如果有幫助沧烈,掃一下,請我喝杯小藍咖啡吧

圖片發(fā)自簡書App
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末像云,一起剝皮案震驚了整個濱河市锌雀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迅诬,老刑警劉巖腋逆,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異侈贷,居然都是意外死亡惩歉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門俏蛮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撑蚌,“玉大人,你說我怎么就攤上這事搏屑≌浚” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵辣恋,是天一觀的道長亮垫。 經(jīng)常有香客問我,道長伟骨,這世上最難降的妖魔是什么饮潦? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮底靠,結果婚禮上害晦,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好壹瘟,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布鲫剿。 她就那樣靜靜地躺著,像睡著了一般稻轨。 火紅的嫁衣襯著肌膚如雪灵莲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天殴俱,我揣著相機與錄音政冻,去河邊找鬼。 笑死线欲,一個胖子當著我的面吹牛明场,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播李丰,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼苦锨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了趴泌?” 一聲冷哼從身側響起舟舒,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗜憔,沒想到半個月后秃励,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡吉捶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年夺鲜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呐舔。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡谣旁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滋早,到底是詐尸還是另有隱情,我是刑警寧澤砌们,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布杆麸,位于F島的核電站,受9級特大地震影響浪感,放射性物質(zhì)發(fā)生泄漏昔头。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一影兽、第九天 我趴在偏房一處隱蔽的房頂上張望揭斧。 院中可真熱鬧,春花似錦、人聲如沸讹开。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旦万。三九已至闹击,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間成艘,已是汗流浹背赏半。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淆两,地道東北人断箫。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像秋冰,于是被迫代替她去往敵國和親仲义。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355