hyperf协程中必须使用hyperf\redis\redis连接池实例,禁用原生redis扩展;需配置redis.php的pool参数,通过redisfactory获取多实例;禁用swoole\coroutine\redis直连。

Hyperf 协程中用 Redis,核心就一条:必须走协程安全的连接池,不能用同步阻塞的 Redis 扩展原生实例(比如 new \Redis()),否则会阻塞整个协程调度器。
用 Hyperf\Redis\Redis 实例操作最稳妥
这是官方封装好的协程 Redis 客户端,底层自动从连接池取连接、自动回收、支持 set/get/hGetAll 等全部常用命令,且默认就是协程安全的。
- 确保已安装:
composer require hyperf/redis - 配置好
config/autoload/redis.php,至少包含host、port、pool(特别是max_connections和wait_timeout) - 在控制器或服务中直接依赖注入:
public function __construct(\Hyperf\Redis\Redis $redis) - 调用方法和原生 Redis 基本一致:
$redis->set('key', 'value', 3600)、$redis->hGetAll('hash:key')
注意:$redis 是单例,但每次调用都会从连接池拿新连接(或复用空闲连接),不是共享同一个 socket —— 所以不用手动 close,也不用担心并发污染。
wait_timeout 设太小会直接报 WaitTimeoutException
这个参数控制“从连接池里等一个可用连接”的最长时间,默认是 3.0 秒。线上高并发时很容易触发,现象是接口偶发超时、日志里出现:
Hyperf\Pool\Exception\WaitTimeoutException: Wait timeout.
排查和调整建议:
- 先用
redis-cli -p 6379 client list | wc -l看当前 Redis 连接数,是否接近max_connections - 若连接数打满,优先调大
max_connections(比如从 10 → 20),而不是只压低wait_timeout -
wait_timeout不建议低于1.0,否则短时流量尖峰下大量请求会立刻失败,不如给点缓冲时间 - 如果业务有强实时性要求(如秒杀库存扣减),可单独为该逻辑配一个独立连接池(比如叫
seckill),避免和其他业务争抢连接
多 Redis 实例必须显式指定 poolName
当项目连多个 Redis(比如缓存用 cache、队列用 queue、通知用 notify),不能只靠 Redis 类注入,因为 DI 容器默认只绑定 default 实例。
正确做法是用 RedisFactory 显式获取:
- 注入工厂:
#[Inject] protected \Hyperf\Redis\RedisFactory $redisFactory; - 按名取实例:
$cacheRedis = $this->redisFactory->get('cache');或$queueRedis = $this->redisFactory->get('queue'); -
poolName必须和redis.php里定义的键名**完全一致**(大小写敏感、无空格),否则抛InvalidArgumentException
容易忽略的点:如果你在 redis.php 里写了 'notify' => [...],那代码里就必须写 get('notify'),写成 get('Notify') 或 get(' notification ') 都会失败 —— 这个报错反而比静默 fallback 更利于定位问题。
别在协程里用 Swoole\Coroutine\Redis 直连
虽然 Swoole 提供了原生协程 Redis 客户端,但在 Hyperf 里不推荐直接用它,原因很实际:
- 它不走 Hyperf 的连接池管理,无法复用连接、无法统计连接数、无法自动心跳保活
- 没有集成到 DI 容器,没法做统一配置(比如 auth、db、超时)、没法做连接隔离
- 遇到
connect timeout或read timeout时,错误类型和Hyperf\Redis\Redis不一致,日志和监控对不上 - 除非你明确需要某个 Swoole 特有指令(比如
brpoplpush),否则没必要绕过封装
真要用,也得自己包装一层连接池 + 超时兜底,工作量远超直接配好 hyperf/redis。











