必须显式声明read-from策略,否则所有读写请求默认全走主节点;Spring Boot的spring.redis.host/port仅支持单节点,多地址仅作故障转移候选,Lettuce需通过哨兵或cluster.nodes获取拓扑并配合read-from(如REPLICA_PREFERRED)才能启用动态读写分离。

read-from 配置必须显式声明,否则所有读写请求默认全走主节点——这是最常被忽略的前提。
为什么 @Cacheable 和 redisTemplate.opsForValue().get() 还是打到主节点?
根本原因不是代码写法问题,而是 Lettuce 客户端压根没启用读写分离策略。Spring Boot 的 spring.redis.host 和 spring.redis.port 只支持单节点地址,即使你填了多个 IP:PORT,Lettuce 也只当它是故障转移候选列表,不会自动识别主从拓扑。
真正触发读路由到从节点的,是 read-from 策略,且必须在配置中明确指定。
- 常见错误现象:
@Cacheable方法、StringRedisTemplate.opsForValue().get()、redisTemplate.hasKey()全部打到主节点,从节点 CPU/网络零负载;监控发现主节点连接数高、延迟上升 -
read-from不是连接建立时静态绑定的,而是在每次执行sync()或async()时动态选节点 - 该配置对
RedisTemplate、@Cacheable、ReactiveRedisTemplate全局生效
哨兵模式下怎么配 read-from: REPLICA_PREFERRED?
哨兵模式必须同时满足三个条件,缺一不可:
- 配置
spring.redis.sentinel.nodes和spring.redis.sentinel.master,让 Lettuce 能获取主从拓扑信息 -
read-from必须写在spring.redis.lettuce下级(不是cluster或根层级) - 大小写敏感:
REPLICA_PREFERRED(Lettuce 3.2+),不是SLAVE_PREFERRED
正确示例:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
spring:
redis:
sentinel:
nodes: 192.168.1.10:26379,192.168.1.11:26379
master: mymaster
lettuce:
pool:
max-active: 32
read-from: REPLICA_PREFERRED
主从直连(非哨兵)怎么启用读写分离?
主从直连不依赖哨兵,但需要 Lettuce 主动发现拓扑,因此必须用 cluster.nodes 列出所有节点(主 + 所有从),并确保 Redis 实例返回的 INFO replication 中的 ip 字段是真实可访问地址(不能是 127.0.0.1)。
- 配置路径是
spring.redis.cluster.nodes,不是sentinel - 每个节点必须能响应
INFO replication,且其中的role、master_host、slave0等字段完整准确 - 若从节点
INFO返回的是127.0.0.1,Lettuce 会连不上——需在 redis.conf 中设replica-announce-ip和replica-announce-port
运行时动态切换读策略怎么办?
静态配置无法满足多机房、灰度、AB 测试等场景,这时得用代码干预客户端构建过程:
- 注册
LettuceClientConfigurationBuilderCustomizerBean - 在
customize()方法里调用clientConfigurationBuilder.readFrom(ReadFrom.REPLICA)或其他枚举值 - 可结合
@ConditionalOnProperty、环境变量或配置中心实现策略热切换 - 注意:该定制器只影响新创建的连接,已建立的连接不会重配置
真正容易被忽略的点是:Lettuce 的读节点选择发生在每次命令执行时,不是连接初始化时;所以哪怕你改了配置,旧连接仍按原策略走,必须重建连接池或重启应用才能生效。

















