Nginx在upstream中配置域名的动态解析问题

      访问: 4,484 次      2 条评论    

Nginx proxy timed out with dynamic upstreams

当使用Nginx 转发请求到AWS ELB(即把ELB的域名作为proxy_pass的upstream)时,由于ELB域名的IP经常变化,会出现Nginx转发请求失败(连接upstream超时)的情况。Nginx 配置样例如下:

location / {
    proxy_pass http://service-1234567890.us-east-1.elb.amazonaws.com;
}

原因在于Nginx解析域名的时机:

Nginx仅在启动的时候,对配置文件中的upstream域名进行解析,并将得到A记录IP地址全部作为upstream,直到下一次加载配置文件时,才会更新域名解析结果。而AWS ELB域名的IP是经常变化的,所以很容易出现转发错误的情况。

解决方案:

1、使用 Nginx Plus(付费方案)

其中一个解决方案是付费购买Nginx Plus版本,然后在配置文件 upstream 组配置中,在 server 指令后添加 resolve 标记。

Example:

upstream backend {
    server service-1234567890.us-east-1.elb.amazonaws.com  resolve;
}

这样Nginx 就会遵循域名的TTL过期机制,当TTL过期时重新进行域名解析,获得server (AWS ELB)域名更新后IP地址。

2、将upstream server配置为变量(取巧免费方案)

另一个免费的方案是按照如下方法进行配置:

resolver 172.16.0.23;
set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com;
location / {
    proxy_pass $upstream_endpoint;
}

即为Nginx 配置一个域名解析器 resolver ,并将 upstream server 配置为一个变量。

这样Nginx 也会遵循域名的TTL过期机制,并在收到请求一个过期的upstream server域名时重新进行域名解析。

这个方法奏效的原因可以在Nginx 官方文档中对 proxy_pass 指令的描述末尾中可以找到:

A server name, its port and the passed URI can also be specified using variables:

proxy_pass http://$host$uri;

or even like this:

proxy_pass $request;

In this case, the server name is searched among the described server groups, and, if not found, is determined using a resolver.


关于 proxy_pass 的 forwarded URI:

如果 location 不是 / ,proxy_pass 后的URI不同的写法会有不同的结果。

1、通常情况(upstream 未使用变量)

1)假设我们有如下配置:

location /foo/ {
    proxy_pass http://127.0.0.1:8080;
}

当我们请求 /foo/bar/baz 时,Nginx 会转发请求到 http://127.0.0.1:8080/foo/bar/baz 。

2)但如果我们这样配置:

location /foo/ {
    # Note the trailing slash       ↓
    proxy_pass http://127.0.0.1:8080/;
}

Nginx 会去除在 loation 中指定的路径,再将URI余下的部分转发。则请求 /foo/bar/baz 时,会被转发到 http://127.0.0.1:8080/bar/baz 。

2、upstream 使用变量的情况

1)假设我们按刚才的解决方案如下进行配置

resolver 172.16.0.23;
set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com/;
location /foo/ {
    proxy_pass $upstream_endpoint;
}

当我们请求 /foo/bar/baz 时,Nginx 会转发请求到 / ,而不是 /bar/baz 。

如果想实现通常情况下Nginx 的转发行为,可以在上述配置中去掉upstream末尾的 / ,手工写rewrite 实现:

resolver 172.16.0.23;
set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com;
location /foo/ {
    rewrite ^/foo/(.*) /$1 break;
    proxy_pass $upstream_endpoint;
}

这样,当我们请求 /foo/bar/baz 时,后端 upstream 会收到 /bar/baz 的请求。


参考:Nginx with dynamic upstreams

已有 2 条评论

  1. 没有验证码,会不会出现很多垃圾??

    1. 可能吧。。验证码还没搞定,哈哈

添加新评论