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启动配置中默认是有保护模式的,要关闭保护模式