与apc_exists和apc_add陷入僵局?(APC & PHP)


Deadlock with apc_exists & apc_add? (apc & PHP)

我想知道是否有人发现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_addapc_store对死锁没有影响,它们对两个函数都有影响。

使用 apc_fetch 的存在检查可能如下所示:

public function has($key) {
    apc_fetch($key, $exists);
    return $exists;
}