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 , ; , 。
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Haproxy 폴링 서버 세트1) 모니터링 포트 서비스 2) 서로 다른 웹 페이지를 대상으로 서로 다른 서버 집합에 전송...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.