我想知道是否有人发现apc_exists()
有任何奇怪的行为,当与apc_add()
或apc_store()
一起使用时,导致整个WAMP服务器挂起?经过长时间的"调试"并最小化问题后,我最终得到了以下代码,导致我的 WAMP 崩溃。
据我所知,访问不同的密钥需要 1 apc_exists()
和 2 apc_add()
。[因此听起来像是一个僵局问题]我在 chrome 中运行此脚本,然后粉碎 F5 键,直到我让 rand thing 发生两次。在那个时候或第一次它通常会挂起。
<?php
$result = "asdfioasdjfoasdjf";
if(apc_exists("asdf")) {
echo("#1<br/>");
apc_add("launcher", $result, 1);
} else {
echo("#2<br/>");
$result = "asdfasdfasdf";
apc_add("launcher", $result, 10);
}
if(rand(0,100) < 4) {
echo("#stored data!<br/>");
apc_add("asdf", "2130130", 1);
}
?>
我的系统/设置:
视窗 7 64 位
WAMP 2.2d 32位
PHP 版本 5.3.10
APC 版本 3.1.9 |$Revision: 325040 $
我在代码中做错了什么吗?这是否与Windows/wamp有关,或者它是否存在于其他环境和php/apc版本中?在上述情况下,如果我将apc_exists()
替换为apc_fetch()
,系统不会崩溃,有谁知道为什么?
我找到了原因。这一切都归结为SO上的这个很好的答案:
首先,重要的是要知道,如果尝试存储一个已经存在特定TTL的密钥,并且ttl尚未通过,则将创建一个新条目;密钥是否相同并不重要,内部将有两个相同键的条目。
其次,APC可能会失败(未命中(。即使没有明显的原因。为什么?APC 显然是倾向于速度而不是一致性的,这意味着当 APC 驱动程序忙于执行一些清理时,即使数据存在,它也会简单地返回 NULL,而不是等到它完成。这个的长版本在这里:http://phpadvent.org/2010/share-and-enjoy-by-gopal-vijayaraghavan
那么问题中提到的具体案例是怎么回事呢?每个请求之间的时间短于 1 秒,即密钥的指定 TTL,因此如果您尝试在此处存储密钥,可能会发生重复。"但是,它使用的是apc_add,难道不应该保证密钥只有在不存在时才存储吗?"显然不是:)这就是导致死锁随机的原因:有时apc_add会像您期望的那样工作,而其他一些它会"错过",也就是说,即使存在apc_add也无法理解还有另一个现有密钥。如果 TTL=0,这可能不是问题,因为在这种情况下,键只是被覆盖,但在问题的特定情况下,由于错误地找不到键和键具有尚未通过的 TTL,它将存储重复项。
由于现在内部有两个具有相同键的条目,因此当使用apc_exists时,它会混淆并挂起。
要点:不要在APC上存储标志,并始终准备一个备用案例,以防它"错过"。APC似乎在仅用于存储存在于其他地方的东西的副本(即文件或数据库条目(时效果最好
它没有明确提及,但死锁只发生在apc_exists
函数中。 apc_fetch
似乎没有遇到任何僵局。我发现更改apc_add
的apc_store
对死锁没有影响,它们对两个函数都有影响。
使用 apc_fetch
的存在检查可能如下所示:
public function has($key) {
apc_fetch($key, $exists);
return $exists;
}