Hyperf的hyperf_db_query_duration_ms仅记录PDO执行耗时,无法反映连接池排队、MySQL锁竞争、索引失效、连接数超限等底层瓶颈,必须结合mysqld_exporter暴露的MySQL原生指标(如threads_connected、innodb_row_lock_time_avg)进行关联分析才能准确定位。

Hyperf 本身不直接监控 MySQL 性能瓶颈,必须通过 mysqld_exporter 暴露数据库指标,再由 Prometheus 抓取;Hyperf 的 hyperf/metric 只负责上报自身进程内的 DB 查询耗时(hyperf_db_query_duration_ms),但无法反映连接池饱和、锁等待、慢查询堆积等底层瓶颈。
为什么不能只靠 hyperf_db_query_duration_ms 判断数据库瓶颈
这个指标只是框架层记录的「从 PDO::prepare 到 execute 完成」的耗时,它掩盖了大量关键问题:
- 连接池已满导致请求在队列中排队,
hyperf_db_query_duration_ms不包含排队时间 - MySQL 内部锁竞争(如行锁、表锁)造成的阻塞,PHP 层无感知
- 查询未走索引、执行计划突变,单次耗时可能正常但 QPS 下降明显
- 连接数接近
max_connections上限,新连接被拒绝,而 Hyperf 日志里只显示 PDO 连接超时
真正要定位瓶颈,得看 mysqld_exporter 暴露的原始 MySQL 状态变量,比如 mysql_global_status_threads_connected、mysql_global_status_innodb_row_lock_time_avg、mysql_global_status_slow_queries。
mysqld_exporter 必须用最小权限账号运行
给 mysqld_exporter 配置的 MySQL 账号不能是 root 或 super 权限,否则存在安全风险。正确做法是创建专用账号并仅授权必要权限:
- 执行
CREATE USER 'exporter'@'%' IDENTIFIED BY 'xxx'; - 授予
PROCESS(查线程状态)、REPLICATION CLIENT(查主从延迟)、SELECT(查information_schema表) - 禁止
GRANT OPTION、FILE、SHUTDOWN等高危权限
如果权限不足,mysqld_exporter 启动后会报错:Error pinging mysqld: error getting info from MySQL: SELECT command denied to user 'exporter'@'x.x.x.x' for table 'processlist',此时需回退检查授权语句。
Prometheus 抓取配置要匹配 mysqld_exporter 的启动方式
mysqld_exporter 默认监听 0.0.0.0:9104,但实际部署时常见三种情况,抓取配置必须对应:
- 容器内直连 MySQL:用
--mysqld.address=host.docker.internal:3306,Prometheusscrape_configs中 target 填mysqld-exporter:9104 - 宿主机部署:MySQL 地址填真实 IP(非
127.0.0.1),否则 exporter 连不上;Prometheus target 填host_ip:9104 - K8s 环境:用 Service DNS 名,如
mysqld-exporter.default.svc.cluster.local:9104,避免用 NodePort 引入额外延迟
如果 Prometheus 抓取失败,在 http://<prometheus-ip>:9090/targets</prometheus-ip> 页面会看到 context deadline exceeded 或 connection refused,优先确认网络连通性和 exporter 进程是否存活。
Hyperf 和 MySQL 监控数据要关联分析才有效
单独看 Hyperf 的 hyperf_db_query_duration_ms 分位数,或单独看 MySQL 的 mysql_global_status_slow_queries,都容易误判。真正有用的分析是交叉比对:
- 当
hyperf_db_query_duration_ms{quantile="0.99"}突增,但mysql_global_status_slow_queries平稳 → 问题在 PHP 层(如连接池配置过小、GC 频繁) - 当
mysql_global_status_threads_connected接近上限,且hyperf_db_query_duration_ms也升高 → 连接池和 MySQL 都承压,需先扩容连接数或优化慢查询 - 当
mysql_global_status_innodb_row_lock_waits显著上升,而hyperf_db_query_duration_ms分布右偏 → 锁冲突是主因,应检查事务范围和索引设计
这种关联依赖 Grafana 的多源面板叠加或 PromQL 的 on() join,不是开箱即用的功能,需要手动构建查询逻辑。最容易被忽略的是时间窗口对齐——Prometheus 抓取间隔(如 15s)和 Hyperf 指标采集间隔(默认 5s)不同步,直接相除会导致毛刺。必须统一用 rate() 或 avg_over_time() 对齐时间粒度。



















