如何清除APC缓存条目?

172

当我部署网站的新版本时,我需要清除所有APC缓存条目。 APC.php 有一个按钮可以清除所有opcode缓存,但我没有看到清除所有用户条目、所有系统条目或所有目录条目的按钮。

是否可以通过命令行或其他方式清除所有缓存条目?


1
我对如何清除过期条目很感兴趣!您可以指定一个TTL,但是php.net文档说当它过期时,它会在下一次请求时被清除... - The Surrican
19个回答

146
你可以使用PHP函数apc_clear_cache
调用apc_clear_cache()将清除系统缓存,而调用apc_clear_cache('user')将清除用户缓存。

20
我发现要通过命令行完成这个操作,你需要进入apc.ini文件并设置:apc.enable_cli=1。 - lo_fye
51
lo_fye: 这真的有效吗?根据我的经验,我发现APC CLI与Apache的APC缓存完全是分开的,而且这是正确的,因为任何CLI进程都在与Apache完全分离的进程中运行。 - Frank Farmer
9
Frank Farmer:我确认此方法适用于运行PHP 5.3.10并使用PHP-FPM接口的Apache或Nginx。我创建了一个Shell脚本来执行此命令 php -r "apc_clear_cache();". - ezraspectre
13
如果使用 mod_php 运行 PHP,这将无法工作。原因如 Frank Farmer 所述。 - David
11
我使用Ubuntu Server 12.04,搭配Nginx和PHP-FPM,PHP版本为5.4。在命令行上运行apc_clear_cache()和apc_clear_cache('user')并不能清除Web服务器/网页的APC缓存! - Pieter Vogelaar
我使用的解决方案是让CLI PHP脚本向本地主机发出HTTP请求,请求运行一个PHP脚本,该脚本只运行apc_clear_cache(有关实现,请参见下面Jeremy的答案)。 - Fredrick Brennan

118

我不认为这些答案中的任何一个真正适用于从命令行清除APC缓存。正如Frank Farmer在上面评论的那样,CLI运行在与Apache分离的进程中。

我从命令行清除缓存的解决方案是编写一个脚本,将一个APC清除脚本复制到web目录中并访问它,然后删除它。该脚本只能从localhost访问。

  1. apc_clear.php

    这是脚本复制到Web目录中、访问和删除的文件。

<?php
if (in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')))
{
  apc_clear_cache();
  apc_clear_cache('user');
  apc_clear_cache('opcode');
  echo json_encode(array('success' => true));
}
else
{
  die('SUPER TOP SECRET');
}
  • 清除缓存脚本

    该脚本将apc_clear.php复制到Web目录,访问它,然后删除它。这是基于Symfony任务的。在Symfony版本中,调用Symfony形式的复制和解除链接,来处理错误。你可能需要添加检查它们是否成功。

  • copy($apcPaths['data'], $apcPaths['web']); //'data' is a non web accessable directory
    
    $url = 'http://localhost/apc_clear.php'; //use domain name as necessary
    $result = json_decode(file_get_contents($url));
    
    if (isset($result['success']) && $result['success'])
    {
      //handle success
    }
    else
    {
      //handle failure
    }
    
    unlink($apcPaths['web']);
    

    8
    如果你正在使用mod_php,你可以重启服务器,比如Apache;如果你正在使用PHP FPM,也可以重启服务器。你的解决方案更加优雅(不需要重启服务器),但也更加复杂 :) - El Yobo
    5
    这比重启php-fpm/apache更好,因为它不需要您的部署用户具有sudo权限。如果您要部署到多个服务器,则为每个服务器输入sudo密码可能会让人感到疲倦。 - andrew
    个人而言,我不介意输入sudo密码(我的部署脚本会保存密码)。但是我想尽可能避免停机时间,这就是为什么我对清除APC文件感兴趣。对于Nginx,有一种(不太容易的)方法可以在没有任何停机时间的情况下重新启动。我不知道PGPfcgi是否也有这样的方法,但我认为不会。清除APC会导致停机吗? - Julien
    1
    @Julien 我猜如果你正在存储 CPU 密集型结果之类的东西,它可能会增加服务器负载。我不会在高峰时段这样做。 - ChocoDeveloper
    @ChocoDeveloper,问题在于如果你的PHP脚本存在漏洞,攻击者可以使用sudo将后门放入你的系统,并通过更改日志文件等方式潜藏踪迹。如果用户没有无密码sudo,则攻击者仍需要root密码或用户密码,因此机器更加安全。(诚然,这假设您使用相同的用户运行PHP脚本部署它们,但这不一定是情况) - rjmunro
    显示剩余3条评论

    69

    我知道这不适用于每个人,但:为什么不进行优雅的Apache重新启动呢?

    例如,在CentOS/RedHat Linux的情况下:

    sudo service httpd graceful
    

    Ubuntu:

    sudo service apache2 graceful
    

    4
    我知道这并不是最理想的,但我很高兴你提到了这个快速而简单的解决方案。 - Bryan Petty
    1
    抱歉重新打开这个帖子,但我面临同样的问题,想知道为什么cronjob不能使apache2重新启动优雅?这种方法有哪些缺点? - user2028856
    @user2028856,除了有些人可能无法完全控制服务器之外,它没有任何问题。因此,如果它对您有效,请使用它。 - Tadas Sasnauskas
    @TadasSasnauskas,“not always have full control of the server.”的意思是什么?我的意思是,每隔半个小时运行它会导致Apache崩溃或破坏其他正在运行的操作,比如cron备份吗? - user2028856
    在你有多个存储的情况下,例如CLI和Web服务器,这是唯一的解决方案。 - dabito
    显示剩余2条评论

    27

    虽然文档中没有说明,但要清除操作码缓存,您必须执行以下操作:

    apc_clear_cache('opcode');
    

    编辑:这似乎只适用于一些旧版本的APC..

    无论你使用的是哪个版本,你都无法从一个PHP CLI脚本中清除mod_php或fastcgi APC缓存,因为CLI脚本将从与mod_php或fastcgi不同的进程中运行。您必须从要清除缓存的进程(或子进程)中调用apc_clear_cache()。使用curl运行简单的PHP脚本就是其中一种方法。


    1
    我应该补充一点,如果你正在运行mod_php并想通过cli-mode php清除缓存,你实际上无法这样做,因为两者在不同的环境中运行。我的解决方案是让cli模式php使用file_get_contents通过http调用自身。虽然不太美观,但它能正常工作。 - ColinM
    将有效的FastCGI请求转储直接通过netcat传输到php-fpm,无需安装真正的HTTP服务器即可实现Pipe操作,因为php-fpm服务器可能与HTTP服务器分离。 - baloo
    这个答案是错误的。正如文档中所解释的那样,如果给定的参数不等于'user',则操作码缓存将始终被清除。 - stollr
    @naitsirch 或许这是最新版本已经修复的一个bug。在我回答时,这个方法对我有效。不幸的是,我不知道当时我使用的是哪个版本,但是显然这个答案对其他25个人也有用,他们可能使用的是和我相同的版本。文档并不总是正确的,特别是对于旧版本来说更是如此。 - ColinM

    12
    如果您正在使用NGINX / PHP-FPM堆栈,则最好的选择可能是重新加载php-fpm。 service php-fpm reload(或在您的系统上,可能是任何重新加载命令)

    重新加载服务php5-fpm是让它工作的原因。我检查了apc.php状态文件并重置了缓存状态,这是在将apc.stat=0选项添加到php.ini后所需的。 - Salem

    12
    如果您想在命令行中清除 APC 缓存:(如果需要,请使用 sudo)
    APCu
    php -r "apcu_clear_cache();" 
    

    美国电源公司

    php -r "apc_clear_cache(); apc_clear_cache('user'); apc_clear_cache('opcode');"
    

    我在终端上遇到了错误,请帮忙解决:“PHP致命错误:在第1行的命令行代码中调用未定义的函数apc_clear_cache()”。 - RaviPatidar
    1
    你应该使用命令“php -m | grep apc”测试你的APC是否已正确安装。 - Léo Benoist

    5

    apc_clear_cache()仅适用于您想要清除缓存的相同php SAPI。如果您使用PHP-FPM并希望清除apc缓存,则必须通过其中一个php脚本而不是命令行来执行此操作,因为这两个缓存是分开的。

    我编写了CacheTool,这是一个命令行工具,可以解决这个问题,只需一条命令即可从命令行清除您的PHP-FPM APC缓存(它会为您连接到php-fpm并执行apc函数)

    它也适用于opcache。

    请查看此处的工作原理:http://gordalina.github.io/cachetool/


    4
    如果您想通过json监控结果,可以使用以下脚本:
    <?php
    
    $result1 = apc_clear_cache();
    $result2 = apc_clear_cache('user');
    $result3 = apc_clear_cache('opcode');
    $infos = apc_cache_info();
    $infos['apc_clear_cache'] = $result1;
    $infos["apc_clear_cache('user')"] = $result2;
    $infos["apc_clear_cache('opcode')"] = $result3;
    $infos["success"] = $result1 && $result2 && $result3;
    header('Content-type: application/json');
    echo json_encode($infos);
    

    如其他答案中所提到的,这个脚本必须通过http或curl调用,在Web应用程序的根目录下暴露之前必须进行安全设置(例如通过IP、令牌等方式)。

    4

    还有一种命令行使用的可能性,尚未提到,那就是使用curl。

    如果您正在使用默认的apc.php脚本,则这并不能解决所有缓存条目的问题,但它可以调用修改后的脚本或您放置的另一个脚本。

    这将清除opcode缓存:

    curl --user apc:$PASSWORD "http://www.example.com/apc.php?CC=1&OB=1&`date +%s`"
    

    将OB参数更改为3以清除用户缓存。
    curl --user apc:$PASSWORD "http://www.example.com/apc.php?CC=1&OB=3&`date +%s`"
    

    把这两行代码放在脚本中,并使用环境变量 $PASSWORD 调用它。

    4
    作为APC文件所定义的内容:
    清除缓存的方法如下:
    php -r 'function_exists("apc_clear_cache") ? apc_clear_cache() : null;'
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接