我在让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等在放置测试脚本的同一服务器上正常工作。
答案 0 :(得分:1)
我们最近遇到了与您类似的问题。我们发现file_get_contents()
最终调用了getaddrinfo()
,它实现了RFC3484的一些排序算法。
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/24
,192.168.1.44/24
,192.168.2.55/24
,192.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查询中首先出现的DA
或DB
将被选为glibc
实施中的最终目的地。