Nginx 动态 upstreams 实现

王朝学院·作者佚名  2016-05-24
窄屏简体版  字體: 小  |  中  |  大  |  超大  

Nginx 动态 upstreams 实现 我最近在工作中做一个设置,我有一个面向用户的 Nginx 服务,它将访问转发到运行在AWS Elastic Load Balancer (如你所知. ELB)上的一个服务。这本身似乎不是一个困难的任务,你只需要找到 ELB 的主机名,将 ngin x指向它,这样不就搞定了,对吧?

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

测试没有问题,再正确设置一下防火墙/安全组配置,它就应该可以很好的工作了。几个小时之后,你可能会发现,服务不再工作了,尽管没有做任何改变。直接访问 ELB 端点是可以工作的,但访问 Nginx 却总是超时提醒。

ELB端启蒙为了弄清楚为什么服务突然中止,需要先了解一下 ELB 是如何工作的:

当你创建一个弹性负载均衡(Elastic Load Balancer),你将会得到 DNS 的返回记录,AWS 会告诉你所有在使用的访问服务。DNS 记录是一个轮询 DNS(round robin DNS)记录,它指向两个或更多的 ip 地址——这取决于你有多少可用的区域。DNS 记录被设置成 60 秒的存活时间(time to live),这意味几乎不会有记录缓存。

短 TTL 可以让 AWS 快速改变机器的运行负载,在不中断服务的情况下,不会有任何复杂的虚拟 IP 问题。这也是他们特别告诉你不要查找主机名和发送流量到其中某个 IP 地址的原因,那样的话,你的服务可能会在未来某个未定义的时间,IP 地址可能会停止为负载均衡工作。

回到 Nginx问题在于,对于 Nginx 来说,当它读取到一个配置时,它就会立刻向 DNS 请求主机名,然后使用其结果,直到下次重新加载配置。在这段时间到来之前,ELB 可能改变 IP 地址,让你的 Nginx 把请求转发到一些不为你服务的地址。

Nginx Plus解决这个问题的方式是为Nginx Plus付费,它添加 resolve 标记对在 upstream 分组上的服务器进行指示。那就是让 Nginx 骄傲的 DNS 对 TTL 的记录,偶尔按顺序重新处理记录,并取得服务器使用的更新列表。

为这个功能花费每年每服务器 $1.500,看起来花费很多。当然这是你希望得到 Nginx Plus 带来的其他功能,如果你不需要它们,这将会是一个昂贵的升级。

免费的选择一个更加实惠的选择是写这样一个配置:

resolver172.16.0.23;set$upstream_endpointhttp://service-1234567890.us-east-1.elb.amazonaws.com;location/{proxy_pass$upstream_endpoint;}

它将会生效并且 Nginx 会遵循记录 DNS 记录的 TTL,万一一个请求进来,会重新解释它而且缓存的记录会过期。为什么会这样?

答案可以在proxy_pass指令文档结尾找到,它声明了:

服务器名,端口以及传递的URI也可以使用变量被指定:

proxy_passhttp://$host$uri;

甚至像这样:

proxy_pass$request;

在这个案例中,服务器名会在所描述的server groups中被查找,如果没找到,会使用resolver来决定.

当我们给 proxy_pass 提供一个变量的时候,我们基本上是利用其改变行为,但这样确实需要我们在配置中指定一个 DNS resolver。例子里边用到的 DNS resolver应该能够在 AWS 上面跑在默认 VPC或者 EC2 中的所有服务器工作(适用)。你也可以随时查看 /etc/resolv.conf 找出哪些 AWS 为你的服务器提供并使用了哪些 DNS 服务器。

关于转发 URI 的 Caveat(警告)如果你在 Nginx 中设置的 Location 不只是 /,那么你需要注意到当给定一个变量作为参数时,proxy_pass 细微的改变行为。

先说重要的,快速概括 proxy_pass 如何在正常在操作中工作:

正常的表现行为

设想我们有一个 Nginx 配置包括这些:

location/foo/{proxy_passhttp://127.0.0.1:8080;}

当我们发送一个 /foo/bar/baz 的请求到这个站点,Nginx 会转发请求到 http://127.0.0.1:8000/foo/bar/baz。

location/foo/{#Notethetrailingslash↓proxy_passhttp://127.0.0.1:8080/;}

Nginx 会在 Location 记录里边去掉部分指定的 URI,然后把剩下的部分传给 upstream 服务器。所以请求 /foo/bar/baz 会被转发到 http://127.0.0.1:8080/bar/baz。

改变行为

当我们使用一个变量作为 proxy_pass 的参数的时候,上面带有尾部斜杠的行为会改变。例如我们有这样的配置。

resolver172.16.0.23;set$upstream_endpointhttp://service-1234567890.us-east-1.elb.amazonaws.com/;location/foo/{proxy_pass$upstream_endpoint;}

当我们向那个配置发送请求 /foo/bar/baz,转发请求将不会去到/并且不是预想中的 /bar/baz。

为此解决方案就是从 upstream 的 endpoint 去掉尾部斜杠,然后像这样手动重写:

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

然后当你发送请求 /foo/bar/baz,upstream 会接受到我们想要的请求 /bar/baz。

结束语要知道这不单单只适用于设置用 elb 做 upstream 服务器,它适用于配置所有在 nginx 做 upstream 服务器的修改 DNS 配置的情况。

希望这对你有用,如果你有任何建议或者只是想单纯联系我,用 twitter 联系吧Tenzer。

码农必须要加班?NO!

知道码农们都想摆脱加班狗、外卖脸的称号,所以我们来了!

我们做了一个能让程序员之间共享知识技能的APP,觉得可以颠覆程序员的工作方 式!

有人说我们痴心妄想,但我们不那么认为。

为了能煽烂说我们痴心妄想的人的脸,现在我们急需程序员业内的牛哔-人物来给 我们“号脉”!“诊断费”丰厚!毕竟我们不差钱儿,只是想做到最好!

圈圈字典中讲到,牛哔-人物是指群成员数高于1000人的QQ群主或关注人数高于 2000人的贴吧吧主或粉丝人数高于10000人的微博博主或成员数高于2000主题贴的版主 或单帖阅读量高于2000博客主或人脉超级广的圈内红人。

对于未能达标的未来大神们,我们只能含泪表示:蜀黍,咱们来日方长,这次暂 时不约好吗?待他日你立地成神,我必生死相依!

来?还是不来?

圈圈互动 接头暗号:1955246408 (QQ)

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航