最近几周,我们在部署代码时遇到了一个负面现象:服务器有时会在几分钟内无响应。
我能找到的唯一相关日志来自/var/log/php7.2-fpm.log
,有时(但并非总是)我会看到这样的条目(注意:这是来自与上图所示不同的事件,但同样会发生):
[22-Mar-2019 15:33:50] WARNING: [pool api] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 231 total children
[22-Mar-2019 15:33:52] WARNING: [pool api] server reached pm.max_children setting (250), consider raising it
[22-Mar-2019 15:34:05] WARNING: [pool app] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 47 idle, and 104 total children
发生的事情是我们对该服务器进行了部署:
git status --porcelain
检查修改git pull origin master
更新文件- 重置 opcache,即我们调用一个端点来执行
opcache_reset()
- 清除本地缓存文件
经过一些试验,我可以将负载问题减少到这样:opcache_reset()
一旦我执行了这个调用(独立于任何之前或之后的部署步骤,当我只调用这个端点时,这也是孤立地发生的),系统负载有可能突然飙升。
如果发生这种情况并且负载“太高”(根据经验我会说 > 200 左右),系统会在几秒钟或几分钟内没有响应,这取决于一切需要多长时间才能平静下来。
眼镜:
- 在 VMWare 上运行的 VM(不是我们自己托管的,我们有合作伙伴)
- 4 个 vCPU
- 8GB 内存
- 8GB 交换空间
- Ubuntu 18.04 TS
- nginx 1.14.0(Ubuntu 默认)
- PHP 7.2(通过https://launchpad.net/~ondrej/+archive/ubuntu/php)
PHP-FPM 配置:
- 我们正在使用具有不同虚拟主机的 6 个池
start_servers
直接总计320 个php -fpm 进程(也通过 确认ps auxw|grep -i fpm|grep -v grep |wc -l
)- 所有池的总数
max_children
约为870
也许这里的总数太高了,目的是为了应对个别虚拟主机上的峰值,有时碰巧有.
通常负载很低,除非我们有这个与 opcache 重置有关的峰值(我最近才发现) :
我知道重置缓存现在所有进程都必须重新填充它是消耗 CPU 的。
但我不明白的是:
- 这只是最近才开始发生,例如可能 1-2 个月,但仅在最近两周内,反应迟钝才明显
- 它并不总是发生,有时在重置缓存时,什么也没有发生
这是opcache_get_status(false)
部署之前的输出:
{
"opcache_enabled": true,
"cache_full": false,
"restart_pending": false,
"restart_in_progress": false,
"memory_usage": {
"used_memory": 67353640,
"free_memory": 66864088,
"wasted_memory": 0,
"current_wasted_percentage": 0
},
"interned_strings_usage": {
"buffer_size": 8388608,
"used_memory": 5215176,
"free_memory": 3173432,
"number_of_strings": 89109
},
"opcache_statistics": {
"num_cached_scripts": 2873,
"num_cached_keys": 5063,
"max_cached_keys": 7963,
"hits": 633581523,
"start_time": 1553172771,
"last_restart_time": 1553248200,
"oom_restarts": 0,
"hash_restarts": 0,
"manual_restarts": 6,
"misses": 9512,
"blacklist_misses": 0,
"blacklist_miss_ratio": 0,
"opcache_hit_rate": 99.9984987161316
}
}
之后在这里:
{
"opcache_enabled": true,
"cache_full": false,
"restart_pending": false,
"restart_in_progress": false,
"memory_usage": {
"used_memory": 57745856,
"free_memory": 76471872,
"wasted_memory": 0,
"current_wasted_percentage": 0
},
"interned_strings_usage": {
"buffer_size": 8388608,
"used_memory": 4337168,
"free_memory": 4051440,
"number_of_strings": 75163
},
"opcache_statistics": {
"num_cached_scripts": 2244,
"num_cached_keys": 3925,
"max_cached_keys": 7963,
"hits": 5893926,
"start_time": 1553172771,
"last_restart_time": 1553265235,
"oom_restarts": 0,
"hash_restarts": 0,
"manual_restarts": 7,
"misses": 4962,
"blacklist_misses": 0,
"blacklist_miss_ratio": 0,
"opcache_hit_rate": 99.91588245106536
}
}
我观察到的其他事情:
- php-fpm 很快停止响应
- 除非负载真的很高,否则 nginx 仍然可以工作;我确认了这一点,因为当 php-fpm 基本上无法访问时,nginx 会交付配置的 500 页面
是什么真正导致了这些负载峰值?我怎样才能避免它们?
接受答案后更新:
基本上只是不调用opcache_reset
并将我的大部分 opcache 设置自定义恢复为默认值(即不强加它们)修复它。
这一步是我多年来部署管道的一部分。我试图找出最初的原因,据我所知,当类引用尚未加载/刷新的新代码时,它与部署问题有关。
事后看来,我什至不确定这是不是真正的问题,但我们到了。
默认情况下,PHP 检查文件时间戳以使 opcache 条目无效。这可以关闭,这是我能想到的唯一使用场景
opcache_reset()
。当然,它也会导致您遇到的问题。我建议回到默认值: