Nginx resolver 命令定义在ngx_http_core_module,可以在http{},server{},location{}中配置。作用是解析proxy_pass 中配置的域名。
使用示例:
http {
upstream test {
server 1.1.1.1 ;
server 2.2.2.2 ;
}
server {
listen 80;
server_name www.test.com;
resolver 8.8.8.8 114.114.114.114 valid=40s ipv6=off;
location / {
proxy_pass http://www.baidu.com;
/* 或者
set $upstream_name "www.baidu.com";
proxy_pass http://$upstream_name;
*/
//proxy_pass http://test;
}
}
}
proxy_pass
可以用字面值IP、域名、upstream名、变量等方式设置回源地址。处理分支如下:
1. 如果有变量,则预编译变量(proxy_lengths),直接返回,等到请求来了再处理(proxy_handler)
2. 如果没有变量,则直接把协议前缀http(s)://后面的当作URL,调用ngx_http_upstream_add添加到umcf->upstreams数组中,plcf->upstream.upstream指向这个upstream。
2.1 首先会解析URL(ngx_parse_url),把host(IP或域名),端口等都分割出来
2.2 如果字面值是IP,那么直接创建uscf->servers,从servers数组push一个server(us),us->addrs 就等于配置的IP。
2.3 其余都当作URL(域名或upstream名),解析URL并设置uscf的各字段值,比如host、port,no_port等字段。
2.3 调用ngx_http_proxy_set_vars设置plcf->vars。
proxy_handler
对请求进行处理,创建u = r->upstream,
1. 如果没有变量(proxy_lengths为空),则设置回源协议就好(u->schema=plcf->vars.schema)
2. 如果有变量,则调用ngx_http_proxy_eval
2.1 计算出值(URL),然后设置好schema
2.2 解析URL,为u->resolved分配空间。如果有IP,那么设置u->resolved->sockaddr;如果不是IP就设置好要解析的host(u->resolved->host)和回源端口(u->resolved->port)
3. 设置u->conf = &plcf->upstream,然后调用ngx_http_upstream_init->ngx_http_upstream_init_request
ngx_http_upstream_init_request
对u->resolved进行判断,根据负载均衡算法选择IP,进入建连,回源流程
1. 如果为空,则直接uscf = u->conf->upstream,找到对应的upstream,进行upstream_connect
2. 如果不为空
2.1 则遍历umcf->upstreams数组进行匹配,则调用perr.init(负载均衡算法的init_peer函数),然后upstream_connect
2.2 如果u->resolved->sockaddr 不为空,说明设置的是IP,用这个IP创建round_robin,然后upstream_connect
2.3 如果为空,则调用ngx_resolve_start,设置解析回调函数ngx_http_upstream_resolve_handler(这里面有upstream_connect),然后ngx_resolve_name进行解析。
问题:
1. 对于proxy_pass http://www.baidu.com; 域名是怎么解析的?
在ngx_http_upstream_init_round_robin函数中,会调用ngx_inet_resolve_host,这个函数中调用getaddrinfo,用/etc/resolv.conf中的dns 作为dns server进行查询了!
注意,对于不带变量,直接配置域名的情况,resolver是不生效的。
2. 那resolver对于哪种配置方法有用?
只有proxy_pass 中设置了变量,而且值是域名,resolver才生效。例如:
set $domain_name "www.baidu.com";
proxy_pass http://$domain_name;
3. resolver解析出的IP是怎么处理的?
ngx_http_upstream_init_request中,在ngx_resolve_name执行之前,设置了ctx->handler = ngx_http_upstream_resolve_handler,在解析出A记录后,会执行ctx->handler
4. resolver 解析出的IP怎么负载均衡的?
ngx_http_upstream_create_round_robin_peer,顾名思义,用的是轮询算法。这个是基础算法,每一种负载均衡算法都会调用这个函数。