WaitTimeoutException本质是连接池无空闲连接可分配,需调优pool.max_connections(≥峰值QPS×平均耗时×2–3倍余量)和pool.wait_timeout(推荐3.0秒),并排查pipeline/multi未exec导致的连接泄漏及MySQL异常污染协程上下文问题。

Hyperf 3.1 报 WaitTimeoutException,本质不是 Redis 慢,而是连接池没空闲连接可分配。核心要解决“等不到连接”这个卡点,而不是调大超时时间硬扛。
检查并调优连接池配置
重点看 config/autoload/redis.php 中的两个参数:
- pool.max_connections:必须 ≥ 峰值 QPS × 平均单次 Redis 耗时(单位秒)。例如 120 QPS × 0.08s = 9.6 → 至少设为 15;但建议留 2–3 倍余量,直接设为 40 或 50 更稳妥
- pool.wait_timeout:别设成 0.1(太激进)或 10(掩盖问题)。推荐 2.0~5.0 秒。设为 3.0 是多数场景下的平衡点
排查 pipeline/multi 连接泄漏
这是高频隐形原因:调用 $redis->pipeline() 或 $redis->multi() 后,若中途异常跳出、或忘记调 ->exec(),连接会被长期独占,协程不退出就一直不释放。
- 错误写法:
try { $redis->pipeline(); throw new RuntimeException(); } catch (\Throwable $e) {}→ 连接泄漏 - 正确写法:用
try/finally包裹,确保exec()或discard()执行;或直接改用 Hyperf 3.1+ 提供的withPipeline()封装方法,它自动处理上下文清理 - 临时验证:在疑似位置加日志,打印
Context::has($redis->getContextKey()),若为true但未执行exec(),基本确认泄漏
留意 MySQL 异常引发的上下文污染
不是 Redis 本身断连,而是业务中混用 DB 和 Redis 时,MySQL 因 wait_timeout 断开后事务回滚失败、异常未捕获,导致后续 Redis 操作在已损坏的协程上下文中执行,表现就是无响应或 Connection reset by peer。
- 检查日志是否同时出现 MySQL “gone away” 和 Redis 连接异常
- 确保 MySQL 操作有完整 try/catch,异常后主动清理或重建事务上下文
- 避免在同一个协程里跨长时间混用 DB + Redis,尤其在定时任务或长连接场景
观察连接池真实水位
别只看配置,要验证运行时状态:
- 用
swoole_get_local_socket_count()或ss -s | grep ESTAB查看当前 ESTABLISHED 连接数,是否持续逼近max_connections - 开启 Hyperf 的连接池监控(如 Prometheus + Grafana),跟踪
hyperf_pool_idle_connections和hyperf_pool_active_connections指标 - 在压测时抓取
strace -p $(pgrep -f 'php bin/hyperf.php start') -e trace=connect,sendto,recvfrom,确认是否真在等连接











