我花了数周时间解决导致 Apache 停止响应直到重新启动的问题,现在我在这里写下这篇文章。这种情况每天发生 3/4 次,有时是几小时后,有时是几分钟后,有时是一天后。这与服务器的并发连接数无关(至少没有证据):它发生在流量高峰期(上午 8:00 至下午 6:00 之间)和访问量非常低的夜间。
配置:VM on Vmware ESXi Rel. 7 - 操作系统:Ubuntu 20.04、Apache 2.4.41、PHP 8.0.15、MSSQL 驱动程序 17.8.1.1-1。6 CPU“Xeon(R) Gold 5218”,12Gb Ram。3 个网站以“纯”PHP 运行(没有 CMS,如 Wordpress、Drupal、Ruby On Rails 等)。Awstats 显示,没有外部访问的内部网每天提供的页面数不到 10k,其他网站每天提供的页面数约为 200k。大多数时候 CPU 使用率约为 1%,内存使用量约为 2Gb。当问题发生时,没有检测到 CPU/内存/网络“峰值”。
当时我安装并配置监控每 20 秒使用 curl 测试一下这个最小的 PHP 网页:
<?php
echo "ok";
?>
通常它会打印“ok”。在“冻结”期间,即使是这个简单的页面也无法提供服务;curl 以超时错误结束并触发 monit 执行“service apache2 restart”。2/3 秒后,网站恢复正常功能(直到下一次冻结)。
以下是未成功补救措施的列表(不按时间顺序排列):
- 删除了 certbot-Letsencrypt 并使用了 Sectigo 购买的 SSL 证书
- 将 Apache 从 mpm_worker 切换到 mpm_event
- 禁用一堆未使用的 Apache 模块
- 禁用一堆未使用的 PHP 模块
- 禁用大多数非关键的 cron 作业(甚至没有证据表明在 cron 作业执行期间发生冻结)。
- 将虚拟网络适配器从 VMXNET3 更改为 E1000
- 启用详细日志记录:没有记录有用的信息/错误,只是在挂起之前提供的最后一页与重启完成时提供的第一页之间存在 25-30 秒的时间间隔。
- 已启用几天mod_log_forensic:使用 check_forensic 实用程序时未报告任何错误
- 仔细检查 .conf 和 .htaccess 中的几条重写规则
- 更改了 Apache 的配置;相关值是:
StartServers 10
MinSpareThreads 40
MaxSpareThreads 120
ThreadLimit 100
ThreadsPerChild 75
MaxRequestWorkers 450
MaxConnectionsPerChild 1000
问题发生前提供的“最后”页面/文件之间没有明显的关联:有时是 PHP 页面(显然不一样),有时是 png/jpeg 图像。阅读日志时,我找不到异常/格式错误/过多的客户端请求。
这个问题 99.99% 与 Apache 有关,PHP-fpm 服务运行正常,冻结后无需重新启动。所有其他服务器的运行服务均不受影响。
在写这篇文章之前,我阅读了大量网页,但没有找到任何有用的(对我来说)提示。
提前致谢
再见
建业达