Nginx upstream 원리 분석 [1] upstream 과 FastCGI 전편

25585 단어 Haproxy
      “Nginx upstream    【1】        ”           accept ngx_http_core_run_phases          ,       FCGI      ,        。

0、      
ngx_http_core_run_phases       cmcf->phase_engine.handlers   checker,    rewrite  ,find_config             ,          FCGI     , checker    ngx_http_core_content_phase,     ngx_http_fastcgi_handler       。

  ngx_http_fastcgi_handler  nginx        ,    ngx_string(“fastcgi_pass”),        ngx_http_fastcgi_pass()      ,      clcf->handler = ngx_http_fastcgi_handler;,       location conf handler  ;

 nginx  rewrite,       ,    ngx_http_update_location_config  ,          ,      handler       r->content_handler     ,   ngx_http_core_content_phase  ,      content_handler。       ,    ngx_http_fastcgi_handler   :

ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r,   ngx_http_phase_handler_t *ph)
{
    size_t     root;
    ngx_int_t  rc;
    ngx_str_t  path;

    if (r->content_handler) {
//   content_handler,        .     FCGI,     fastcgi_pass   127.0.0.1:8777;   
//   ngx_http_fastcgi_pass  ,   location   hander ngx_http_fastcgi_handler。
//   ngx_http_update_location_config     content_handler     loc      。
        r->write_event_handler = ngx_http_request_empty_handler;
        ngx_http_finalize_request(r, r->content_handler(r));
        return NGX_OK;
    }
//······

}

static char *
ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{//nginx    fastcgi_pass         .  fastcgi_pass   127.0.0.1:8777;
    ngx_http_fastcgi_loc_conf_t *flcf = conf;
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    //    ,  ngx_http_update_location_config     content_handle ,   content phase    
    clcf->handler = ngx_http_fastcgi_handler;
//`````
}
void ngx_http_update_location_config(ngx_http_request_t *r)
29
{//      。  loc_conf   ,           r        。
//      r->content_handler = clcf->handler;,    。
    if (clcf->handler) {//          handler,       content_handler    ,       phase   ,   。
//ngx_http_fastcgi_handler       ,   ngx_http_core_content_phase      FCGI  ,             
//····
//proxy    ngx_http_proxy_handler。
        r->content_handler = clcf->handler;
    }
}
1、ngx_http_fastcgi_handler      :
ngx_http_fastcgi_handler    nginx     header   ,    ngx_http_core_content_phase        ,    upstream    ,  upstream    fastcgi    proxy     。       :fastcgi  upstream,       ,  upstream           。        。

    ngx_http_upstream_create    upstream  ,   r->upstream   ,              upstream ;
    upstream       create_request,process_header,finalize_request ;
   u->pipe->input_filter ngx_http_fastcgi_input_filter,       FCGI       ,  event_pipe      ,   , “Nginx upstream    【2】- buffering  upstream  ”        ;
      ngx_http_read_client_request_body  ,          BODY,          ngx_http_upstream_init,       BODY   ,    ngx_http_upstream_init      upstream  ,          FCGI,  PHP。
  upstream         ,        :

u->create_request = ngx_http_fastcgi_create_request;//                     (       ),   u->request_bufs     。

u->reinit_request = ngx_http_fastcgi_reinit_request;//             ( create_request        )   

u->process_header = ngx_http_fastcgi_process_header;//             bit,                  

u->finalize_request = ngx_http_fastcgi_finalize_request;// Nginx                 

         :

