redis slave节点默认只读,publish命令因属写操作而被拒绝,报错“readonly”;subscribe虽可执行但不可靠,因订阅关系不复制、不跨节点,且消息不通过复制通道转发,故生产环境应统一在master节点进行发布与关键订阅。

Slave节点执行PUBLISH命令直接报错
Redis 的 Slave 节点默认是只读的,这是由 replica-read-only yes(旧版叫 slave-read-only)配置强制控制的。一旦启用(默认开启),所有写命令(包括 PUBLISH)都会被拒绝,返回错误:READONLY You can't write against a read only replica.
注意:这不是 Pub/Sub 机制本身的限制,而是 Redis 复制架构的底层约束——Slave 只负责同步和提供读服务,不参与任何写操作决策,哪怕 PUBLISH 看似“不改数据”,它仍被归类为写命令。
-
PUBLISH会触发内部事件分发、更新订阅者计数、写入输出缓冲区,这些行为在协议层被标记为写操作 - 即使你手动关掉
replica-read-only,也**不推荐**让 Slave 执行PUBLISH——这会导致主从状态不一致(比如消息只发到 Slave 的订阅者,Master 不知道,其他 Slave 也收不到) - Slave 上能
SUBSCRIBE是因为订阅只是注册客户端状态,不修改数据,也不影响复制流
为什么SUBSCRIBE在Slave上能成功但实际不可靠
虽然 SUBSCRIBE 命令在 Slave 节点上能执行成功,但它的行为存在隐性风险:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 订阅关系只存在于当前 Slave 实例内存中,不会同步给 Master 或其他 Slave
- 如果该 Slave 故障或发生故障转移(failover),所有订阅连接立即丢失,且无法自动恢复
- 发布者若向 Master 的 channel 发布消息,该消息**不会转发给 Slave 上的订阅者**——Pub/Sub 不走复制通道,它是独立于 RDB/AOF 的实时通信路径
- 你看到的 “订阅成功” 只是 Redis 允许注册,不代表它能稳定收消息;真实场景中,99% 的生产环境都禁止把业务订阅逻辑部署在 Slave 上
读写分离架构下正确的发布/订阅部署方式
Pub/Sub 本质是实时广播通道,不是持久化消息队列。它必须和写入口对齐,否则语义就断了。正确做法只有一个:所有 PUBLISH 和关键 SUBSCRIBE 都走 Master 节点(或明确的写节点)。
- 发布端必须连 Master —— 否则消息发不出去,或只发到局部节点
- 订阅端可连 Master 或 Sentinel/Cluster 中的任意可读节点,但需确保:连接的是同一个逻辑集群,且网络可达 Master(因为 Pub/Sub 消息不复制,订阅者必须直连消息源)
- 如果用了代理(如 HAProxy、Twemproxy、Redis Proxy),确认它支持 Pub/Sub 协议透传;很多代理默认截断或不转发
SUBSCRIBE流,导致“看似连上了,实则收不到” - 使用客户端库(如 Jedis、StackExchange.Redis)时,检查是否启用了
pubsub专用连接池——普通连接池可能复用连接,而SUBSCRIBE后连接进入监听态,不能再发其他命令
容易被忽略的兼容性细节
有些团队试图绕过限制,在 Slave 上用 CONFIG SET replica-read-only no 再 PUBLISH,结果发现消息确实发出去了,但很快引发连锁问题:
- 该 Slave 的复制偏移量(
master_repl_offset)不再与 Master 对齐,INFO replication显示repl_backlog_active:0或同步中断 - 其他 Slave 可能因收到不一致的复制流而报错
Replication stream corrupted - 哨兵(Sentinel)或 Cluster 会检测到该节点状态异常,可能触发误判或自动剔除
- 更隐蔽的问题:某些客户端(尤其是老版本)在收到
READONLY错误后会静默降级重试,但重试目标仍是同一 Slave,形成死循环
真正需要读写分离 + Pub/Sub 的场景,应该用独立的 Master 实例承载发布逻辑,而不是强行在 Slave 上开写权限。










