必须用GetSubscriber(),IDatabase.Publish()是伪方法:它只发COMMAND PUBLISH命令,不走Pub/Sub通道;真正发布和订阅必须通过ISubscriber实例,且共用同一ConnectionMultiplexer单例连接。

必须用 GetSubscriber(),IDatabase.Publish() 是伪方法
很多人一写就错:直接调 redis.GetDatabase().Publish("channel", "msg"),看似返回成功,但订阅端永远收不到。因为 IDatabase.Publish() 底层只是发个 COMMAND PUBLISH 命令,不走 Pub/Sub 连接通道,也不参与客户端连接状态管理。
真正建立订阅通道、维持长连接、接收广播消息的,只有 IConnectionMultiplexer.GetSubscriber() 返回的 ISubscriber 实例。发布也必须用它:subscriber.PublishAsync("channel", "msg")。
-
ISubscriber是轻量、无状态的,每次GetSubscriber()都返回新对象,但共享底层物理连接 - 不能把
ISubscriber当成单例反复复用——不同业务逻辑建议各持一个独立实例,避免SubscribeAsync()和UnsubscribeAsync()混乱 -
IDatabase只管键值读写,ISubscriber才管消息广播,二者职责严格分离
发布和订阅必须共用同一个 ConnectionMultiplexer 实例
这是 90% “能发不能收”问题的根源。如果发布代码用了 new ConnectionMultiplexer(...),而订阅代码用了另一个单例类里封装的连接,哪怕都连向 localhost:6379,消息也一定丢。
Redis 服务端只把消息推给“当前连接上已注册该频道的客户端”。两个连接实例 = 两个独立 client,彼此看不到对方的订阅关系。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 务必统一使用单例连接(如
Lazy<connectionmultiplexer></connectionmultiplexer>封装) - 检查
ConnectionMultiplexer.IsConnected为true后再调SubscribeAsync(),否则订阅静默失败 - Docker 环境下注意:
localhost在容器内指向自己,发布/订阅两端都要用宿主机 IP 或host.docker.internal
频道名大小写敏感且不自动 trim 空格
调试时最隐蔽的坑:sub.Subscribe("user:login") 收不到 sub.Publish("USER:LOGIN", "ok") 的消息;更糟的是配置项里写 "ChannelName": " user.events ",代码拼接后实际订阅的是带前后空格的字符串,Redis 完全匹配失败。
- 所有频道名应统一小写 + 下划线风格,如
"order:created" - 从配置或用户输入获取频道名时,必须显式
.Trim(),并做.ToLowerInvariant() - 用
redis-cli手动验证:SUBSCRIBE order:created和PUBLISH order:created "test"能通,说明服务端没问题
UnsubscribeAsync() 必须手动配对调用,GC 不会帮你清理
ISubscriber 不实现 IDisposable,using var sub = connection.GetSubscriber() 完全无效。不调 UnsubscribeAsync(),连接会一直挂着,服务端持续维护该 client 的订阅结构体(含缓冲区、回调队列),内存缓慢增长,最终触发 Redis 的 maxclients 限制或客户端 OOM。
- 在
IHostedService.StartAsync()中订阅,在StopAsync()中取消;不要在 MVCController方法里临时订阅 - 若需按需监听,务必保存
ISubscriber引用,并在明确退出点调await sub.UnsubscribeAsync("channel") - 批量退订可用
await sub.UnsubscribeAsync(new[] { "a", "b" }),传null表示退订全部
真正难的不是写通第一行 SubscribeAsync(),而是让这套机制在长周期服务里稳住连接、不漏退订、不跨实例、不被空格和大小写绊倒。这些细节不靠文档,靠一次线上排查。

















