本文目录导读:

- 核心流程(建议按顺序进行)
- 常用压力测试工具
- 典型 PHP 压力测试场景与脚本
- 关键注意事项(避免“假压测”)
- 监控与分析(压测时同步进行)
- 常见瓶颈与优化方向
- 进阶:使用 Swoole 或 Workerman 的压测
- 快速入门步骤
进行 PHP API 压力测试,主要目的是模拟高并发请求,找出系统的性能瓶颈(如 QPS、响应时间、CPU/内存消耗等)。
以下是完整的实施步骤,包括工具选择、测试流程、常见瓶颈分析和优化建议。
核心流程(建议按顺序进行)
- 确定测试目标:API 需要支撑
1000 QPS,P99 响应时间< 200ms。 - 选择测试工具。
- 准备测试脚本与数据(注意排除 PHP 自身瓶颈,如 Opcache 未开启)。
- 执行测试(从小并发逐步加压)。
- 监控系统资源(CPU、内存、I/O、PHP-FPM 进程数)。
- 分析结果与优化。
常用压力测试工具
ab(Apache Bench)—— 最简洁
适合快速测试单一接口的吞吐量。
ab -n 10000 -c 100 http://your-api.com/endpoint
-n:总请求数-c:并发数(模拟同时 100 个客户端)
输出关键指标:
Requests per second:QPSTime per request:平均响应时间Failed requests:失败率
wrk—— 高性能、可脚本化
比 ab 更强大,支持 Lua 脚本构造复杂请求(如 POST、带 Token)。
wrk -t12 -c400 -d30s http://your-api.com/endpoint
-t:线程数(= CPU 核心数)-c:连接数-d:测试持续时间
POST 请求示例(需写 Lua 脚本):
wrk.method = "POST"
wrk.body = '{"username":"test"}'
wrk.headers["Content-Type"] = "application/json"
Apache JMeter—— 图形化、最全面
适合复杂的测试场景(如登录 → 获取数据 → 提交订单等事务链)。
- 优点:支持分布式压测、报告详细。
- 缺点:配置相对繁琐,对机器资源占用较高。
Locust—— Python 编写,代码驱动
适合技术团队,用 Python 写测试逻辑,可动态调整并发。
from locust import HttpUser, task, between
class MyUser(HttpUser):
wait_time = between(1, 2.5)
@task
def get_data(self):
self.client.get("/api/data")
运行:
locust -f locustfile.py --host=http://your-api.com
典型 PHP 压力测试场景与脚本
假设你的 API 是一个返回 JSON 的用户信息接口:
// api/user.php
header('Content-Type: application/json');
$id = $_GET['id'] ?? 0;
$user = $db->query("SELECT * FROM users WHERE id = $id");
echo json_encode($user->fetch());
使用 wrk 测试 GET 接口:
wrk -t4 -c100 -d60s http://your-api.com/api/user?id=1
使用 ab 测试 POST 接口(需写文件):
将 POST 数据写入 post.txt,
ab -n 10000 -c 100 -p post.txt -T application/json http://your-api.com/api/login
关键注意事项(避免“假压测”)
-
确保 Opcache 已开启
PHP 解释执行是 IO 密集型,不开 Opcache 的话,每个请求都会重新编译 PHP 文件,测试结果会严重偏低。opcache.enable=1 opcache.memory_consumption=128 opcache.max_accelerated_files=4000
-
数据库连接池与慢查询
PHP 默认每次请求都创建/销毁数据库连接,使用连接池(如 Swoole)或持久连接(pconnect)可显著提升并发。
注意排查是否存在慢 SQL(slow_query_log)。 -
PHP-FPM 配置调优
pm.max_children:最大进程数(经验公式:内存 / 每个进程内存,8GB 内存,每个进程约 30MB,则pm.max_children ≈ 250)pm.start_servers、pm.min_spare_servers、pm.max_spare_servers:根据并发量合理设置。request_terminate_timeout:避免请求卡死占用进程。
-
日志与 IO 影响
压力测试时,建议暂时关闭access_log,或者将日志写到独立的磁盘(如 SSD、tmpfs),否则频繁写日志会严重拖慢性能。 -
模拟真实数据
不要总是请求同一个 ID(如?id=1),否则 MySQL 的query cache会美化结果,使用随机 ID 或其他参数。
监控与分析(压测时同步进行)
服务器端实时监控
# PHP-FPM 进程状态 watch -n 1 "ps aux | grep php-fpm | wc -l" # 系统负载 top -bn1 | head -5 # MySQL 线程数 mysqladmin status
关键指标记录
| 指标 | 说明 |
|---|---|
| QPS 峰值 | 系统吞吐上限 |
| 平均响应时间 | 用户体验关键 |
| P99 响应时间 | 最慢 1% 请求耗时 |
| CPU 空闲率 | 低于 20% 说明 CPU 是瓶颈 |
| PHP-FPM 空闲进程数 | 如果为 0 且等待队列增长,说明进程数不足 |
常见瓶颈与优化方向
| 现象 | 可能原因 | 优化方案 |
|---|---|---|
| CPU 高,QPS 低 | PHP 代码效率低、Opcache 未开启 | 开启 Opcache,优化复杂算法,引入 Redis 缓存 |
| 内存高 | PHP-FPM 进程数过多 | 降低 pm.max_children,使用 pm = ondemand |
| 网络 I/O 高 | 外部 API 调用慢、数据库连接慢 | 批量处理、异步请求(Swoole)、连接池 |
| 数据库 CPU 高 | 慢查询、无索引 | 添加索引、启用查询缓存、读写分离 |
| QPS 上不去且 CPU 空闲 | 锁竞争(文件锁、数据库行锁) | 减少锁粒度、使用乐观锁、升级 SSD |
进阶:使用 Swoole 或 Workerman 的压测
如果是传统 PHP-FPM,单个请求结束后会销毁所有资源,并发能力天然受限(通常单机 500~2000 QPS)。
如果使用 Swoole 或 Workerman(常驻内存),单机 QPS 可达数万,此时压测方式相同,但需关注:
- 协程数量:Swoole 的
max_coroutine限制。 - 内存泄漏:常驻内存下,循环变量未释放会积累。
- TCP 连接数:
ulimit -n需调大(如 65535)。
快速入门步骤
- 本地或测试服务器,开启 Opcache。
- 使用
wrk或ab对一个简单 GET 接口进行压测(如返回{"status":"ok"}),先测出基础网络+PHP 框架的极限。 - 加入数据库查询(带随机 ID),观察 QPS 下降幅度。
- 逐步增加并发数,再监控服务器资源,找到瓶颈点。
- 根据瓶颈(CPU、内存、IO、DB)针对性优化。
这样你的压测结果才真正反映了 API 的承载能力,而不是被 PHP 配置或系统限制所掩盖。