Redis Cluster从节点默认拒读,需先执行readonly命令或用redis-cli -c启动才能读取;该设置仅对当前连接生效,不解决复制延迟问题。

为什么从节点执行 GET 直接报 (error) MOVED
Redis Cluster 默认禁止从节点处理任何读请求,哪怕该键确实落在它所复制的主节点负责的槽位上。客户端一发 GET,从节点立刻返回 MOVED 重定向到对应主节点——这不是网络或配置错误,是集群协议层的硬性限制。
根本原因在于:从节点的连接默认标记为 flags=N(normal),不带只读语义;而集群要求「只读」必须显式声明,否则一律按写安全模型处理,强制路由到主节点。
-
readonly是连接级命令,每次新建连接后都得重输一次 - 断开重连、客户端自动重试、连接池复用等场景下,
readonly状态不会继承 - 执行
readwrite可退回到默认行为,但通常没必要
如何正确启用从节点只读能力
在已连接的从节点上,先执行 readonly,再发读命令。顺序不能反,且必须在同一连接内完成:
127.0.0.1:6384> readonly OK 127.0.0.1:6384> get songtest "testjc"
此时 client list 中该连接的 flags 会从 N 变成 r,表示只读连接已激活。
- 仅对当前连接生效,不影响其他连接或全局配置
- 不改变复制关系,也不影响故障转移逻辑
- 如果从节点尚未完成全量同步,
GET仍可能返回空或过期值——readonly不解决复制延迟问题
redis-cli 启动时就启用集群+只读模式
手动敲 readonly 容易漏,尤其在脚本或自动化流程中。更稳妥的方式是启动客户端时直接进入集群模式并隐式启用只读上下文:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
使用 redis-cli -c -p 6384 连接从节点,-c 参数会自动处理 MOVED 和 ASK 重定向,同时让客户端在从节点上尝试本地读取(前提是该槽由其主节点负责)。
-
-c模式下,GET请求若命中本地从节点负责的槽,会直接响应;否则才重定向 - 它比手动
readonly更适合运维排查和临时调试 - 但注意:
-c不等于“强制走从节点”,它仍遵守集群拓扑,只是把重定向逻辑交给客户端做
应用代码里怎么避免反复手动设置
用 Lettuce 或 Jedis 这类客户端时,不能依赖交互式命令。关键点是:连接初始化阶段就要注入只读状态。
Lettuce 示例(Java):
RedisURI redisUri = RedisURI.Builder.redis("127.0.0.1", 6384).withTimeout(Duration.ofSeconds(3)).build();
ClientResources resources = ClientResources.builder().build();
StatefulRedisConnection<String, String> connection = RedisClient.create(resources, redisUri).connect();
connection.sync().readonly(); // 必须在首次读之前调用
Jedis 示例(需确认版本 ≥ 4.0):
Jedis jedis = new Jedis("127.0.0.1", 6384);
jedis.readonly(); // 同样必须在 get 前执行
- 连接池场景下,需在
pool.getResource()后立即执行readonly(),或封装为自定义工厂 - Spring Boot 的
RedisTemplate默认不支持自动 readonly,需通过execute方法透传原生命令 - 别指望
slave-read-only yes配置项——集群模式下该配置完全被忽略
最常被忽略的一点:readonly 解决的是「能不能读」,不是「读得准不准」。从节点数据滞后几毫秒甚至几秒很常见,业务若强依赖实时性,就不该把读流量切过去。

















