nginx upstream的实现

很多其他模块会调用该模块完成对后端服务器的访问
upstream模块还是一个http模块,所有它自己必须要实现一些特定的接口:
1.static ngx_command_t ngx_http_upstream_commands[] = {

{ ngx_string("upstream"),

  NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,

  ngx_http_upstream,

  0,

  0,

  NULL },



{ ngx_string("server"),

  NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,

  ngx_http_upstream_server,

  NGX_HTTP_SRV_CONF_OFFSET,

  0,

  NULL },



  ngx_null_command

};
//这里表明upstream是对upstream指令和内部的server指令感兴趣
2.static ngx_http_module_t ngx_http_upstream_module_ctx = {

ngx_http_upstream_add_variables,       /* preconfiguration */

NULL,                                  /* postconfiguration */



ngx_http_upstream_create_main_conf,    /* create main configuration */

ngx_http_upstream_init_main_conf,      /* init main configuration */

3.ngx_module_t ngx_http_upstream_module = {

NGX_MODULE_V1,

&ngx_http_upstream_module_ctx,         /* module context */

ngx_http_upstream_commands,            /* module directives */

NGX_HTTP_MODULE,                       /* module type */

4.它的相关函数,可以类比http模块的处理方式:
注意它内部也会有分配保存配置结构体的使用
5.nginx的使用:
在ngx_upstream_t结构体中会有五个回调函数指针,开发人员按需注册自己需要的函数,那么就可以使用upstream了
那么所注册的hanlder回调函数,它的一般的流程是:
1》创建一个ngx_upstream_t结构体
2》申请一个请求上下文
3》把该请求上下文设置到对应得模块中
4》开始注册回调函数:
u->create_request:设置创建请求报文的回调函数
u->reinit_request:设置当连接失败以后需要执行的动作
u->process_header:设置处理上游服务器的响应头回调函数
u->finalize_request:销毁upstream请求的时候调用
u->buffering:
//upstream的标志位,为0时以下游网速优先,不会使用文件缓存,为1时有多个buffer,并且可以使用文件来缓存响应包体
u->pipe:
//当buffering为1时,会使用到该结构,即上游网速优先,需要使用多个buffer来缓存响应
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
//开始读取请求包体,并且调用ngx_http_upstream_init,该函数的作用是启动upstream机制,但是这里要注意一点在启动之前要设置一个ngx_http_upstream_conf_t配置结构体,它指定的是upstream的运行机制,
6.upstream的运行过程:
ngx_http_upstream_init:
根据ngx_http_upstream_conf_t中的成员初始化upstream
同时开始连接上游服务器
具体流程:
a.调用某个http模块实现的create_request方法构造出报文,
b.调用ngx_http_upstream_connect向上游服务器发起连接
c = u->peer.connection;
c->data = r;
//将客户端与上游服务器的连接的读写事件的处理回调设置为
//ngx_http_upstream_handler
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
//ngx_http_upstream_handler最后会调用u->write_event_handler或者read_event_handler
u->write_event_handler = ngx_http_upstream_send_request_handler;
u->read_event_handler = ngx_http_upstream_process_header;

ngx_http_upstream_send_request(r, u);
//代表已经建立连接,向上游服务器发送请求内容
注意这里请求不是一次性就可以发送完的,所以需要多次加入epoll中进行监控,所以它最终调用ngx_http_upstream_send_request发送请求,但是如果一次性没有发送完的话就要调用上面的ngx_http_upstream_send_request_handler;发送
c.当建立了与上游的连接以后就会向上游服务器发送请求,
ngx_http_upstream_send_request:
主要是调用ngx_output_chain向上游服务器发送请求报文
紧接着就会调用 ngx_http_upstream_process_header(r, u);来解析响应头了,该函数是Http模块自己实现的
d. ngx_http_upstream_process_header(r, u)
接收到的响应头部存储到ngx_http_upstream_t的buffer缓冲区中,
然后recv
然后调用http模块自己实现的u->process header处理接收到的响应头,负责进行解析
对解析出的错误头进行相关处理,比如返回404
再次调用ngx_http_upstream_process_headers()把u->headers_in中的各个头部信息设置到r->headers_out中,以便于发送

if (!r->subrequest_in_memory) {
//调用该函数,先转发响应头,再转发响应体
ngx_http_upstream_send_response(r, u);
return;
}
//如果是父请求,需要转发响应体,就调用上面那个函数
如果是子请求的话,使用子请求的input_filter进行处理
默认的input_filter是不转发
u->read_event_handler = ngx_http_upstream_process_body_in_memory//设置接收事件的处理函数,
ngx_http_upstream_process_body_in_memory(r, u);
这个是处理子请求的情况,即不转发包体的情况,在内存中对包体进行处理
e.处理响应包体:
在子请求中不需要转发包体,只是处理一下就可以,在父请求的模式下需要转发包体,这时有上游网速优先和下游网速优先俩种情况,如果下游网速优先,那么就需要分配一块固定大小的buffer去接收缓冲区,同时进行转发,如果上游网速优先的话,那么就需要更多的buffer去缓冲数据,同时还可能使用临时文件
ngx_http_upstream_process_body_in_memory(r, u);:该函数用来处理子请求,即不转发响应包,即subrequest_in_memory=1的时候使用这种处理方式,它会调用http模块实现的input_filtr方法处理接收到的包体,如果http模块没有实现,那么就调用默认的ngx_http_upstream_non_buffered_filter,如果实现了那就使用http实现的input filter,注意这个input_filter方法的实现其实最主要的是对buffer的使用
ngx_http_upstream_send_response:该函数用来处理父请求,即转发响应包体的情形,且同时考虑上下游速度的情况,他会根据ngx_http_upstream_conf_t中的buffering标志决定是否打开缓存处理,为0默认下游更快
它会根据不同的设置调用不同的转发方式:
调用ngx_http_send_header向下游客户端发送http包头,即发送headers_out中的头部
//c是客户端与nginx之间建立的连接
c = r->connection;
//将header_sent置位,表示响应头部已经发送了
u->header_sent = 1;
接下来是清除请求中的临时文件
//获得http core在该loc下的配置
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
//u->buffering为0表示下游网速优先,不需要开辟更多的缓存区
//来存放相关回应报文
** if (!u->buffering) {
//未设置input_filter的话,设置默认的处理函数,input_filter是对
//在buffer中接收到的数据进行相应处理,感觉主要有两个功能
//一是把相关buffer挂到out链表,一是对内容进行过滤
if (u->input_filter == NULL) {
//啥都不做
u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
//该函数试图在buffer中缓存所有的数据,会操作设置ngx_buf中的
//各个字段
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
//设置upstream读事件的处理回调函数,当上游服务器接收到响应的时候可以调用这个接收响应
u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;

//设置request写事件的处理回调函数,一旦向客户端的tcp连接上可写的时候调用这个函数
r->write_event_handler =
           ngx_http_upstream_process_non_buffered_downstream;

接下来的代码继续设置Buffer的相关指针,
调用input_filter方法处理包体(http模块没有实现的话就用默认的)
//在该函数中,开始向下游客户端发送响应包体,
//发送完数据还会从上游接收包体
ngx_http_upstream_process_non_buffered_downstream(r);
//有数据可以进行处理,处理上游数据,在该函数中
//收完上游包体也会往下游发送相应。即接收上游包体
if (u->peer.connection->read->ready) {
ngx_http_upstream_process_non_buffered_upstream(r, u);
}
注意上述俩个函数的底层是ngx_http_upstream_process_non_bufferd_request
**如果bufferinf=1,那么就代表着需要更多的缓存去缓冲数据,这个时候需要一个ngx_event_pipt_t结构体来实现转发
对包头的转发同样是ngx_http_send_header
ngx_http_upstream_process_non_buffered_downstream(r)
ngx_http_upstream_process_non_buffered_upstream(r, u);
实现,但是底层是ngx_event_pipe实现,通过一个参数标记来控制读写方向
ngx_event_pipe_read_upstream和
ngx_event_pipe_write_to_downstream实现
f.结束upstream请求:
当nginx与上游服务器的交互出现错误时,或者正常处理完请求时,就需要结束请求,这个时候不能简单的调用ngx_http_finalize_request结束请求,这样无法结束upstream请求,
upstream提供了俩个独特的方法,一个是ngx_http_upstream_cleanup和ngx_http_upstream_next
在启动upstream的时候,ngx_http_upstream_cleanup会挂载到请求的cleanup链表中,Http框架在结束请求的时候会调用该方法,而该方法实际上是调用了ngx_http_upstream_finalize_request结束请求的

当处理请求出现错误的时候,往往会调用Ngx_http_upstream_next方法。这是upstream提供的一个比较灵活的方法,比如出错时并不是立刻结束请求,而是再尝试连接一次。

ngx_http_upstream_request_finalize的实现:
它的主要功能就是清理与上游服务器的交互资源,然后调用框架提供的ngx_http_finalixe_request.

猜你喜欢

转载自blog.csdn.net/wellwang1993/article/details/51200985
今日推荐