通常,像 Amazon 的 Elastic Load Balancer 这样的负载均衡器使用具有多个 A 记录的 DNS 记录集来提供多个可以处理到请求端点的流量的负载均衡器实例:
$ dig +short my-fancy-elb.us-east-1.elb.amazonaws.com
10.0.1.1
10.0.1.2
如果我尝试以详细模式卷曲此 URL,我会注意到似乎curl
对两个 IP 地址进行循环尝试:
$ curl -ivs http://my-fancy-elb.us-east-1.elb.amazonaws.com | grep -i 'connected'
* Connected to my-fancy-elb.us-east-1.elb.amazonaws.com (10.0.1.1)
$ curl -ivs http://my-fancy-elb.us-east-1.elb.amazonaws.com | grep -i 'connected'
* Connected to my-fancy-elb.us-east-1.elb.amazonaws.com (10.0.1.2)
curl
对记录集中描述的 A 记录进行循环执行是由二进制文件本身完成的,curl
还是由 Linux 内核为其执行的?
TCP 存在于第 4 层,DNS 存在于第 7 层,因此我认为各个二进制文件和库必须实现自己的负载平衡和故障转移:获取给定域名的 DNS 记录集并从该集合中选择一个要连接的 TCP 地址。
我是否可以合理地期望编程语言、浏览器和像 curl 这样的库会为我执行 A 记录上的负载平衡和故障转移?
答案1
简短的回答是,情况有所不同。
当答案集中存在多个地址记录时,查询的 DNS 服务器通常会以随机顺序返回它们。操作系统通常会按照收到的顺序将返回的记录集呈现给应用程序。也就是说,事务的双方(名称服务器和操作系统)都有选项,这可能会导致不同的行为。通常不会使用这些选项。例如,一个鲜为人知的文件/etc/gai.conf
控制基于 glibc 的系统上的这一点。
Zytrax 书籍(火箭科学家的 DNS)有关于这个话题的历史的一个很好的总结,并得出结论RFC 6724是应用程序和解析器实现应该遵守的当前标准。
从这里值得注意的是选择报价来自 RFC 6724:
Well-behaved applications SHOULD NOT simply use the first address
returned from an API such as getaddrinfo() and then give up if it
fails. For many applications, it is appropriate to iterate through
the list of addresses returned from getaddrinfo() until a working
address is found. For other applications, it might be appropriate to
try multiple addresses in parallel (e.g., with some small delay in
between) and use the first one to succeed.
标准鼓励应用程序在发生故障时不会停止在第一个地址,但这既不是要求,也不是许多随意编写的应用程序将要实现的行为。除非您确定大部分(或至少最重要的)消费应用程序将正常运行,否则您永远不应该仅仅依靠多个地址记录来实现高可用性。现代浏览器在这方面往往做得很好,但请记住,它们并不是您处理的唯一消费者。
(此外,正如@kasperd 在下面指出的那样,区分这在 HA 和负载平衡方面带来的好处非常重要)
答案2
我猜测发生的情况是,记录的 DNS TTL 设置得非常低,curl
每次都需要再次解析并从 DNS 服务器获取另一个 IP。
无论curl
是内核还是 DNS 层都没有意识到这种负载平衡的发生,而且你也无法合理地期待这样的事情发生。
答案3
基本情况是 DNS 服务器通常以伪随机方式循环记录。
fedor@piecka:~$ dig +short @ns1.yahoo.com yahoo.com
206.190.36.45
98.138.253.109
98.139.183.24
fedor@piecka:~$ dig +short @ns1.yahoo.com yahoo.com
98.139.183.24
206.190.36.45
98.138.253.109
fedor@piecka:~$ dig +short @ns1.yahoo.com yahoo.com
98.139.183.24
98.138.253.109
206.190.36.45
就 curl 而言,它有自己的 DNS 解析库,该库尊重服务器呈现的顺序。
关于这个话题有一个故事https://daniel.haxx.se/blog/2012/01/03/getaddrinfo-with-round-robin-dns-and-happy-eyeballs/。其中也提到了 curl 的实现。
答案4
curl 对记录集中描述的 A 记录进行循环处理是由 curl 二进制文件本身完成的,还是 Linux 内核为其执行的操作?
都不是。通常是 DNS 服务器更改 IP 地址。curl 库需要解析主机名以获取每个请求的 IP 地址。它将请求发送到 DNS 服务器,DNS 服务器会返回 IP 地址列表。DNS 服务器也可以位于同一台机器上进行本地缓存。大多数 DNS 服务器在每个请求中轮流轮换 IP 列表。因此,由于列表的顶部 IP 已更改,因此您在每个请求中都会获得不同的 IP。如果您从 Linux 机器 ping www.google.com,则每次都可能会看到不同的地址。
客户端是否通常对多个 A 记录实现故障转移/负载平衡?
我使用 curl 执行了通过 http 获取文件的测试。当第一个 IP 无法访问时(故障转移),Curl 能够使用另一个 IP 重试。因此,“故障转移”适用于 curl 的 http 请求。