我们有一个 Apache 服务器,几乎每天都会变得没有响应。通过检查 /server-status (mod_status),我们可以看到有 60 个子进程都处于“W”(发送回复)状态。
- 如果我们运行,
service httpd restart
一切都会恢复正常,问题也会在一天左右的时间内消失。 - 如果我们不重新启动 Apache 而是杀死每个子进程,问题仍然存在(这是我们访问 /server-status 的唯一方法,它会响应直到所有进程都进入“W”状态)。
- 对我来说,当问题开始发生时,我们的 PHP 脚本似乎从未完成,这让我认为这是一个 MySQL、Solr 或 PHP/Apache 超时问题。
- 然而...
- Solr/MySQL 立即响应。
- 有大量可用的 MySQL 连接(我们使用 AWS-RDS,允许的最大连接数大于 Apache 进程数)。
- RAM 仍然可以使用(每个进程为 10m x 60 = 600Mb RAM,还有足够的可用空间)。
- PHP 已
max_exectution_time
设置为“30”。 - Apache
TimeOut
设置为“60”。 - 我们不使用持久的 MySQL 连接。
- 我们做用于
curl_setopt($conn, CURLOPT_FORBID_REUSE, 0)
查询 Solr (我希望如果连接断开,curl 能够正确地收集垃圾)。
- 但似乎许多过程绝不完成...我让一个进程继续运行,同时终止所有其他进程,并且该进程持续了 2 个小时,仍然提供完全相同的页面(我可以在 /server-status 中看到这一点),通常需要 50 毫秒才能响应。
- 我们的代码中不使用
set_time_limit(0)
任何类似的愚蠢的东西。 - 我认为省略
set_time_limit
意味着脚本将在之后完成max_execution_time
。
我有一个理论,Apache 的ListenBacklog
设置太高了,每当我们终止进程时,就会立即启动 60 个新进程,所有进程都试图响应早已消失的客户端。这可以解释为什么我们重新启动服务器后问题就消失了。但似乎ListenBacklog
没有设置,因此将使用默认值“511”。我尝试连续多次终止所有子进程以清除积压,但问题仍然存在……对 PHP 页面的所有新请求都需要很长时间才能响应(大多数都没有响应)。
PHP配置:
max_execution_time = 30
max_input_time = 60
safe_mode = off
Apache 配置:
KeepAlive off
<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxClients 60
MaxRequestsPerChild 1000
</IfModule>
我已经没有主意了...如能提供任何提示我将非常感激!
答案1
我建议的故障排除步骤是:
strace -p $PID
在一个挂起的进程上查看它被卡在了哪些系统调用上(如果有的话)lsof -p $PID
查看该进程中打开的文件句柄或套接字是否可以给你提供线索tcpdump -vv -A -s1500 port 80
查看流量情况以及响应哪里出了问题。