【问题标题】:PHP not respecting RoundRobin in DNSPHP不尊重DNS中的RoundRobin
【发布时间】:2013-06-20 09:20:09
【问题描述】:

我无法让 PHP 尊重启用 RoundRobin 的 DNS 条目。该条目(例如它的 domain.example.com)分配了三个可能的 IP 地址。 RoundRobin 工作(用 ping、telnet、wget 等测试)。 不幸的是,当使用 PHP SOAP 扩展,甚至是普通的 file_get_contents 时,它总是连接到 DNS 中指定的第一个 IP 地址。令人惊讶的是,gethostbyname 函数认为 RoundRobin 非常好。我已经在每台服务器中放置了一个输出 1 或 2 或 3 的文件,并在另一台服务器上执行了几次脚本:

var_dump(file_get_contents('http://domain.example.com/test.html'));
var_dump(gethostbyname('domain.example.com'));

第一行总是打印“1”(从第一个 IP 地址开始)。第二行随机输出三个可能的 IP 地址之一。

问题:有没有人有类似的问题?如何强制 PHP 在 DNS 中尊重 RoundRobin,至少在发出 SOAP 请求时?

编辑 没有 DNS 缓存,也没有代理。如前所述,ping、telnet、wget 等在放置测试脚本的同一台服务器上工作正常。

【问题讨论】:

  • 中间有没有网络代理?
  • DNS 查找被缓存。您必须清空系统的 DNS 缓存。

标签: php dns round-robin


【解决方案1】:

我们最近遇到了与您类似的问题。我们发现file_get_contents()最终调用了getaddrinfo(),它实现了RFC3484的一些排序算法。

来自php source code的sn-p片段

PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string)
{
    // skip...

    if ((n = getaddrinfo(host, NULL, &hints, &res))) {
        if (error_string) {
            *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
            php_error_docref(NULL, E_WARNING, "%s",     ZSTR_VAL(*error_string));
        } else {
            php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
        }
    return 0;
    }

    //skip...
}

我们仍在寻找解决问题的更好方法。

编辑:

RFC3484 的第 6 节规定了目标地址选择算法,规则 9 与 IPv4 相关。

规则 9:使用最长匹配前缀。

当 DA 和 DB 属于同一个地址族时(都是 IPv6 或 两者都是 IPv4): 如果 CommonPrefixLen(DA, Source(DA)) > CommonPrefixLen(DB, Source(DB)),然后首选 DA。同样,如果 CommonPrefixLen(DA, Source(DA))

假设我们有源地址192.168.1.100/24 和四个候选目标地址192.168.1.33/24192.168.1.44/24192.168.2.55/24192.168.2.66/24

以上地址以二进制格式表示

S  192.168.1.100    11000000.10101000.00000001.01100100
-------------------------------------------------------
DA 192.168.1.33     11000000.10101000.00000001.00100001
DB 192.168.1.44     11000000.10101000.00000001.00101100
DC 192.168.2.55     11000000.10101000.00000010.00110111
DD 192.168.2.66     11000000.10101000.00000010.01000010

你可以看到

CommonPrefixLen(DA, S) == CommonPrefixLen(DB, S) == 25 >
CommonPrefixLen(DC, S) == CommonPrefixLen(DD, S) == 22

因此,DADB(在原始 DNS 查询中首先出现)将被选为 glibc 实现中的最终目的地。

【讨论】:

  • 感谢调查。你当然是对的。 debian bug tracker 对此有一些争论,当源地址和目标地址位于不同的子网中时,这种排序行为被禁用。我已经在 Debian 机器(使用 glibc 2.19)和 RoundRobin 上检查了它。不幸的是,不在 CentOS 7.1 和 glibc 2.17 上,但我可以忍受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
  • 2011-03-28
  • 1970-01-01
  • 2011-11-21
  • 2011-09-25
  • 2014-09-30
相关资源
最近更新 更多