static ngx_int_t
ngx_http_fastcgi_handler(ngx_http_request_t *r)
{//FCGI    ,ngx_http_core_run_phases               。
//ngx_http_core_find_config_phase   ngx_http_update_location_config  
    ngx_int_t                     rc;
    ngx_http_upstream_t          *u;
    ngx_http_fastcgi_ctx_t       *f;
    ngx_http_fastcgi_loc_conf_t  *flcf;
 
    if (r->subrequest_in_memory) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_http_fastcgi_module does not support subrequest in memory");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_upstream_create(r) != NGX_OK) {//    ngx_http_upstream_t  ,  r->upstream   。
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));

    if (f == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);//r->ctx[module.ctx_index] = c;       fcgi_ctx_t       ctx  
    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);//  fcgi   。(r)->loc_conf[module.ctx_index]

    if (flcf->fastcgi_lengths) {//    fcgi   ,           。
        if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {//  fastcgi_pass   127.0.0.1:9000;   URL   。       ;
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    u = r->upstream;
    ngx_str_set(&u->schema, "fastcgi://");// fcgi  。
    u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
    u->conf = &flcf->upstream;
#if (NGX_HTTP_CACHE)
    u->create_key = ngx_http_fastcgi_create_key;//  flcf->cache_key           scgi_cache_key line;          line;
#endif
    u->create_request = ngx_http_fastcgi_create_request;
    u->reinit_request = ngx_http_fastcgi_reinit_request;
    u->process_header = ngx_http_fastcgi_process_header;
    u->abort_request = ngx_http_fastcgi_abort_request;
    u->finalize_request = ngx_http_fastcgi_finalize_request;
    //         event_pipe  ,   FCGI     buffering   。FCGI   buffering
    u->buffering = 1;
    u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));

    if (u->pipe == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    //    fcgi         ,      \r
\r
FCGI , 。 u->pipe->input_filter = ngx_http_fastcgi_input_filter; u->pipe->input_ctx = r; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; } 2、 ngx_http_read_client_request_body: ngx_http_read_client_request_body BODY, 2 : r->header_in; , 。 2 ngx_http_request_body_t , r->request_body = rb; 。 : typedef struct { // POST , ngx_temp_file_t *temp_file; // BODY BUFFER , HEADER , 2 ngx_chain_t *bufs; // POST , ngx_buf_t *buf; //r->headers_in.content_length_n - preread; , 。 off_t rest; // 。 ngx_chain_t *to_write; //POST HANDLER , ngx_http_upstream_init ngx_http_client_body_handler_pt post_handler; } ngx_http_request_body_t; 2 , BODY。 、 body: , discard_body, ngx_http_upstream_init upstream ; ngx_http_test_expect HTTP/1.1 100 Continue; ngx_http_request_body_t , r->request_body = rb; content_length_n 0, BODY, OK, ngx_http_upstream_init 。 : /* * on completion ngx_http_read_client_request_body() adds to * r->request_body->bufs one or two bufs: * *) one memory buf that was preread in r->header_in; , * *) one memory or file buf that contains the rest of the body */ ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) {//post_handler = ngx_http_upstream_init。NGINX BODY upstream ,GOOD size_t preread; ssize_t size; ngx_buf_t *b; ngx_chain_t *cl, **next; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; r->main->count++; if (r->request_body || r->discard_body) {//discard_body 。 。 post_handler(r);// , ngx_http_upstream_init return NGX_OK; } if (ngx_http_test_expect(r) != NGX_OK) {// HTTP/1.1 100 Continue return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->request_body = rb;// , 。 if (r->headers_in.content_length_n < 0) { post_handler(r);// body , 0 return NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_in.content_length_n == 0) {// content_length_n if (r->request_body_in_file_only) {//client_body_in_file_only 0 。 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = clcf->client_body_temp_path; tf->pool = r->pool; tf->warn = "a client request body is buffered to a temporary file"; tf->log_level = r->request_body_file_log_level; tf->persistent = r->request_body_in_persistent_file; tf->clean = r->request_body_in_clean_file; if (r->request_body_file_group_access) { tf->access = 0660; } rb->temp_file = tf;// POST body。 0 , 。 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } // content_length_n 0, 。 init post_handler(r);// GET return NGX_OK; } 、 body, : body ,nginx ngx_http_upstream_init rb->post_handler , body 。 nginx r->header_in BODY, , buf , rb->bufs 。 , body, ngx_http_upstream_init, 。 , , : // , content_length_n 0 , POST 。 , POST , ngx_http_upstream_init rb->post_handler = post_handler; preread = r->header_in->last - r->header_in->pos;// , 。 if (preread) {// /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client request body preread %uz", preread); b = ngx_calloc_buf(r->pool);// ngx_buf_t , if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->temporary = 1; b->start = r->header_in->pos;// 。 POS 。 ,HEADERS 。 b->pos = r->header_in->pos; b->last = r->header_in->last; b->end = r->header_in->end; rb->bufs = ngx_alloc_chain_link(r->pool);// buf 。 2 BODY if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->bufs->buf = b;// BODY rb->bufs->next = NULL;// rb->buf = b;//ngx_http_request_body_t buf buf if ((off_t) preread >= r->headers_in.content_length_n) {//OK, BODY , , ngx_http_upstream_init /* the whole request body was pre-read */ r->header_in->pos += (size_t) r->headers_in.content_length_n; r->request_length += r->headers_in.content_length_n;// if (r->request_body_in_file_only) {// , if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } post_handler(r);// return NGX_OK; } // , 。 /* * to not consider the body as pipelined request in * ngx_http_set_keepalive() */ r->header_in->pos = r->header_in->last;// , , r->request_length += preread;// rb->rest = r->headers_in.content_length_n - preread;// , 。 if (rb->rest <= (off_t) (b->end - b->last)) {// BUFFER , 。 /* the whole request body may be placed in r->header_in */ rb->to_write = rb->bufs;// rb->bufs->buf = b; r->read_event_handler = ngx_http_read_client_request_body_handler;// return ngx_http_do_read_client_request_body(r);// } // BUFFER 。 。 next = &rb->bufs->next;// buf } else { b = NULL;// rb->rest = r->headers_in.content_length_n;// 。 next = &rb->bufs;// bufs } , BODY 0, , , body, rb->rest BODY , next &rb->bufs->next; ngx_http_request_body_t next 。 , next , &rb->bufs->next &rb->bufs; , rb->bufs 。 ngx_http_do_read_client_request_body , , c->recv(c, rb->buf->last, size);// 。 ngx_unix_recv, , epoll 。 ngx_http_do_read_client_request_body readv BODY, , POST , r->request_body , , post_handler, ngx_http_upstream_init。 size = clcf->client_body_buffer_size;// 。 size += size >> 2;// size + 1/4*size, 1.25 , (1.25 ), , 。 if (rb->rest < size) {// 1.25 size = (ssize_t) rb->rest;// if (r->request_body_in_single_buf) {// buffer 。 size += preread; } } else {// 1.25 POST , POST 。 size = clcf->client_body_buffer_size; /* disable copying buffer for r->request_body_in_single_buf */ b = NULL; } rb->buf = ngx_create_temp_buf(r->pool, size);// if (rb->buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl = ngx_alloc_chain_link(r->pool);// if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = rb->buf;// , 。 cl->next = NULL;// 。 if (b && r->request_body_in_single_buf) {// buffer , size = b->last - b->pos; ngx_memcpy(rb->buf->pos, b->pos, size); rb->buf->last += size; next = &rb->bufs;// 。 } *next = cl;//GOOD, 。 , buffer, , 。 if (r->request_body_in_file_only || r->request_body_in_single_buf) { rb->to_write = rb->bufs;// 。 buffer, } else {// , 2 BUFFER, , 。 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; } r->read_event_handler = ngx_http_read_client_request_body_handler;// , , return ngx_http_do_read_client_request_body(r);// } ngx_http_do_read_client_request_body BODY, rb->post_handler(r); ngx_http_upstream_init 。 3、ngx_http_upstream_init_request : ngx_http_upstream_init , EVENT , ngx_http_upstream_init_request 。 2 : 1. create_request fcgi proxy 。 2. ngx_http_upstream_connect 。 , cache 。 u->create_request(r), r->request_body->bufs u->request_bufs FastCGI , u->request_bufs 。 create_request , FCGI ngx_http_fastcgi_create_request,proxy ngx_http_proxy_create_request , 。 u->output , , output_filter 。 static void ngx_http_upstream_init_request(ngx_http_request_t *r) { //ngx_http_upstream_init , 。 /* 1. create_request fcgi proxy 。 2. ngx_http_upstream_connect 。 */ ngx_str_t *host; ngx_uint_t i; ngx_resolver_ctx_t *ctx, temp; ngx_http_cleanup_t *cln; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; ngx_http_upstream_srv_conf_t *uscf, **uscfp; ngx_http_upstream_main_conf_t *umcf; u = r->upstream;//ngx_http_upstream_create u->store = (u->conf->store || u->conf->store_lengths); if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {//ignore_client_abort 。 。 r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;// 。 r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; } if (r->request_body) {// POST ,ngx_http_read_client_request_body u->request_bufs = r->request_body->bufs;// , create_request 。 } // FCGI。 FCGI , , , STDIN 。 u->request_bufs 。 // Proxy ,ngx_http_proxy_create_request , u->request_bufs if (u->create_request(r) != NGX_OK) {//ngx_http_fastcgi_create_request ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } u->peer.local = u->conf->local; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.alignment = clcf->directio_alignment; u->output.pool = r->pool; u->output.bufs.num = 1; u->output.bufs.size = clcf->client_body_buffer_size; // writer。 output_filter。 ngx_output_chain u->output.output_filter = ngx_chain_writer; u->output.filter_ctx = &u->writer;// ngx_chain_writer, buf 。 u->writer.pool = r->pool; if (r->upstream_states == NULL) {// upstream_states, upstream 。 r->upstream_states = ngx_array_create(r->pool, 1, sizeof(ngx_http_upstream_state_t)); if (r->upstream_states == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } } else {// , 。 u->state = ngx_array_push(r->upstream_states); if (u->state == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); } // , cln = ngx_http_cleanup_add(r, 0);// , 。 if (cln == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } cln->handler = ngx_http_upstream_cleanup;// cln->data = r;// 。 u->cleanup = &cln->handler; fastcgi_pass URL , unix , socket. ngx_http_fastcgi_handler , , 。 , , :http://www.pagefault.info/?p=251。 ngx_http_upstream_init_request FCGI , ngx_http_upstream_connect FCGI。 4、ngx_http_upstream_connect FastCGI: ngx_http_upstream_connect FCGI , 。 。 socket,connect peer, , ngx_http_upstream_send_request 。 , 。 , ngx_http_upstream_send_request 。 ngx_event_connect_peer, peer, socket(),connect(),add_event 。 : ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) {// peer, . , rc = pc->get(pc, pc->data);//ngx_http_upstream_get_round_robin_peer peer s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0);// SOCK // ngx_cycle->free_connections , c = ngx_get_connection(s, pc->log); // 。 if (ngx_nonblocking(s) == -1) {} // 。 c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; rc = connect(s, pc->sockaddr, pc->socklen);// if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {// } if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {// } } ngx_http_upstream_connect : static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { // socket,connect peer, , ngx_http_upstream_send_request // , 。 , ngx_http_upstream_send_request 。 ngx_int_t rc; ngx_time_t *tp; ngx_connection_t *c; r->connection->log->action = "connecting to upstream"; r->connection->single_connection = 0; if (u->state && u->state->response_sec) { tp = ngx_timeofday();// u->state->response_sec = tp->sec - u->state->response_sec;// 。 u->state->response_msec = tp->msec - u->state->response_msec; } // u->state = ngx_array_push(r->upstream_states);// if (u->state == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); tp = ngx_timeofday(); u->state->response_sec = tp->sec; u->state->response_msec = tp->msec; // , 。 rc = ngx_event_connect_peer(&u->peer);// peer, socket(),connect(),add_event ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream connect: %i", rc); if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } u->state->peer = u->peer.name; if (rc == NGX_BUSY) {// peer , , 。 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);// , ngx_http_upstream_connect 。 return; } if (rc == NGX_DECLINED) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);// 。 return; } , 。 /* rc == NGX_OK || rc == NGX_AGAIN */ c = u->peer.connection;// peer 。 c->data = r;// 。 c->write->handler = ngx_http_upstream_handler;// 。 。 write_event_handler。 c->read->handler = ngx_http_upstream_handler;// , write_event_handler // upstream , upstream 。 ngx_http_upstream_handler upstream 。 u->write_event_handler = ngx_http_upstream_send_request_handler;// 。 u->read_event_handler = ngx_http_upstream_process_header;// c->sendfile &= r->connection->sendfile; u->output.sendfile = c->sendfile; c->pool = r->pool; c->log = r->connection->log; c->read->log = c->log; c->write->log = c->log; /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ u->writer.out = NULL;// i ngx_chain_write 。 u->writer.last = &u->writer.out;// 。 。 u->writer.connection = c; u->writer.limit = 0; , BODY, , r->request_body->buf u->output->free , 。 ngx_http_upstream_send_request 。 if (u->request_sent) {// 。 , if (ngx_http_upstream_reinit(r, u) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } } if (r->request_body // POST ,ngx_http_read_client_request_body && r->request_body->buf && r->request_body->temp_file && r == r->main) {//request_body FCGI 。 BODY, BODY , r->request_body->buf 。 /* * the r->request_body->buf can be reused for one request only, * the subrequests should allocate their own temporay bufs */ u->output.free = ngx_alloc_chain_link(r->pool); if (u->output.free == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; }// 。 // BODY , ? output , send_request u->output.free->buf = r->request_body->buf; u->output.free->next = NULL; u->output.allocated = 1; // , ? FCGI ngx_http_upstream_s request_bufs r->request_body->buf->pos = r->request_body->buf->start; r->request_body->buf->last = r->request_body->buf->start; r->request_body->buf->tag = u->output.tag; } u->request_sent = 0;// 。 if (rc == NGX_AGAIN) {// rc , 。 ngx_add_timer(c->write, u->conf->connect_timeout); return; } #if (NGX_HTTP_SSL) if (u->ssl && c->ssl == NULL) { ngx_http_upstream_ssl_init_connection(r, u, c); return; } #endif ngx_http_upstream_send_request(r, u);// , 。 } 5、ngx_http_upstream_send_request FCGI PHP: ngx_http_upstream_send_request , ; , 。

좋은 웹페이지 즐겨찾기