概述 upstream是nginx向上游发起tcp请求的一种机制。在nginx中有很多有用的模块都用到了该机制,例如proxy模块,memcache模块等。 upstream模块提供了两个配置指令:upstream和server来指定上游服务器地址。 代码 upstream机制的实现是在ngx_http_upstream.h|c, ngx_http_upstream_round_robin.h|c 这几个文件中。 先从程序启动解析配置指令开始。调用逻辑在ngx_http_block函数中。 首先会调用ctx的函数指针指向的ngx_http_upstream_create_main_conf函数创建一个结构体保存配置: typedef struct { ngx_hash_t headers_in_hash; ngx_array_t upstreams; // 一组上游服务器数组 /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t; 接着会调用ctx的另一个函数指针指向的函数ngx_http_upstream_add_variables添加变量。 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf) { ngx_http_variable_t *var, *v; for (v = ngx_http_upstream_vars; v->name.len; v++) { var = ngx_http_add_variable(cf, &v->name, v->flags); if (var == NULL) { return NGX_ERROR; } var->get_handler = v->get_handler; var->data = v->data; } return NGX_OK; } 接着会解析NGX_HTTP_MAIN_CONF级别的配置,upstream模块只有upstream指令是该级别的。读取配置内容,直到处理到upstream name { … } ,会调用ngx_http_upstream函数处理。 // 对应一组上游服务器,也就是一个upstream指令 struct ngx_http_upstream_srv_conf_s { ngx_http_upstream_peer_t peer; void **srv_conf; ngx_array_t *servers; /* ngx_http_upstream_server_t */ // server 指令对应的配置,实际的上游服务器的地址 ngx_uint_t flags; ngx_str_t host; // 一组上游服务器的名称 u_char *file_name; ngx_uint_t line; in_port_t port; ngx_uint_t no_port; /* unsigned no_port:1 */ #if (NGX_HTTP_UPSTREAM_ZONE) ngx_shm_zone_t *shm_zone; #endif }; typedef struct { ngx_str_t name; ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; ngx_uint_t max_conns; ngx_uint_t max_fails; time_t fail_timeout; ngx_msec_t slow_start; unsigned down:1; unsigned backup:1; NGX_COMPAT_BEGIN(6) NGX_COMPAT_END } ngx_http_upstream_server_t; static char * ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { char *rv; void *mconf; ngx_str_t *value; ngx_url_t u; ngx_uint_t m; ngx_conf_t pcf; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *http_ctx; ngx_http_upstream_srv_conf_t *uscf; ngx_memzero(&u, sizeof(ngx_url_t)); value = cf->args->elts; u.host = value[1]; // name 一组上游服务器的名称。 u.no_resolve = 1; u.no_port = 1; // 分配ngx_http_upstream_srv_conf_t结构体添加到umcf->upstreams数组 uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE |NGX_HTTP_UPSTREAM_WEIGHT |NGX_HTTP_UPSTREAM_MAX_CONNS |NGX_HTTP_UPSTREAM_MAX_FAILS |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT |NGX_HTTP_UPSTREAM_DOWN |NGX_HTTP_UPSTREAM_BACKUP); if (uscf == NULL) { return NGX_CONF_ERROR; } // http模块下每个block配置都会对应一个这样的上下文 // 指明所属block的模块配置 和 本block的模块配置 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } http_ctx = cf->ctx; // main_conf 指向所属的http{} ctx->main_conf = http_ctx->main_conf; /* the upstream{}'s srv_conf */ ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->srv_conf == NULL) { return NGX_CONF_ERROR; } // upstream 模块srv级别创建配置文件结构体的函数指针为空,所以再下边数组赋值不会被覆盖掉 ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf; uscf->srv_conf = ctx->srv_conf; /* the upstream{}'s loc_conf */ ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; } for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; if (module->create_srv_conf) { mconf = module->create_srv_conf(cf); if (mconf == NULL) { return NGX_CONF_ERROR; } // srv_conf 数组包含了所有模块的srv级别的配置 ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf; } if (module->create_loc_conf) { mconf = module->create_loc_conf(cf); if (mconf == NULL) { return NGX_CONF_ERROR; } // loc_conf 数组包含了所有模块的loc级别的配置 ctx->loc_conf[cf->cycle->modules[m]->ctx_index] = mconf; } } uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_server_t)); if (uscf->servers == NULL) { return NGX_CONF_ERROR; } /* parse inside upstream{} */ pcf = *cf; cf->ctx = ctx; cf->cmd_type = NGX_HTTP_UPS_CONF; // 解析NGX_HTTP_UPS_CONF级别的配置 // 该级别的配置指令有server,配置上游服务器地址的。有ip_hash 配置负载均衡策略的。 rv = ngx_conf_parse(cf, NULL); *cf = pcf; if (rv != NGX_CONF_OK) { return rv; } if (uscf->servers->nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no servers are inside upstream"); return NGX_CONF_ERROR; } return rv; } 开始解析NGX_HTTP_UPS_CONF级别的server指令,对应的函数ngx_http_upstream_server。 static char * ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_upstream_srv_conf_t *uscf = conf; time_t fail_timeout; ngx_str_t *value, s; ngx_url_t u; ngx_int_t weight, max_conns, max_fails; ngx_uint_t i; ngx_http_upstream_server_t *us; us = ngx_array_push(uscf->servers); if (us == NULL) { return NGX_CONF_ERROR; } ngx_memzero(us, sizeof(ngx_http_upstream_server_t)); value = cf->args->elts; weight = 1; max_conns = 0; max_fails = 1; fail_timeout = 10; for (i = 2; i < cf->args->nelts; i++) { if (ngx_strncmp(value[i].data, "weight=", 7) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) { goto not_supported; } weight = ngx_atoi(&value[i].data[7], value[i].len - 7); if (weight == NGX_ERROR || weight == 0) { goto invalid; } continue; } if (ngx_strncmp(value[i].data, "max_conns=", 10) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_CONNS)) { goto not_supported; } max_conns = ngx_atoi(&value[i].data[10], value[i].len - 10); if (max_conns == NGX_ERROR) { goto invalid; } continue; } if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) { goto not_supported; } max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10); if (max_fails == NGX_ERROR) { goto invalid; } continue; } if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) { goto not_supported; } s.len = value[i].len - 13; s.data = &value[i].data[13]; fail_timeout = ngx_parse_time(&s, 1); if (fail_timeout == (time_t) NGX_ERROR) { goto invalid; } continue; } if (ngx_strcmp(value[i].data, "backup") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) { goto not_supported; } us->backup = 1; continue; } if (ngx_strcmp(value[i].data, "down") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { goto not_supported; } us->down = 1; continue; } goto invalid; } ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[1]; u.default_port = 80; if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in upstream \"%V\"", u.err, &u.url); } return NGX_CONF_ERROR; } us->name = u.url; us->addrs = u.addrs; us->naddrs = u.naddrs; us->weight = weight; us->max_conns = max_conns; us->max_fails = max_fails; us->fail_timeout = fail_timeout; return NGX_CONF_OK; invalid: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; not_supported: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "balancing method does not support parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } 转载请注明:爱开源 » nginx的http模块的upstream机制
概述
upstream是nginx向上游发起tcp请求的一种机制。在nginx中有很多有用的模块都用到了该机制,例如proxy模块,memcache模块等。
upstream模块提供了两个配置指令:upstream和server来指定上游服务器地址。
代码
upstream机制的实现是在ngx_http_upstream.h|c, ngx_http_upstream_round_robin.h|c 这几个文件中。
先从程序启动解析配置指令开始。调用逻辑在ngx_http_block函数中。
首先会调用ctx的函数指针指向的ngx_http_upstream_create_main_conf函数创建一个结构体保存配置:
接着会调用ctx的另一个函数指针指向的函数ngx_http_upstream_add_variables添加变量。
接着会解析NGX_HTTP_MAIN_CONF级别的配置,upstream模块只有upstream指令是该级别的。读取配置内容,直到处理到upstream name { … } ,会调用ngx_http_upstream函数处理。
开始解析NGX_HTTP_UPS_CONF级别的server指令,对应的函数ngx_http_upstream_server。