Spring Data Redis 主从集群 哨兵集群 分片集群 yml 配置

Spring Data Redis,yml 配置中添加 Redis 主从集群配置,一主二从集群,没有哨兵

在 Spring Data Redis 中,针对没有哨兵(Sentinel)一主二从 架构,配置方式主要取决于你使用的客户端(Lettuce 或 Jedis)以及你是否需要读写分离

通常情况下,Spring Boot 会自动发现主从关系,但如果需要精细控制(如强制从从节点读取),则需要通过 Java 配置类配合 yml 来实现。

以下是基于 Lettuce 客户端(Spring Boot 2.x/3.x 默认)的完整配置方案。

1. application.yml 配置

在没有哨兵的情况下,我们通常手动指定所有节点(主节点 + 从节点),或者仅指定主节点(Lettuce 会自动通过 CLUSTER NODESINFO REPLICATION 发现从节点,但在静态主从模式下建议显式列出)。

yaml 复制代码
spring:
  redis:
    # 默认连接的主节点 IP(用于初始化连接)
    host: 192.168.1.100 
    port: 6379
    password: your_password
    database: 0
    timeout: 3000ms
    
    # 关键配置:Lettuce 连接池与读写策略
    lettuce:
      pool:
        max-active: 20      # 最大连接数
        max-idle: 10        # 最大空闲连接
        min-idle: 5         # 最小空闲连接
        max-wait: 2000ms    # 连接超时时间
      # 拓扑刷新策略(可选,用于动态感知节点变化)
      cluster:
        refresh:
          adaptive: true

    # 如果你使用的是 Jedis,配置结构会有所不同(见下文补充)
    jedis:
      pool:
        max-active: 20
        max-idle: 10
        min-idle: 5

注意 :在纯主从模式(非集群模式)下,spring.redis.cluster.nodes 配置项通常不生效或不需要配置。我们需要在 Java 配置类中构建静态的主从拓扑。

2. Java 配置类(实现读写分离)

仅靠 yml 配置,Spring 默认所有请求都会发往主节点。为了实现**"主写从读"**,你需要创建一个配置类,利用 LettuceClientConfiguration 设置读取策略。

这里演示如何配置 优先从从节点读取 (REPLICA_PREFERRED):

java 复制代码
import io.lettuce.core.ReadFrom;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;

import java.util.Arrays;

@Configuration
public class RedisMasterReplicaConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.password}")
    private String password;

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        // 1. 定义主从节点拓扑结构
        // 格式:host:port,这里手动指定一主二从
        RedisStaticMasterReplicaConfiguration config = new RedisStaticMasterReplicaConfiguration(
                Arrays.asList(
                        host + ":" + port,          // 主节点
                        "192.168.1.101:6380",       // 从节点 1
                        "192.168.1.102:6381"        // 从节点 2
                )
        );
        config.setPassword(RedisPassword.of(password));

        // 2. 配置 Lettuce 客户端行为
        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                // 核心配置:优先从从节点读取数据
                // 如果从节点不可用,会自动回退到主节点
                .readFrom(ReadFrom.REPLICA_PREFERRED) 
                .build();

        // 3. 创建连接工厂
        return new LettuceConnectionFactory(config, clientConfig);
    }
}

3. 核心配置说明

配置项/策略 说明
RedisStaticMasterReplicaConfiguration 用于在非哨兵模式下,手动指定主从节点列表。Spring 会维护这个静态列表。
ReadFrom.REPLICA_PREFERRED 推荐。优先从 Slave 读取,如果 Slave 挂了,自动切回 Master,保证高可用。
ReadFrom.REPLICA 强制只从 Slave 读取。如果 Slave 全挂,会抛出异常(不推荐,除非你有严格的一致性要求且能容忍报错)。
ReadFrom.UPSTREAM 默认行为。只从 Master 读取(即没有读写分离)。

4. 补充:如果你使用的是 Jedis

