ab命令跑出800请求每秒,力测MySQL直接挂了。力测这是力测上周帮朋友看的一个电商后台,PHP 7.4配MySQL 5.7,力测单表30万商品数据。力测他说平时也就几十个并发,力测结果一次推广活动涌进来几百人,力测整个站点卡死。力测问题不在PHP本身,力测而在每次请求都去查一次商品库存。力测
压力测试这件事,力测很多人上来就纠结工具选型。力测ab、力测wrk、力测JMeter、力测Locust,选哪个?我的看法是,先用ab把单接口跑通再说。ab的安装几乎零成本,Linux下apt install apache2-utils或者yum install httpd-tools就搞定。一条命令:ab -n 1000 -c 100 http://your-site/api/list,1000个请求、100并发,几秒钟出结果。关键是看两个数——Requests per second和Time per request。前者低于50,基本可以判断接口有问题。
但ab有个硬伤:它只能测单个URL,没法模拟用户登录态和会话保持。真实场景里用户先登录、再浏览、再加购物车,ab做不了这个链路。这时候得上wrk或者JMeter。wrk的Lua脚本能自定义请求头和body,轻量且性能极强,一台普通笔记本就能压出几万QPS。JMeter图形化,适合团队协作,但资源消耗大,GUI模式下跑高并发容易自己先崩。
说回PHP本身。PHP-FPM的进程数配置是第一个瓶颈点。pm.max_children默认值往往偏小,比如5或者10。100并发打进来,FPM直接排队,请求全部超时。调到50左右比较合理,具体看内存——每个PHP进程大概占30-50MB,服务器8G内存的话,100个进程就吃掉4G,留点余量给MySQL和系统。用pm.status_path打开状态页,实时看活跃进程数和排队数,比瞎猜靠谱。
第二个坑是数据库连接。每次请求new PDO?那压力测试一跑,MySQL的max_connections瞬间打满。用持久连接或者连接池,PHP-FPM环境下持久连接(PDO::ATTR_PERSISTENT => true)能省掉TCP握手和认证开销,但要注意事务残留问题。我自己的做法是用Swoole或者RoadRunner这类常驻内存方案,连接池天然支持,QPS能从几百直接拉到几千。
第三个是OPcache。没开OPcache的PHP,每次请求都要重新编译脚本,CPU全耗在词法语法分析上。检查opcache.enable=1,opcache.memory_consumption=128,opcache.max_accelerated_files=10000。这三个值调完,单接口响应时间能降30%以上。有个朋友的生产环境忘了开OPcache,压测时CPU 100%,开了之后直接降到40%。
再说个具体的观察。同一个接口,用ab压和用wrk压,结果可能差一倍。ab是同步阻塞模型,每个连接等上一个响应完才发下一个;wrk用epoll异步,能更充分地打满服务端。所以ab测出来的QPS偏保守,wrk的数字更接近极限。但别只看工具给的数字,结合服务器端的top、vmstat、MySQL的show processlist一起看。CPU是用户态高还是内核态高?磁盘IO有没有瓶颈?慢查询日志里有没有新出现的SQL?这些比单纯的QPS数字有价值得多。
最后提一句,压力测试不是一次性的活。每次改完代码、调完配置,重新跑一遍基线。把结果记下来,形成趋势图。哪天QPS突然掉了20%,翻记录就知道是哪个commit引入的。工具是死的,数据是活的,关键还是人去看、去分析、去调。