PHP不尊重DNS中的循环法

时间:2013-06-20 09:20:10

标签: php dns round-robin

我在让PHP遵守启用RoundRobin的DNS条目时遇到问题。条目(例如,它的domain.example.com)分配了三个可能的IP地址。 RoundRobin工作(使用ping,telnet,wget等测试)。 不幸的是,当使用PHP SOAP扩展,甚至是普通的file_get_contents时,它总是连接到DNS中指定的第一个IP地址。令人惊讶的是,gethostbyname函数完全可以看到RoundRobin。我在每台服务器上输出一个或两个或三个文件,并在另一台服务器上执行该脚本几次:

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等在放置测试脚本的同一服务器上正常工作。

1 个答案:

答案 0 :(得分:1)

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

来自php source code

的片段
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))< CommonPrefixLen(DB,Source(DB)),   然后更喜欢DB。

假设我们有源地址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

原始DNS查询中首先出现的DADB将被选为glibc实施中的最终目的地。