Spring Data Redis 不支持多数据源路由式读写分离,需通过 Lettuce 的 ReadFrom.REPLICA_PREFERRED 策略实现;必须使用哨兵或集群模式,配合正确拓扑配置与可达从节点才能生效。

Spring Data Redis 本身不支持多数据源路由式读写分离,所谓“配置多数据源”是常见误解——RedisTemplate 只能绑定一个 RedisConnectionFactory,无法像 JDBC 那样通过 AbstractRoutingDataSource 动态切换主/从连接池。
为什么不能像数据库那样配两个 RedisTemplate?
Redis 主从不是独立的数据源,而是同一份数据的拓扑视图。Spring Data Redis 的设计前提是:客户端(Lettuce)自行识别角色并按策略分发命令,而非应用层手动选节点。
-
RedisTemplate底层调用的是StatefulRedisConnection#sync(),其读写路由由 Lettuce 内部的ReadFrom策略控制,与你注入几个RedisTemplatebean 无关 - 手动 new 两个
RedisTemplate,分别指向主、从地址,会导致连接管理混乱、拓扑感知失效、故障转移失败 -
@Cacheable、StringRedisTemplate等所有基于RedisTemplate的抽象,都共享同一个 connection factory,无法“路由到从库”
真正起作用的是 Lettuce 的 ReadFrom 策略
必须显式配置 ReadFrom.REPLICA_PREFERRED(或 REPLICA),否则所有操作默认走主节点——哪怕你写了十个从节点地址,也不生效。
-
read-from: REPLICA_PREFERRED是 YAML 配置项,但仅在哨兵(sentinel)或集群(cluster)模式下被 Lettuce 解析;纯主从直连(spring.redis.host)不识别该配置 - 若用哨兵模式,
spring.redis.sentinel.master+spring.redis.sentinel.nodes配好后,再通过LettuceClientConfigurationBuilderCustomizer注入策略才有效 - 代码级配置优先于 YAML:
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED)必须写在自定义@Bean中,且该 bean 要@Primary
哨兵模式下最简可行配置
这是目前 Spring Boot 3.2+ 推荐的落地方式,兼顾自动发现与故障转移:
@Configuration
public class RedisConfig {
@Bean
@Primary
public RedisConnectionFactory redisConnectionFactory(RedisProperties properties) {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster") // 必须与哨兵中配置的 master name 一致
.sentinel("192.168.1.10", 26379)
.sentinel("192.168.1.11", 26379);
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED) // 关键:必须在这里设
.build();
return new LettuceConnectionFactory(sentinelConfig, clientConfig);
}
}
- 不要在
application.yml里写spring.redis.host,它会覆盖哨兵配置 - 哨兵节点必须可连通,且
mymaster名称大小写敏感,错一个字母就 fallback 到单节点直连 -
ReadFrom.REPLICA在所有从节点宕机时直接抛异常;REPLICA_PREFERRED才是生产推荐值
容易被忽略的三个硬性前提
即使代码全对,以下任一缺失都会导致读写分离静默失效:
- Redis 服务端必须开启
slave-read-only yes(默认已开),否则 Lettuce 不认为它是合法 replica - 从节点的
INFO replication输出中必须包含role:slave和master_host字段,Lettuce 靠这个反向构建拓扑 - 应用启动时,至少有一个从节点网络可达——Lettuce 初始化时会尝试连接列表中任一节点获取拓扑,连不上就退化为单主模式
最终效果不是“一部分请求走从库”,而是每次 redisTemplate.opsForValue().get("key") 都由 Lettuce 动态决定发给谁;你看到的慢查询日志、连接数分布,才是真实分流依据。



















