upstream 的启动 -- ngx_http_proxy_handler

2016-02-14 17:52:30   最后更新: 2016-02-14 18:33:15   访问数量:626




upstream 是 nginx http 模块的重要成员之一,此前我们介绍过 nginx http 模块执行的 11 个阶段:

HTTP 请求处理的 11 个阶段 -- ngx_http_handler

作为 http 模块的成员,upstream 模块的执行也逃不出这 11 个阶段

 

在 NGX_HTTP_FIND_CONFIG_PHASE 阶段(ngx_http_core_find_config_phase),nginx 在根据 uri 匹配对应的 location 并初始化请求结构对应字段的过程中,对于指定了启动函数的 module,会将启动函数赋值给请求描述结构的 content_handler 字段

而在生成 HTTP 响应的 NGX_HTTP_CONTENT_PHASE 阶段(ngx_http_core_content_phase),首先执行的就是:

if (r->content_handler) { r->write_event_handler = ngx_http_request_empty_handler; ngx_http_finalize_request(r, r->content_handler(r)); return NGX_OK; }

 

 

在 ngx_http_proxy_module 模块的 ngx_http_proxy_merge_loc_conf 函数中,如果转发方式是 upstream,他将会将 location 描述结构中启动函数 clcf->handler = ngx_http_proxy_handler 设为 ngx_http_proxy_handler,因此这里调用的 r->content_handler 就是 ngx_http_proxy_handler 函数

 

// static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) // upstream 执行函数 {{{ static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; ngx_http_proxy_ctx_t *ctx; ngx_http_proxy_loc_conf_t *plcf; // 创建并初始化请求描述结构中的 upstream 字段,即创建 upstream 描述结构 if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_proxy_module); plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); u = r->upstream; // 将 upstream 上游目标标记(http://、https:// 等)复制给 upstream 对应字段 if (plcf->proxy_lengths == NULL) { ctx->vars = plcf->vars; u->schema = plcf->vars.schema; #if (NGX_HTTP_SSL) u->ssl = (plcf->upstream.ssl != NULL); #endif } else { // 解析上游配置的机器信息 if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; u->conf = &plcf->upstream; // 注册相关默认回调函数 #if (NGX_HTTP_CACHE) u->create_key = ngx_http_proxy_create_key; #endif u->create_request = ngx_http_proxy_create_request; u->reinit_request = ngx_http_proxy_reinit_request; u->process_header = ngx_http_proxy_process_status_line; u->abort_request = ngx_http_proxy_abort_request; u->finalize_request = ngx_http_proxy_finalize_request; r->state = 0; if (plcf->redirects) { u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; } if (plcf->cookie_domains || plcf->cookie_paths) { u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; } u->buffering = plcf->upstream.buffering; // 为转发描述结构分配空间 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } // 赋值上游数据处理回调函数 u->pipe->input_filter = ngx_http_proxy_copy_filter; u->pipe->input_ctx = r; // 赋值包体处理前的初始化方法 u->input_filter_init = ngx_http_proxy_input_filter_init; // 赋值原始数据处理的回调函数 u->input_filter = ngx_http_proxy_non_buffered_copy_filter; u->input_filter_ctx = r; u->accel = 1; // upstream 的执行 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; } // }}}

 

他的主要工作是调用 ngx_http_upstream_create 创建初始化请求描述结构中的 upstream 字段,即创建 upstream 描述结构

紧接着对 upstream 描述结构中必要的字段和回调函数进行赋值和初始化

然后通过 ngx_http_read_client_request_body 函数调用 ngx_http_upstream_init 函数实现 upstream 的连接和通信,并生成 HTTP 响应返回

 

nginx 提供了初始化 ngx_http_request_t 结构中的 upstream 域的 upstream 创建函数 -- ngx_http_upstream_create

ngx_http_proxy_handler 的第一步工作就是调用 ngx_http_upstream_create 创建并初始化 ngx_http_request_t 中的 upstream 描述结构

// ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r) // 在请求中创建 upstream,初始化 r->upstream {{{ ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r) { ngx_http_upstream_t *u; u = r->upstream; if (u && u->cleanup) { r->main->count++; ngx_http_upstream_cleanup(r); } // 为 ngx_http_upstream_t 结构分配空间 u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { return NGX_ERROR; } r->upstream = u; u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #if (NGX_THREADS) u->peer.lock = &r->connection->lock; #endif #if (NGX_HTTP_CACHE) r->cache = NULL; #endif u->headers_in.content_length_n = -1; u->headers_in.last_modified_time = -1; return NGX_OK; } // }}}

 

 

这个函数为 upstream 在内存池中分配了空间,并进行了必要的初始化工作

在之前的日志中,我们介绍了 ngx_http_upstream_s 这个结构:

upstream 及其相关的数据结构

 

他描述了必要的回调函数及配置参数以及状态等信息

 

upstream 描述结构中有一个重要的成员 pipe,他描述了在 upstream 转发过程中上下游的各种信息及对原始数据进行处理的回调函数

// struct ngx_event_pipe_s // 事件转发结构,用于 upstream 过程中上下游转发 {{{ struct ngx_event_pipe_s { // 上下游连接描述结构 ngx_connection_t *upstream; ngx_connection_t *downstream; // 保存上游获取的原始数据 ngx_chain_t *free_raw_bufs; ngx_chain_t *in; ngx_chain_t **last_in; // 保存需要缓存到 tempfile 的数据 ngx_chain_t *out; ngx_chain_t *free; ngx_chain_t *busy; /* * the input filter i.e. that moves HTTP/1.1 chunks * from the raw bufs to an incoming chain */ // 对原始数据进行处理的回调函数 ngx_event_pipe_input_filter_pt input_filter; void *input_ctx; // 输出到 client 端前的处理回调函数 ngx_chain_writer ngx_event_pipe_output_filter_pt output_filter; void *output_ctx; unsigned read:1; unsigned cacheable:1; unsigned single_buf:1; unsigned free_bufs:1; unsigned upstream_done:1; unsigned upstream_error:1; unsigned upstream_eof:1; unsigned upstream_blocked:1; unsigned downstream_done:1; unsigned downstream_error:1; unsigned cyclic_temp_file:1; // 已分配的 buf 数 ngx_int_t allocated; ngx_bufs_t bufs; ngx_buf_tag_t tag; ssize_t busy_size; off_t read_length; off_t length; // 配置的 max_temp_file_size 属性值 off_t max_temp_file_size; // buf 映射到 temp_file 的大小 ssize_t temp_file_write_size; ngx_msec_t read_timeout; ngx_msec_t send_timeout; ssize_t send_lowat; ngx_pool_t *pool; ngx_log_t *log; // 从上游预读的 buf ngx_chain_t *preread_bufs; size_t preread_size; ngx_buf_t *buf_to_file; size_t limit_rate; time_t start_sec; // temp_file 描述结构 ngx_temp_file_t *temp_file; /* STUB */ int num; }; // }}}

 

 

 

 






技术帖      龙潭书斋      nginx      server      源码      sourcecode      webserver      upstream      ngx_http_upstream_module      ngx_http_proxy_handler      转发     


1#沈七: (回复)2017-11-10 17:39:26

代码部分观赏效果很差。。

京ICP备15018585号