Spring Boot集成Redis集群(Cluster模式)

同样的,我们还是分两种集成方式来介绍,并是以 Cluster 模式进行集成。另外,还有几篇关于的 Windows 下 Redis 的搭建与集成系列文章可做参考

Spring Boot 项目集成 Redis

windows 下 Redis 的安装和使用

Windows 系统搭建 Redis 集群三种模式 (零坑、最新版)


集成 jedis#



引入依赖
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

配置绑定

新增配置

################################################ 连接池配置
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=100
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=2000
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=500
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0

################################################ redis 集群部署配置
#设置 key 的生存时间,当 key 过期时,它会被自动删除
spring.redis.cluster.expire-seconds=120
#设置 redis 集群的节点信息
spring.redis.cluster.nodes=127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005,127.0.0.1:7006
#设置命令的执行时间,如果超过这个时间,则报错
spring.redis.cluster.command-timeout=5000

新增对应配置映射类RedisPoolProperties

@Component
@PropertySource("classpath:/redis.properties")
public class RedisPoolProperties {

    private Integer maxActive;
    private Integer maxWait;
    private Integer maxIdle;
    private Integer minIdle;

    public Integer getMaxActive() {
        return maxActive;
    }

    public void setMaxActive(Integer maxActive) {
        this.maxActive = maxActive;
    }

    public Integer getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(Integer maxWait) {
        this.maxWait = maxWait;
    }

    public Integer getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(Integer maxIdle) {
        this.maxIdle = maxIdle;
    }

    public Integer getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(Integer minIdle) {
        this.minIdle = minIdle;
    }

    @Override
    public String toString() {
        return "RedisPoolProperties{" +
                "maxActive=" + maxActive +
                ", maxWait=" + maxWait +
                ", maxIdle=" + maxIdle +
                ", minIdle=" + minIdle +
                '}';
    }
}

连接池的配置的在上一篇文章Spring Boot 项目集成 Redis已做介绍


注册

拿到集群的相关配置,然后就集群的注册

@Configuration
public class RedisConfig {

	@Autowired
    private RedisClusterProperties redisClusterProperties;
    
    /* Jedis - 集群、连接池模式 */
    @Bean
    public JedisCluster jedisCluster(){

        /* 切割节点信息 */
        String[] nodes = redisClusterProperties.getNodes().split(",");
        Set<HostAndPort> hostAndPorts = new HashSet<>();
        for (String node : nodes) {
            int index = node.indexOf(":");
            hostAndPorts.add(new HostAndPort(node.substring(0,index),Integer.parseInt(node.substring(index + 1))));
        }

        /* Jedis 连接池配置 */
        JedisPoolConfig jedisPoolConfig = getJedisPoolConfig();

        return new JedisCluster(hostAndPorts,redisClusterProperties.getCommandTimeout(),jedisPoolConfig);

    }
    
    /**
     * 连接池配置
     * @return JedisPoolConfig
     **/
    private JedisPoolConfig getJedisPoolConfig(){
        
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        
        jedisPoolConfig.setMaxIdle(redisPoolProperties.getMaxIdle());       // 最大空闲连接数, 默认 8 个
        jedisPoolConfig.setMaxTotal(redisPoolProperties.getMaxActive());    // 最大连接数, 默认 8 个
        jedisPoolConfig.setMinIdle(redisPoolProperties.getMinIdle());       // 最小空闲连接数, 默认 0
        jedisPoolConfig.setMaxWaitMillis(redisPoolProperties.getMaxWait()); // 获取连接时的最大等待毫秒数 (如果设置为阻塞时 BlockWhenExhausted), 如果超时就抛异常, 小于零: 阻塞不确定的时间,  默认 -1
        jedisPoolConfig.setTestOnBorrow(true);                              // 对拿到的 connection 进行 validateObject 校验
        return jedisPoolConfig;
    }

}

获取 redis 客户端

新增一个工具接口IRedisCluster,然后写一个组件对接口进行实现:获取 redis 客户端实例后,进行 redis 相关操作的封装

接口

public interface IRedisCluster {

    String set(String key, String value);

    String get(String key);
}

实现IRedisCluster接口

@Service("redisClusterService")
public class RedisClusterService implements IRedisCluster{
    
    @Autowired
    private JedisCluster jedisCluster;

    @Override
    public String set(String key, String value) {
        return jedisCluster.set(key, value);
    }

    @Override
    public String get(String key) {
        return jedisCluster.get(key);
    }
}

先封装两个最简单的方法,更详细的封装后续再介绍


使用

新增一个RedisController编写简单的服务接口:

@RestController
public class RedisClusterController {

    @Autowired
    @Qualifier("redisClusterService")
    private IRedisCluster redisCluster;

    @PostMapping("/cluster/jedis/{key}")
    public void setDataByJedis(@PathVariable("key") String key){
        System.out.println("set" + key);
        redisCluster.set(key,key + "nice");
    }

    @GetMapping("/cluster/jedis/{key}")
    public void getDataByJedis(@PathVariable("key") String key){
        System.out.println(redisCluster.get(key));
    }


}

验证

用 postman 分别调用setDatagetData对应服务,控制台打印以下信息:

image

用 redis-cli 客户端连接集群中任意一个节点

redis-cli -c -p 7001

得到集群中已经有相关记录:

image


集成 spring-data-redis#



引入依赖
 <dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

配置绑定

因为是 Spring 封装的组件,所以有比较完善的支持,我们直接在 `` 下新增关于集群的配置

# ------------------------------------------------------------ cluster 集群模式
# 重连最大数
spring.redis.cluster.max-redirects=3
# 集群主机信息
spring.redis.cluster.nodes=127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005,127.0.0.1:7006

# ------------------------------------------------------------ 连接池配置
# lettuce
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.min-idle=0
  • 配置 spring.redis.lettuce.pool 节点会自动你开启连接池
  • 需将单机模式的相关配置注释掉,不然虽然能启动,但的操作 redis 时会报错

注册
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();

        /* 设置 value 的序列化规则和 key 的序列化规则 */
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

        redisTemplate.setKeySerializer(stringRedisSerializer);                // key 采用 String 的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);            // hash 的 key 也采用 String 的序列化方式
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); // value 序列化方式采用 jackson
        redisTemplate.setConnectionFactory(connectionFactory);                // 默认使用 letttuce,如果想使用 Jedis,创建 JedisConnectionFactory 实例作为参数传入

        return redisTemplate;
    }
}

获取 redis 客户端

同样实现的上述的IRedisCluster接口

@Service("redisClusterTemplateService")
public class RedisClusterTemplateService implements IRedisCluster{

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public String set(String key, String value) {
        redisTemplate.opsForValue().set(key,value);
        return key;
    }

    @Override
    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }
}

使用

编写对应的setget服务

@RestController
public class RedisClusterController {

    @Autowired
    @Qualifier("redisClusterTemplateService")
    private IRedisCluster redisTemplateCluster;

     @PostMapping("/cluster/{key}")
    public void setData(@PathVariable("key") String key){
        System.out.println("set" + key);
        redisTemplateCluster.set(key,key + "nice");
    }

    @GetMapping("/cluster/{key}")
    public void getData(@PathVariable("key") String key){

        System.out.println(redisTemplateCluster.get(key));
    }
}

验证

用 postman 分别调用setDatagetData对应服务,控制台打印以下信息:

image

用 redis-cli 客户端连接集群中任意一个节点

redis-cli -c -p 7006

得到集群中已经有相关记录:

image


异常处理#


io.lettuce.core.RedisConnectionException: Connection closed prematurely

redis 启动配置中默认是有保护模式的,要关闭保护模式