虽然 Lettuce 是默认推荐,但如果你使用的是 Jedis,配置逻辑类似,但类名不同:

java 复制代码
// Jedis 版本的配置思路
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;

// ... 在 @Bean 中
RedisStaticMasterReplicaConfiguration config = new RedisStaticMasterReplicaConfiguration(...);
// Jedis 同样支持 readFrom 设置,但通常通过 JedisClientConfiguration 构建
JedisClientConfiguration clientConfig = JedisClientConfiguration.builder()
        .readFrom(ReadFrom.REPLICA_PREFERRED)
        .build();

return new JedisConnectionFactory(config, clientConfig);

5. 验证配置是否生效

启动项目后,你可以通过以下方式验证:

  1. 查看日志:启动时观察控制台日志,看是否成功连接到了所有指定的节点。
  2. 压测观察 :在主节点和从节点的服务器上使用 tcpdump 或 Redis 监控工具,观察 GET 请求是否分发到了从节点(6380, 6381),而 SET 请求是否只在主节点(6379)执行。
  3. Redis 命令 :在 Redis 主节点执行 info replication,确保 connected_slaves 数量为 2,且状态为 online

Spring Data Redis,yml 配置中添加 Redis 哨兵集群配置

在 Spring Data Redis 中配置 Redis 哨兵(Sentinel)集群,核心在于告诉 Spring Boot:"不要直接连 Redis 主节点,而是去问哨兵节点,当前的老大(Master)是谁"。

以下是基于 Spring Boot 2.x/3.x 和默认客户端 Lettuce 的完整配置方案。

1. application.yml 配置

这是最关键的一步。你需要配置哨兵节点的列表以及主节点在哨兵配置中定义的逻辑名称 (通常叫 mymaster,但具体取决于你的 Redis 服务端配置)。

yaml 复制代码
spring:
  redis:
    # 1. 哨兵配置核心
    sentinel:
      master: mymaster  # 【重要】这是 Redis 主节点在 Sentinel 配置中的逻辑名称,不是 IP
      nodes:            # 哨兵节点的 IP:Port 列表(建议配置所有哨兵,用逗号分隔或列表格式)
        - 192.168.1.100:26379
        - 192.168.1.101:26379
        - 192.168.1.102:26379
    
    # 2. 认证与基础配置
    password: your_redis_password  # Redis 主从节点的密码
    # sentinel-password: your_sentinel_password # 如果哨兵节点单独设置了密码,需配置此项(Spring Boot 2.4+)
    database: 0
    timeout: 3000ms

    # 3. 连接池配置 (Lettuce)
    lettuce:
      pool:
        max-active: 20      # 最大连接数
        max-idle: 10        # 最大空闲连接
        min-idle: 5         # 最小空闲连接
        max-wait: 2000ms    # 获取连接的最大等待时间

⚠️ 注意事项:

  • master 字段 :必须与 Redis 服务端 sentinel.confsentinel monitor <master-name> ... 这一行的 <master-name> 完全一致。
  • nodes 字段 :这里填写的是哨兵的端口(默认 26379),而不是 Redis 数据节点的端口(默认 6379)。

2. 实现读写分离(Java 配置)

仅配置 yml 文件,Spring Boot 默认会连接 Master 进行读写。如果你希望利用从节点(Slave)分担读流量,需要添加一个简单的 Java 配置类来指定读取策略。

java 复制代码
import io.lettuce.core.ReadFrom;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;

@Configuration
public class RedisSentinelConfig {

    @Bean
    public LettuceConnectionFactory redisConnectionFactory(RedisSentinelConfiguration sentinelConfig) {
        
        // 配置 Lettuce 客户端:优先从从节点读取数据
        // 如果从节点不可用,会自动降级回主节点
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(sentinelConfig, clientConfig);
    }
}

3. 配置参数详解

