(php-fpm generated a lot of load when resetting opcache, rendering server unresponsive)
最近几周,我们在部署代码时遇到了一种负面现象:服务器有时会在几分钟内变得无响应。
我可以找到的唯一相关日志来自/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_reset()
- 清除本地缓存文件
经过一些试验,我可以将负载问题减少到这样: opcache_reset()
一旦执行了此调用(与任何先前或以后的部署步骤无关,当我仅调用此端点时,此操作也会单独发生),系统负载可能会突然激增。
如果发生这种情况,并且负载“过高”(根据经验,我会说> 200左右),系统将变得无响应,直到几秒钟或几分钟,这取决于一切需要多长时间才能平静下来。
眼镜:
- 在VMWare上运行的VM(不是我们自己托管的,我们是合作伙伴)
- 4个vCPU
- 8GB RAM
- 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设置自定义项opcache_reset
并将其恢复为默认值(即不强加它们)来修复它。
实际上,这一步骤是我部署流程的一部分。我想找出最初的原因,据我所知,它与类引用未加载/刷新的新代码时的部署问题有关。
事后看来,我什至不确定这是否是实际的问题,但我们现在就在这里。
默认情况下,PHP检查文件时间戳以使opcache条目无效。可以将其关闭,这是我能想到的唯一opcache_reset()
可以使用的方案。当然,它也会引起你遇到的问题。
我建议回到默认值:
opcache.validate_timestamps = 1
opcache.revalidate_freq = 2
opcache.revalidate_path = 0
非常感谢你; 尽管事后看来很明显,但并没有那么明显地理解这根本没有必要:-)