【问题标题】:Capistrano Symlinks Being Cached?Capistrano 符号链接被缓存?
【发布时间】:2013-08-29 07:03:15
【问题描述】:

我一直在 CentOS 6 上使用 Capistrano 设置 PHP 部署,并遇到了一个有趣的问题。 capistrano 的工作方式是这样设置文件夹:

  • /var/www/myapp.com/
    • 当前(/releases 中最新版本的符号链接)
    • 共享
    • 发布
      • 20130826172737
      • 20130826172114

当我查看“当前”符号链接时,它指向的是最新版本。起初,打开我的网络应用程序时,一切正常。部署新版本后,current 文件夹正确指向新版本,但 Web 应用程序尝试从旧版本(已在 Capistrano 清理过程中删除)加载文件。此外,虚拟主机配置为指向 /var/www/myapp.com/current/Public

符号链接是否以任何方式缓存?

失败的特定 PHP 代码(初始化我的框架)是这样的:

require_once dirname(dirname(__FILE__)) . '/App/App.php';
App\App::run();

位于 index.php 中,当前位于 /var/www/app.com/current/Public/index.php

我的 Apache 错误日志显示:

PHP 致命错误:require_once(): 无法打开所需的 '/var/www/myapp.com/releases/20130826172237/App/App.php' (include_path='.:/usr/share/pear:/usr/共享/php')在/var/www/myapp.com/releases/20130826172237/Public/index.php

当前符号链接显示:

当前 -> /var/www/zverse/releases/20130826172641

显然 20130826172641 != 20130826172237 后者是以前的版本。

任何想法或领域我可以看看?

【问题讨论】:

  • 似乎是个小问题。我等了大约 10 分钟,然后又试了一次,它奏效了。我想知道这是否是某种 Apache 优化?
  • 禁用 PHP 的真实路径缓存或使用mod_realdoc,此问题将消失,无需重新启动服务器。
  • 与 Centos 上的 nginx 服务器相同的问题,“当前”符号链接不会更新到最新的。

标签: php capistrano symlink


【解决方案1】:

我无法验证这一点,但似乎 Apache 跟随/缓存符号链接的旧位置存在一些不可预知的行为:

唯一可以彻底解决此问题的方法是循环 Apache,我们不希望在每次部署时都这样做。 -- 迈克·布里顿

他建议移动整个目录,而不是更新符号链接。

【讨论】:

  • 感谢您的信息。我仍然经常遇到这个问题,但我的 Capistrano 部署过程的一部分执行了service httpd restart,这似乎解决了这个问题。
  • service httpd reload/systemctl reload apache2.service 不涉及停机,效果相同。
  • 感谢@smcjones - 您想编辑答案/使其成为社区答案吗?我目前无法对此进行测试
  • 如果可以的话,我想我会把它作为评论留下。我没有针对 Fedora/RHEL 测试过这个,只针对 Debian/Ubuntu 版本,所以我可能会关闭语法。
【解决方案2】:

您是否检查了 realpath_cache_size 和 realpath_cache_ttl 指令?默认情况下,php > 5.1 会将符号链接文件的真实路径缓存 120 秒。这将导致 capistrano 部署出现问题。主要问题是缓存——即使你清除了缓存,你的旧 php 文件将继续提供两分钟,用旧数据重新填充它——以及 php 和静态文件之间的交互。静态文件由 Apache 直接提供,因此会立即更新。不过,在部署后两分钟内,php 代码仍将来自以前的版本,因此它将期待任何更改的静态文件的旧版本。如果您使用更改这些文件名称的缓存中断过程,这尤其是一个问题。在这种情况下,php 代码将根本无法找到它所期望的文件。

无论如何,有两种解决方案。首先是在 php.ini 中将 realpath_cache_size 设置为 0。 (注意:将 realpath_cache_ttl 设置为 0 不会禁用缓存。)或者,如果您想保持启用状态,您应该能够在部署后立即使用 clearstatcache 函数清除 realpath 缓存你的符号链接,使用 capistrano 钩子。但是请注意,如果您使用的是 mod_php,则 php cli 和 apache 运行时是分开的,因此您需要使用 apache 调用的 php 脚本调用该函数,类似于 clearing the APC cache here 所做的那样。不过我还没有测试过,因为我没有注意到简单地禁用缓存会对性能产生重大影响。

【讨论】:

  • 对实际路径缓存和 APC 缓存填充之间的确切交互有什么想法,清除后? apc_clear_cache() 将清除 php-fpm 池的整个(共享内存)缓存,但 clearstatcache(true) 只会清除该特定 php-fpm 进程的实际路径缓存。如果我有 4 个 php-fpm 进程在繁忙的系统上运行,其他 3 个仍然可以再次从旧数据中填充?
  • @jrg 我不确定你在问什么。 APC 缓存和真实路径缓存是两个独立的问题。如果您将 APC 用于您的类图或类似的东西,当您重新部署代码的新版本时,这将失效,您需要在部署时清除它。 realpath 缓存是独立的,指的是 php 缓存符号链接,因此在您重新部署后它将使用文件的旧位置,除非您运行 clearstatcache。如果确实只清除了那个 php 进程的 realpath 缓存(正如我所说,我还没有测试过),那么你需要一种方法来清除它。
  • @jrg 不确定如何在不重新启动 Web 服务器的情况下完成此操作。 (我个人发现,仅仅禁用 realpath 缓存并不会以任何明显的方式影响性能。同样,这与 APC 缓存不同。)另外需要注意的是,如果您使用 APC 或其他缓存来缓存您的类映射或任何 php 目录,您需要在清除 realpath 缓存后立即清除它;否则它将从旧值重新填充。
  • 对...在 Capifony 部署后(“部署后”),我们一直在努力清除我的 APC 操作码和用户缓存,但有时仍然会出现问题。例如新的 Assetic 资产文件,但在交付的 HTML 中引用旧的。然后我找到了你关于 realpath 缓存的笔记。我将进行更多实验,将其设置为 0 大小,因为我认为如果不对 php-fpm 进行一些修改,就无法在多个 php-fpm 进程中可靠地清除它。
  • APC 和 OpCache 已禁用,realpath_cache_* 变量设置为 0,但路径仍在混合...找不到解决方案。顺便说一句,我们使用的是 nginx 而不是 apache,但问题仍然存在。
猜你喜欢
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多