配置项 说明
spring.redis.sentinel.master 逻辑名称 。Spring 会问哨兵:"谁是 mymaster 的老大?",哨兵会返回当前的 Master IP。
spring.redis.sentinel.nodes 哨兵列表。Spring 会随机连接其中一个哨兵来获取 Master 地址。如果连接失败,会自动尝试列表中的下一个。
spring.redis.password 数据节点密码。用于连接 Redis Master/Slave 的密码。
spring.redis.sentinel.password 哨兵节点密码 。如果你的哨兵进程单独设置了 requirepass,需要配置此项。

4. 常见问题排查

  1. 启动报错 Cannot get master address from sentinel

    • 检查 master 名称是否拼写正确(通常默认是 mymaster,但也可能是 master1 等)。
    • 检查防火墙是否开放了哨兵端口(26379)。
    • 确保 Spring Boot 服务器能 ping 通哨兵服务器。
  2. 连接到了错误的 IP

    • Redis 哨兵返回的是 Redis 实例配置的 IP。如果 Redis 部署在 Docker 或 NAT 网络后,确保 Redis 实例配置的 bind-ip 和哨兵能识别的 IP 是 Spring Boot 服务器能访问的。
  3. Spring Boot 3.x 差异

    • Spring Boot 3.x 的配置前缀依然是 spring.data.redis(在 yml 中通常简写为 spring.redis),配置结构基本保持不变。

Spring Data Redis,yml 配置中添加 Redis 分片集群配置

在 Spring Data Redis 中配置 Redis 分片集群(Redis Cluster),核心在于告诉客户端集群的"种子节点"。客户端(默认是 Lettuce)连接后会自动发现整个集群拓扑结构。

以下是基于 Spring BootLettuce 客户端的完整配置方案。

1. application.yml 配置

这是最基础也是最重要的部分。你需要列出部分节点(通常建议列出所有主节点,或者至少 3 个节点),Spring Boot 会自动识别这是一个集群环境。

yaml 复制代码
spring:
  redis:
    # 1. 集群配置核心
    cluster:
      # 节点列表(逗号分隔或数组格式)
      # 注意:这里填写的是 Redis 数据节点的 IP:Port,不是哨兵端口
      nodes:
        - 192.168.1.100:7001
        - 192.168.1.100:7002
        - 192.168.1.100:7003
        - 192.168.1.100:7004
        - 192.168.1.100:7005
        - 192.168.1.100:7006
    
    # 2. 认证与基础配置
    password: your_redis_password  # 集群统一密码
    timeout: 3000ms                # 命令超时时间

    # 3. Lettuce 客户端配置(推荐)
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
        min-idle: 5
        max-wait: 2000ms
      # 集群拓扑刷新配置(应对主从切换)
      cluster:
        refresh:
          adaptive: true  # 自适应刷新:遇到 MOVED/ASK 重定向时自动更新拓扑
          period: 60s     # 定期刷新:每 60 秒强制刷新一次拓扑(作为兜底)

💡 关键点说明:

  • spring.redis.cluster.nodes :只要配置了此项,Spring Boot 就会自动启用 RedisClusterConfiguration,无需手动指定 hostport
  • 节点数量:不需要配置所有 6 个节点,配置 3 个主节点通常就足够 Lettuce 发现全貌,但为了高可用,建议配置所有节点。
  • adaptive: true :非常重要。当集群发生主从切换(Failover)时,客户端缓存的槽位(Slot)映射会失效。开启此配置后,Lettuce 收到 MOVED 异常时会自动更新路由表,无需重启服务。

2. 实现读写分离(Java 配置)

与哨兵模式类似,默认情况下 Spring Data Redis 会优先读写主节点。如果你希望利用从节点分担读流量,需要添加配置类。

java 复制代码
import io.lettuce.core.ReadFrom;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.RedisClusterConfiguration;

@Configuration
public class RedisClusterConfig {

