我们知道memcache的PHP客户端在连接mc后,如果中间memcached宕掉了,你们重启之后,mc-client会自动连接到server的,这是如何做到的呢?
先写一个test脚本:
<?php
$mc = new Memcache();
$mc->connect("10.10.10.10",11211);
while(1){
$ret = $mc->set("a","a");
if($ret) {
echo "okn";
} else {
echo "failn";
}
sleep(1);
}
?>
启动脚本后,先宕掉memcached,再启动memcached:
间隔时间
第一次失败的时间: 1240491343.709920
第一次重连: 1240491358.751046 15s
第二次重连: 1240491373.790693 15s
第三次重连: 1240491388.829329 15s
第四次重连: 1240491403.869810 15s
结论: mc client 失败后,如果没有主动重连,在15s后再使用该连接,将尝试重连,在15s内根本就不做尝试重连的动作,即使服务器15s内
又恢复正常服务,mc client也是不知道的
——————————————-
关于pconnect的研究:
先写一个test脚本:
<?php
$mc = new Memcache();
while(1){
$mc->pconnect("10.55.38.18",11211);
$ret = $mc->set("a","a");
if($ret) {
echo "okn";
} else {
echo "failn";
}
sleep(1);
}
?>
1. 虽然pconnect是针对apache类程序开发的,但是命令行程序里有相同的效果
2. 虽然$mc->pconnect("10.55.38.18",11211);是写在了循环里面,但是通过tcpdump发现,并没有每次都重连mc
3. 虽然好像每次都重连,其实都还是完全有connect里的机制来控制了,就是说循环里面的pconnect与写到循环外面没有任何的区别
4. 如果把里面的pconnect 换成connect,则效果就和我们想象的一样了,这样,不管服务器端是否有异常,每次都是真正的连接
程序在$mc->pconnect("10.55.38.18",11211);时报的两种错误:
第一种:Warning: Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Unknown error (0) in /usr/home/junjie2/testmc.php on line 4
第二种:PHP Warning: Memcache::pconnect(): Can’t connect to 10.55.38.18:11211, Connection refused (111) in /usr/home/junjie2/testmc.php on line 4
前者是因为并没有真正去连接,只是发现连接不可用(已关闭)就直接返回错误了
后者是第一次失败的15s之后,就尝试做一次真正的重新连接,因为这是memcached还没有重启,就返回了 Connection refused,这样下次pconnect,又接着返回第一种错误,直到又过15s
php的memcahce-2.2.4 中文件 php_memcache.h 中有如下定义
#define MMC_DEFAULT_RETRY 15 /* retry failed server after x seconds */
即: 15s内是不做真正的连接的。
注意: memcache客户端默认设置的超时时间为1s, 极容易超时的,所以你要知道,当超时后,客户端会主动关闭连接的,因为它以为服务器down了,然后就是15s内的操作统统返回失败。
如何避免这种问题呢?
办法一: 在第一个测试脚本中,使用了connect,而不是pconnect, 连接操作是在循环体外的;如果connect(注意不是pconnect)发生在循环体内就能及时发现连接已有效了,就不需要等待15s了,当然,这样的话,每次都是真实的重新连接了,而且特别需要注意的是,如果这样的话,close()操作也一定要写在循环体里面,否则你将创建n多连接,知道不允许你在连接了。
办法二: 使用addServer的方式: bool Memcache::addServer ( string $host [, int $port = 11211 [, bool $persistent [, int $weight [, int $timeout [, int $retry_interval [, bool $status [, callback $failure_callback [, int $timeoutms ]]]]]]]] )
将$retry_interva 设置为0,这样就每次都重新连接了。