hyperf 3.1 redis协程客户端默认不自动重连,需配置心跳检测('heartbeat' => true)、合理设置max_idle_time,并在pipeline/multi后用finally或withpipeline确保连接释放,同时业务层捕获redisexception并做降级或重试。

Hyperf 3.1 的 Redis 协程客户端默认不自动重连,断线后若未主动处理,后续调用会直接报错(如 Connection reset by peer 或卡在 get())。要实现稳定可用的 Redis 访问,需同时配置连接池健康机制和业务层异常兜底,而不是依赖“重连”本身。
Redis 连接池启用心跳检测(关键)
Hyperf 的 Redis 连接池本身不探测连接有效性,必须开启 heartbeat 并配合合理的空闲时间,才能在连接被服务端关闭前主动剔除它:
-
必须显式开启:
'heartbeat' => true,该选项默认为false,不设就等于没开 -
max_idle_time要比 Redis 的timeout少 30–60 秒(单位毫秒)。例如 Redis 配置了timeout 300(5 分钟),则这里设290000 - 配置位置在
config/autoload/redis.php对应 Redis 实例的pool子项下,不是全局配置 - 若使用 Swow 引擎,还需额外指定
'handler' => \Hyperf\Redis\Handler\SwowHandler::class,否则连接池无法复用
避免连接泄漏:pipeline/multi 必须配 finally
断线表现常由连接泄漏引发——比如 pipeline() 或 multi() 后未执行 exec(),连接就被长期独占,导致连接池耗尽、新协程等不到连接而超时。这不是断线问题,是资源没释放:
- 错误写法:
try { $redis->pipeline()->set('a',1)->get('b'); throw new Exception(); } catch (...) { }→exec()没执行,连接不归还 - 正确写法:用
try/finally包裹,确保exec()或discard()总被执行 - 更推荐:Hyperf 3.1+ 提供
withPipeline()方法,自动管理上下文与释放,无需手写 finally
业务代码中捕获并响应 Redis 异常
即使配置了 heartbeat,网络抖动、服务端重启等仍可能造成单次操作失败。应在关键 Redis 调用处做细粒度异常捕获,而非只靠全局异常处理器:
- 捕获
Hyperf\Redis\Exception\RedisException和底层Swoole\Coroutine\Redis\Exception - 对非关键操作(如日志记录、异步缓存更新),可静默忽略或降级(如跳过缓存直查 DB)
- 对关键操作(如分布式锁、库存扣减),建议加简单重试(最多 1–2 次),并记录 warn 日志
- 不要在异常处理里尝试“手动重连”,Hyperf 的连接池会在下次
get()时自动新建连接
排查是否真断线,还是连接池瓶颈
很多“断线”其实是连接池满导致的假象。先确认真实原因再调配置:
- 看日志是否频繁出现
WaitTimeoutException:这是连接池无空闲连接,不是 Redis 断了 - 检查
pool.max_connections是否足够:按峰值 QPS × 平均耗时 × 2~3 倍余量估算 - 用
ss -s | grep ESTAB或swoole_get_local_socket_count()查看实际 TCP 连接数是否贴近上限 - Redis 服务端执行
INFO clients看connected_clients是否异常高,或有大量idle时间长的连接