    @Bean
    public LettuceConnectionFactory redisConnectionFactory(RedisClusterConfiguration clusterConfig) {
        
        // 配置 Lettuce 客户端:优先从从节点读取数据
        // 如果从节点不可用,会自动降级回主节点
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(clusterConfig, clientConfig);
    }
}

3. 代码使用注意事项(跨 Slot 问题)

在分片集群中使用 RedisTemplate 时,有一个巨大的"坑"需要注意:多 Key 操作

  • 单 Key 操作(推荐)
    • set(key, value), get(key), hget(key, field) 等完全没问题,客户端会自动计算 Hash Slot 并路由到正确节点。
  • 多 Key 操作(限制)
    • mget(key1, key2), mset(key1, val1, key2, val2) 等操作,要求所有 Key 必须落在同一个 Slot 上
    • 如果 key1 在节点 A,key2 在节点 B,直接调用会报错 CROSSSLOT Keys in request don't hash to the same slot

解决方案:使用 Hash Tag {}

如果你必须对多个 Key 进行批量操作,可以使用 {} 包裹 Key 的公共部分,强制它们落入同一个 Slot。

java 复制代码
// 错误示范:可能跨 Slot
redisTemplate.opsForValue().multiGet(Arrays.asList("user:1001", "user:1002"));

// 正确示范:强制使用相同的 Slot(取 {} 内的内容计算 hash)
// 这两个 Key 都会根据 "common_group" 计算槽位,从而落在同一个节点
redisTemplate.opsForValue().multiGet(Arrays.asList("{common_group}:user:1001", "{common_group}:user:1002"));

4. 配置参数详解

配置项 说明
spring.redis.cluster.nodes 种子节点列表 。客户端连接任意一个节点后,会执行 CLUSTER NODES 命令获取完整拓扑。
spring.redis.lettuce.cluster.refresh.adaptive 自适应刷新。开启后,当遇到重定向异常时,自动触发拓扑更新,是生产环境必备配置。
spring.redis.lettuce.cluster.refresh.period 定期刷新。作为双重保险,定期后台刷新拓扑结构。
spring.redis.password 集群密码。Redis Cluster 通常所有节点配置相同的密码。

5. 常见报错排查

  1. MOVED xxx 192.168.x.x:700x

    • 这是正常现象,表示客户端请求的节点不是该 Key 的负责节点,节点告诉客户端"去那边找"。
    • 解决 :确保开启了 adaptive: true,Lettuce 会自动处理。如果一直报错,检查网络是否通畅,或者客户端是否无法连接新的 IP(如内网 IP 映射问题)。
  2. CROSSSLOT Keys in request don't hash to the same slot

    • 原因 :执行了 mgetmset 或事务操作,但涉及的 Key 分布在不同的槽位。
    • 解决 :使用 {tag} 语法强制 Key 落在同一槽位,或者在代码中循环单 Key 操作(性能稍低)。
  3. 连接超时

    • 检查 Redis 节点的 cluster-announce-ip 配置。如果 Redis 在 Docker 中,必须配置该参数为宿主 IP,否则客户端拿到的拓扑信息是容器内网 IP,导致无法连接。
相关推荐
威联通安全存储1 小时前
深度观察:跨越“存起来”的误区,智造时代如何重构工业数据底座?
大数据·人工智能·python·重构
暮冬-  Gentle°1 小时前
更优雅的测试:Pytest框架入门
jvm·数据库·python
凸头1 小时前
后过滤召回塌陷:Redis 先召回 → ES 再过滤,如果全部被过滤掉怎么办?
数据库·redis·elasticsearch
早睡早起好好code1 小时前
InternNav 论文回看
笔记·python·深度学习·学习·算法
kcuwu.2 小时前
Python文件操作零基础及进阶
android·服务器·python
傻啦嘿哟2 小时前
使用 Python 实现 Word 文档文本格式化全解析
开发语言·python·word
2501_921649492 小时前
外汇实时汇率 API | 24 小时 架构设计与实战指南
大数据·python·websocket·金融·restful