FPM进程过多,挤爆了CPU,导致短时间内服务器接口迟缓的问题如何解决?
1. 运行环境
LNMP
1). 当前使用的 Laravel 版本?
Laravel 6.20.44
2). 当前使用的 php/php-fpm 版本?
PHP 版本:7.4.30
php-fpm 版本:
3). 当前系统
CentOS 7.9
4核 8G
4). 业务环境
业务环境:生产
负载均衡:无(所有服务均在一个机器上)
5). 相关软件版本
Nginx1.22.1、MySQL5.7.39、Redis 6.2.7
2. 问题描述?
抢购商品的场景,200人左右,逐渐增长中,现在有一个问题就是,到点抢购时,cpu(4核)就被fpm给干满了,业务跑完后(下单的业务已经变成异步队列形式,所有流程上的逻辑没有耗费任何时间)cpu就正常了。大部分是用户占用,内存占用很低;开启了Opcahe、路由缓存、配置文件缓存、能搞的都搞了,php慢日志也没有什么错误。
我用jmeter在测试环境测试了一番(2核4G的),直接请求了单个php文件,200并发时cpu没问题;但是使用laravel框架路由访问到控制器内(只是输出一个字符串,没有任何业务逻辑),这一瞬间也把cpu干爆了(2-3s的样子,生产环境用户点击更复杂大概10s左右用户不同时刷新了cpu也就立马下来了)
3. 您期望得到的结果?
希望有经验的大神能客观指点一下如下疑问:
1、你们并发访问laravel框架内控制器的方法时fpm占用cpu资源率是多少,会不会爆满?
2、是否有必要使用swoole?
3、如需要提升配置,是升单个服务器的配置还是使用多个服务器做负载均衡?
抢购场景200人不一定只有200并发,如果前端不控制点击和刷新频率的话,这点人直接拉高配置就好,前端控制,oss这些做好,还用不上负载均衡。
试试这个
fpm 的
pm
设置为static
。pm.max_children
设置为CPU核心的两倍。然后如果还是扛不住,建议考虑做弹性伸缩支持,因为你这个其实就是临时性的需求。完全可以通过临时申请服务器来解决问题。其实PHP 还支持 opcache, DB 持久链接,preload预加载,我觉得你都可以参考下。
php的优化有限。无所谓是
代码层
和fpm
层。除去这两个之外的任何手段,都没用,想都不用想。说说swoole
因为laravel的特性,使用swoole,只能每个请求都重新初始化所有的全局对象container、request、response、validate、db等。swoole和opcache的结合没研究过不知道opcache能不能助力swoole,如果不能那每次光文件I/O开销就够一壶了。如果用swoole还是建议使用hyperf等框架
世界加钱可及
在所有的优化手段都应用后还是慢,可以考虑加机器了。一台不够两台,两台不够10台。相信在10台机器都不够的前提下,你一定是不缺钱的。
200 并发 4核8G 应该是扛不住的,你可以试试修改 php-fpm.conf 改成 static,但不一定管用,如果是到点抢购,可以用云平台的弹性伸缩+负载均衡,直接镜像你原来的服务器,操作起来很简单,就注意点如果数据库和 redis 在原服务器存储,弹性服务器一定要写成主服务器的 ip。
在 Laravel 框架中,当多个请求同时访问控制器的方法时,FPM(FastCGI Process Manager)的 CPU 资源占用率会根据请求的复杂度和数量以及服务器的配置情况而异。因此,无法确定 FPM 在并发访问时的 CPU 资源占用率会是多少,也不能保证它不会爆满。通常情况下,为了避免 FPM 占用过多 CPU 资源,应该尽量减少对控制器方法的并发访问,或者通过优化服务器配置来提高 FPM 的处理能力。
换webman吧
升到php8+lv9+octane(swoole),你的单机还可以继续战斗。。
有没有可能。。你的瓶颈是mysql。。不是php
从你的问题来看的话,目前感觉就是php-fpm过多,CPU占用率高,但是包括其他指标都没有提供,有点难看出瓶颈 首先建议,先把php-fpm进程改成static,数量一般都是64左右,开opcache,再重新压测下看看吧
可以尝试一下升级 php8.1, 开启Jit,个人并发自测过,有倍数级的并发提升。
使用Laravel Octane,带宽拉高,我觉得不使用Laravel Octane或swoole,拯救不了,除非堆配置
php 如果是 fpm 模式选框架还是 phalcon 这种扩展性的香,laravel什么优雅纯粹扯犊子
先把各种缓存加了吧,比如opencache,不行直接上webman,composer装过去无缝
把抢购服务单独拉出来用swoole做服务端处理高频请求。 原来的业务结构不变。
令牌桶 + 按照用户账号加锁 控制下进入的用户,限制每个用户ID 进入controller次数
升级服务器配置 完美解决