不能只用jmeter直连mysql压测,因会绕过hyperf路由、中间件、连接池、协程调度等关键环节,导致测试结果无法反映真实业务接口性能;必须通过hyperf http接口压测并结合hyperf/metric等工具分析全链路指标。

Hyperf 本身不提供内置的数据库压测能力,必须借助外部工具(如 JMeter)构造并发 SQL 请求;但直接用 JMeter 测 MySQL,只能看到数据库层表现,无法定位是 Hyperf 框架层、连接池配置、协程调度还是 SQL 执行逻辑拖慢了整体链路。真正的瓶颈分析,得把 JMeter 的请求打到 Hyperf 的 HTTP 接口上,再配合框架自带的性能分析器(如 hyperf/tracer 或 hyperf/metric)采集全链路指标。
为什么不能只用 JMeter 直连 MySQL?
直连 MySQL 绕过了 Hyperf 的整个请求生命周期:路由分发、中间件、DB 连接池管理、协程上下文切换、ORM 封装开销等全被跳过。你测出的 QPS 再高,也不代表业务接口能扛住同等压力。常见错误现象包括:
- JMeter 直连 MySQL 报
Communications link failure,但 Hyperf 接口却正常——说明问题在连接复用或超时配置不一致 - 直连压测吞吐量达 8000 QPS,而通过 Hyperf 接口压测只有 1200 QPS,且
cpu_usage不高、memory_used稳定——大概率是协程调度阻塞或 DB 连接池max_connections设得太小 - 响应时间 P95 突增但错误率为 0——需检查是否触发了 Hyperf 的
max_coroutine限制,导致新请求排队等待协程资源
JMeter 发送请求到 Hyperf 接口的关键配置
确保压测的是真实业务路径,不是裸 DB 连接。你需要:
- 在 Hyperf 中暴露一个带数据库操作的 HTTP 接口(例如
GET /api/user/{id}),内部使用Db::table()->where()->first()或Model::find() - JMeter 的
HTTP RequestSampler 中,Server Name or IP填部署 Hyperf 的服务器地址,Path填对应接口路径,Protocol为http或https - 务必禁用 JMeter GUI 模式执行压测:启动命令必须用
jmeter -n -t test.jmx -l result.jtl -e -o report/,否则 GUI 自身内存和线程开销会污染结果 - 线程组的
Ramp-Up Period建议设为与预期流量增长节奏匹配(如模拟秒杀,设为1;模拟日常高峰,设为300),避免瞬间打垮 Hyperf 的max_coroutine
用 hyperf/metric 暴露关键指标给 JMeter 关联分析
仅看 JMeter 的 Aggregate Report 不够,必须把 Hyperf 运行时指标拉出来交叉验证。启用 hyperf/metric 后,在 config/autoload/metrics.php 中配置 Prometheus 输出:
return [
'default' => [
'driver' => Hyperf\Metric\Adapter\Prometheus\RemoteWriteDriver::class,
'config' => [
'url' => 'http://localhost:9091/api/v1/write',
],
],
];
然后在压测期间访问 http://your-hyperf-server:9501/metrics(默认暴露端口),重点关注:
-
hyperf_http_server_request_duration_seconds_bucket:对比 JMeter 的 P95 响应时间,确认是否一致 -
hyperf_db_query_duration_seconds_sum:SQL 平均耗时,若该值远低于总响应时间,说明瓶颈在 PHP 层或网络 -
hyperf_coroutine_count:实时协程数,若持续接近max_coroutine配置值,就是协程资源不足的明确信号 -
hyperf_db_pool_connections_idle和hyperf_db_pool_connections_active:连接池水位,若active长期满而idle为 0,需调大max_connections
Hyperf 数据库连接池参数与压测表现强相关
Hyperf 的 max_connections 默认是 10,这在 JMeter 设置 100 线程时必然成为瓶颈。修改位置在 config/autoload/databases.php:
'mysql' => [
'driver' => Hyperf\Database\Connectors\MysqlConnector::class,
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 5,
'max_connections' => 50, // ← 必须根据 JMeter 线程数 × 每请求 DB 调用次数预估
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => 60.0,
],
],
注意:max_connections 不是越大越好。若设为 200 但 MySQL 服务端 max_connections 只有 150,会导致大量连接拒绝,JMeter 报错 Too many connections;若设为 50 但 JMeter 线程数 100 且每个请求查 3 次库,仍会排队等待。











