Hyperf 3.1 分布式缓存必须联动协程上下文、连接池和服务发现,否则易引发缓存击穿、协程污染和连接泄漏;RedisPool需手动配置,因默认redis:// DSN走懒加载单例,共享连接导致高并发写竞争或阻塞。

Hyperf 3.1 的分布式缓存不是“配个 Redis 就完事”,而是必须和协程上下文、连接池、服务发现联动才能真正生效。单独配置 redis 客户端或 @Cacheable 注解,大概率会遇到缓存击穿、协程间数据污染、连接泄漏这三类问题。
为什么 RedisPool 必须手动配置,不能只靠 redis:// DSN?
Hyperf 3.1 默认的 redis:// 连接字符串走的是懒加载单例模式,所有协程共享同一个连接实例 —— 这在高并发下极易触发写竞争或超时阻塞。真实生产环境必须显式声明连接池。
-
config/autoload/cache.php中禁用默认redis驱动,改用pool驱动 - 在
config/autoload/pool.php里定义RedisPool,关键参数:'min_connections' => 5(防冷启动抖动)、'max_connections' => 30(匹配 Swoole worker 数)、'connect_timeout' => 1.0 - 避免使用
RedisFactory的createDriver()直接 new 实例,它绕过 DI 容器生命周期管理
@Cacheable 在微服务调用链中失效的常见原因
当一个 RPC 接口被多个服务(如 user-service 和 order-service)同时调用时,@Cacheable 默认只在当前进程内生效,跨服务不共享缓存键,更不会自动穿透到上游服务的缓存层。
- 缓存 key 默认基于类名 + 方法名 + 参数序列化生成,但不同服务的类命名空间不同,导致 key 冲突或重复计算
- 若启用了
Consul服务发现,需配合cache:prefix配置项统一前缀,例如'prefix' => 'hyperf:prod:' - 不要在
JSON-RPC接口方法上直接加@Cacheable,应改用CacheAspect手动控制缓存读写时机,避免协程上下文丢失
中间件里读写缓存的陷阱:协程上下文隔离 vs 全局连接池
在 Middleware 中调用 $this->container->get(CacheInterface::class) 获取缓存实例,看似合理,但实际可能拿到的是非池化连接,尤其在 onReceive 或 onConnect 回调中。
- 必须确保中间件构造函数中注入的是
PoolProxy包装后的CacheInterface,而非原始驱动实例 - 检查
di.php是否覆盖了CacheInterface绑定,正确写法是:Container::set(CacheInterface::class, function (Container $container) { return make(PoolProxy::class, ['pool' => 'redis']); }); - 禁止在中间件
process()中执行sleep()或阻塞 I/O,协程调度会被打断,导致连接池归还延迟甚至泄漏
真正难的不是配置几行 YAML,而是在协程常驻模型下,把缓存生命周期、连接复用边界、服务间 key 空间划分这三件事对齐。漏掉任意一环,压测时 QPS 上不去,线上就表现为偶发性缓存 miss 或 Redis 连接数飙升。


















