一、前言:为什么你的 RedisTemplate 连不上集群?
你已经成功搭建了 Redis 分片集群(3 主 3 从),但在 Spring Boot 中配置 RedisTemplate 后却发现:
- ❌ 写入时报错:(error) MOVED 12345 192.168.1.10:7002
- ❌ 读取时连接超时
- ❌ 多 key 操作失败:CROSSSLOT Keys in request don't hash to the same slot
根本原因:你还在用单机模式配置连接集群!
本文将手把手教你正确配置 RedisTemplate 访问 Redis Cluster,并解决常见问题。
二、核心原理:客户端如何与 Cluster 通信?
Redis Cluster 是去中心化架构:
- 客户端首次连接任意节点
- 节点返回 MOVED 或 ASK 重定向指令
- 客户端缓存 <slot → node> 映射,后续直连目标节点
✅ Lettuce(Spring Boot 2.x+ 默认客户端)原生支持 Cluster 协议,自动处理重定向!
三、第一步:添加依赖(无需额外引入)
Spring Boot 2.7+ 已内置 Lettuce 和 Cluster 支持:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
⚠️ 不要手动引入 Jedis!除非你有特殊需求(Jedis Cluster 功能较弱)
四、第二步:配置 application.yml
4.1 基础配置(无密码)
spring:
redis:
cluster:
nodes:
– 192.168.1.10:7001
– 192.168.1.10:7002
– 192.168.1.10:7003
– 192.168.1.10:7004
– 192.168.1.10:7005
– 192.168.1.10:7006
timeout: 2000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
4.2 带密码的集群
spring:
redis:
password: your_cluster_password # 所有节点密码相同
cluster:
nodes: [ … ]
🔑 关键:只需列出部分节点即可(建议至少 3 个),Lettuce 会自动发现全集群拓扑。
五、第三步:配置 RedisTemplate(支持 JSON 序列化)
@Configuration
public class RedisClusterConfig {
@Bean
@Primary
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用 Jackson 序列化,避免乱码
Jackson2JsonRedisSerializer<Object> jsonSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY
);
jsonSerializer.setObjectMapper(mapper);
// 设置序列化器
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jsonSerializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
✅ 无需自定义 RedisConnectionFactory!Spring Boot 自动创建 LettuceConnectionFactory 并启用 Cluster 模式。
六、第四步:编写业务代码(自动路由)
@Service
public class UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void saveUser(Long userId, String name) {
// 自动计算 slot 并路由到对应主节点
redisTemplate.opsForValue().set("user:" + userId, name);
}
public String getUser(Long userId) {
// 自动路由到负责该 key 的节点(主或从)
return (String) redisTemplate.opsForValue().get("user:" + userId);
}
// ⚠️ 跨 slot 多 key 操作会失败!
public List<Object> getUsers(List<Long> userIds) {
List<String> keys = userIds.stream()
.map(id -> "user:" + id)
.collect(Collectors.toList());
return redisTemplate.opsForValue().multiGet(keys); // 可能报 CROSSSLOT
}
}
七、解决常见问题
❌ 问题 1:MOVED 错误(未启用 Cluster 模式)
- 原因:错误地使用了单机配置(如 spring.redis.host)
- 解决:必须使用 spring.redis.cluster.nodes
❌ 问题 2:CROSSSLOT 错误
- 原因:多个 key 不在同一 slot
- 解决:使用 Hash Tag 强制同 slot
// OK!{1001} 作为 hash tag
redisTemplate.opsForValue().multiGet(
Arrays.asList("{user1001}.name", "{user1001}.age")
);
❌ 问题 3:客户端未刷新拓扑(扩容/故障转移后连错节点)
- 解决:启用 Lettuce 拓扑自动刷新
spring:
redis:
lettuce:
cluster:
refresh-period: 30s # 每 30 秒刷新一次
八、高级配置:自定义 Lettuce 行为
如需更精细控制,可自定义 LettuceClientConfiguration:
@Bean
public LettuceClientConfigurationBuilderCustomizer lettuceClientConfigurationBuilderCustomizer() {
return builder -> builder
.commandTimeout(Duration.ofSeconds(3))
.clientOptions(ClusterClientOptions.builder()
.topologyRefreshOptions(
ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(30))
.enableAllAdaptiveRefreshTriggers() // 网络异常时主动刷新
.build())
.build());
}
九、验证是否生效
9.1 查看启动日志
INFO io.lettuce.core.cluster.RedisClusterClient –
Connecting to Redis at [192.168.1.10:7001, …]
INFO o.s.d.r.c.ClusterConnectionProvider –
Redis Cluster topology refreshed
9.2 监控 Redis 节点命令
- 在不同 master 上执行 MONITOR
- 观察写请求是否分布到不同节点(证明分片生效)
十、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!





