WaitTimeoutException 根源是 wait_timeout 过小而非连接数不足,需同步调高该值(建议生产设为5.0且类型为float),并联动调整 max_connections;还需检查 min_connections、pipeline 异常释放、connect/read timeout 等配置。

WaitTimeoutException 不是连接数不够,而是协程排队等连接的时间太短——只调 max_connections 没用,必须同步调高 wait_timeout 并确认类型为 float。
为什么 max_connections 加了还报 wait timeout
根本原因是 wait_timeout 仍卡在默认的 1.0 或 2.0 秒。这个值控制协程在池里“等空闲连接”的最长时间,不是数据库或 Redis 的响应耗时。哪怕连接池里有空闲连接,只要协程排队超过该阈值,就直接抛 WaitTimeoutException。
- 日志反复出现 “wait timeout”,但
php bin/hyperf.php hyperf:redis:pool:stats显示current_used远低于max_connections→ 典型wait_timeout过小 -
SHOW PROCESSLIST或redis-cli CLIENT LIST看不到堆积连接 → 问题不在后端服务,而在连接池调度逻辑 - 压测时毛刺集中在某几秒,且与 Lua 脚本、慢查询、网络抖动时间吻合 → 等待窗口被轻易击穿
wait_timeout 和 max_connections 怎么配才合理
二者必须联动估算,不能孤立设置:
-
wait_timeout生产建议设为5.0(float 类型),开发环境不低于2.5;写成'wait_timeout' => '5.0'会因类型错误被忽略,必须显式转(float) env('REDIS_WAIT_TIMEOUT', 5.0) -
max_connections要按峰值 QPS × 平均耗时 × 余量算:例如线上 120 QPS、Redis 平均耗时 80ms,则理论需 9.6 个连接,起步设 30–50;单机 8 Worker 混用 cache/queue 场景,可设到 80 - MySQL 池和 Redis 池必须分开配,
max_connections不能复用同一数值——Redis 池设 200 可能打满 Redis 实例,而 MySQL 池设 200 则大概率触发Too many connections
容易漏掉的三个配置细节
光改 max_connections 和 wait_timeout 还不够,这三个点不检查,调参等于白调:
-
min_connections没设或设太低(如 1)→ 冷启动时每次都要新建连接,放大首屏延迟,建议设为 5–10 -
pipeline或multi调用后异常跳出,没兜住exec()→ 连接被协程长期独占,池子越用越小;必须用try/finally包裹,或升级到 Hyperf 3.1+ 使用withPipeline() -
connect_timeout和read_timeout混淆:前者是建连超时(推荐 3.0–5.0),后者是读响应超时(推荐 5.0),二者都影响连接获取链路,但不等价于wait_timeout
怎么验证改完真生效
重启服务后别只盯日志有没有错,要抓实时数据:
- 执行
php bin/hyperf.php hyperf:redis:pool:stats,看current_used是否贴近你设的max_connections,若长期 >90% 且仍有wait timeout,大概率是pipeline泄漏 - 用
swoole_get_local_socket_count()或ss -s | grep ESTAB观察进程级 TCP 连接数是否稳定,避免 fd 泄漏 - 配合 Prometheus 查
hyperf_redis_pool_used_connections和hyperf_redis_pool_wait_seconds_sum,后者持续升高说明等待队列积压
真正难的是平衡:池子太小,请求排队超时;太大,又可能把 Redis 打满,还掩盖了代码里真实的连接泄漏点。


















