需求
proxy_bind隶属于proxy_module,为向后端建立连接时的local ip。
我们以最新版nginx1.19.5为例,查看proxy_bind源码,发现proxy_bind配置指令只能接受1个或者2个参数。如下:
{ ngx_string("proxy_bind"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
ngx_http_upstream_bind_set_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
NULL },
{ ngx_string("proxy_socket_keepalive"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive),
NULL },
如果我们想使用proxy_bind配置多个ip支持ip数组怎么办呢???
这就需要我们修改nginx源码了。
修改源码
首先修改配置指令改成NGX_CONF_1MORE,然后修改ngx_http_upstream_bind_set_slot_array
ngx_string("proxy_bind"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_upstream_bind_set_slot_array, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.local_array), NULL }, char *ngx_http_upstream_bind_set_slot_array(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ... ngx_http_upstream_local_array_t **plocal, *local; plocal = (ngx_http_upstream_local_array_t **) (p + cmd->offset); if (*plocal != NGX_CONF_UNSET_PTR) { return "bind is duplicate"; } value = cf->args->elts; // 建立local array local = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_local_array_t)); *plocal = local; // 建立local peer addr local->addr = ngx_pcalloc(cf->pool, sizeof(ngx_peer_addrs_t)); // 建立addr array local->addr->addrs = ngx_array_create(cf->pool, 1, sizeof(ngx_addr_t)); // 遍历所有的local ip,放进array中 ...... default: return NGX_CONF_ERROR; } } ... } |
在init_request中,将u→peer.local_array 赋值为u→conf→local_array
static void ngx_http_upstream_init_request(ngx_http_request_t *r) { ... u = r->upstream; u->peer.local_array = ngx_http_upstream_get_local_array(r, u->conf->local_array); ... } |
u→conf是通过不同的handler获得的,在nginx配置中常用的proxy_pass。
可以将这个赋值上去。
static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { ... u = r->upstream; // 获取proxy的loc conf plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); // 获取对应的conf u->conf = &plcf->upstream; ... } |
plcf->upstream→upstream是真正的upstream_srv_conf。
是在proxy_pass中获取的。
static char * ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ...
plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); ... } |
END
最后抓包分析是否符合预期。