设置详情:
我有在 ubuntu 10.04 下运行的 Apache 2.2.14。虚拟主机的文档根目录设置为符号链接。
请求的脚本乍一看是这样的:
<?php
// other useful stuff here
echo 'v1.2.42';
因此,除了执行有用的工作外,脚本还会在页脚中输出其版本。版本在脚本中是硬编码的,并由构建脚本修改。
部署新版本时,文档根目录将使用非常标准的方法切换到新版本:
ln -s /path/to/app-1.2.43 app-new
mv -Tf app-new app # where `app` is the document root
此后,我不再为 apache 做任何reload
事情restart
。
今天,在另一次发布之后,我经历了以下事情:
- 我将
1.2.42
版本升级到1.2.43
- 在浏览器中打开应用程序
- 它
42
在底部 F5
- 仍然42
。- 然后
42
和43
随机出现。大约 30 秒后,预期43
开始持续显示。
另一台具有类似配置的服务器的行为完全相同。并且似乎存在一些持续的超时,直到它开始正常工作 :-S
更多配置细节:
apache 配置为通过 mpm-prefork 运行。php 的版本是 5.3.2,安装为mod_php
。有不已安装任何操作码缓存。
有没有什么办法可以将其缓存在何处?apache2 reload
保证这不会发生吗?
附言:我已经证明(向我自己)这apache reload
不会重置该状态并且未定义的行为会继续。
更新:
我发现每个 apache 工作者都会将指向文档根目录的符号链接扩展为真实路径。
当你执行优雅reload
命令时 - 只会重新启动空闲的工作进程,而繁忙的工作进程(包括正在为 Keep-Alive 连接提供服务的工作进程)则会一直保留,直到它们空闲下来。我可以使用 1 个工作进程来重现它,它完美地解释了我的观察结果。
现在的问题是:如何优雅地中断保持活动连接?
关于这个主题,值得一读的有趣文章:https://blogs.oracle.com/oswald/entry/apache_s_graceful_restart_reprise
答案1
看起来 apache 进程确实缓存了符号链接的结果。即使 apache 重新加载也可能无法解决您的问题,因为重新加载只是重新读取配置文件并重新应用新设置。它实际上并没有终止正在运行的进程。
我认为处理这种情况的最佳方法是apache2 restart
。这可能比您想象的更安全,因为它将阻止新连接,并允许旧连接在重新启动之前干净地完成。在中等 Web 服务器上,这应该在一秒钟内发生。而且由于 HTTP 是无状态的,您的用户甚至不会注意到。除了如果他们在重新启动期间尝试启动新连接,可能会有半秒钟的挂起。
另一种可能性是实际更改配置中的文档根目录和符号链接的名称,然后执行apache2 reload
。然后它应该会检测到新的文档根目录并强制重新解析符号链接的引用目录。
我能想到的最后一件事是尝试使用硬链接。但这将需要不同的工作流程,以防止覆盖新应用程序版本。
答案2
当设置时,Apache 会lstat
在路径组件中缓存符号链接(系统调用) (根据设计)。Options FollowSymlinks
为了避免缓存,您可以尝试Option SymLinksIfOwnerMatch
保证不缓存lstat
调用。
然而,这需要正确配置,并且需要测量性能影响。参见这里
答案3
好吧,我找到了一个适合我的解决方案。这是一个很小的脚本,可以执行以下操作:
KeepAlive
在 apache 配置中关闭- 获取当前 worker 的 PID
- 跑步
apache reload
- 等待 #2 的所有工人退出
- 切换符号链接
- 重启
KeepAlive
并重新加载 Apache