从单机到集群,SpringBoot集成Redis让你的架构更强大

从单机到集群,SpringBoot集成Redis让你的架构更强大

1场景

当我们项目中集成了Redis时,但是Redis架构可能随着项目的大小、数据量、业务量等等进行变化。我们在做架构时,可能需要兼容三种模式,当项目想要选择单机、哨兵、集群时可以进行无缝切换。

2实现

完成以后,可通过配置文件指定对应的模式即可。上代码

Maven依赖

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>3.7.1</version>
</dependency>

Spring配置文件关于Redis部分的配置

# redis
spring.redis.database=0
spring.redis.host=192.168.50.130
spring.redis.port=6379
spring.redis.password=enginex123
#连接超时时间(毫秒)
spring.redis.timeout=6000
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=3000
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=1000
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=100
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=5
# 集群模式配置
    #最大重定向次数
spring.redis.cluster.max-redirects=5
    #集群节点列表
spring.redis.cluster.nodes=192.168.0.10:6380,192.168.0.10:6381,192.168.0.10:6382,192.168.0.11:6380,192.168.0.11:6381,192.168.0.11:6382

# 哨兵模式配置
    #哨兵服务的密码,可能与redis本身密码是不用的,具体在sentinel配置文件里配置
spring.redis.sentinel.password=enginex123
    #主节点名称
spring.redis.sentinel.master=masterRedis
    #Sentinel节点列表
spring.redis.sentinel.nodes=192.168.50.130:26379
#redis环境模式 standalone:单机  cluster:集群 sentinel:哨兵
redis.model = sentinel

读取Redis属性配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author lisw
 * 微信公众号 ,走进Java
 * @description redis配置
 * @createDate 2022-11-01 16:23:40
 **/

@Data
@Configuration
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
    private String host;

    private Integer port;

    private String password;

    private Integer database;

    private int timeout;

    private Cluster cluster;

    private Sentinel sentinel;

    public static class Cluster {
        private List<String> nodes;

        private Integer maxRedirects;

        public List<String> getNodes() {
            return nodes;
        }

        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }

        public Integer getMaxRedirects() {
            return maxRedirects;
        }

        public void setMaxRedirects(Integer maxRedirects) {
            this.maxRedirects = maxRedirects;
        }
    }

    public static class Sentinel{
        private List<String> nodes;
        private String master;
        private String password;

        public List<String> getNodes() {
            return nodes;
        }

        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }

        public String getMaster() {
            return master;
        }

        public void setMaster(String master) {
            this.master = master;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}

读取Jedis属性配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @author lisw
 * 微信公众号 ,走进Java
 * @description redis配置
 * @createDate 2022-11-01 16:26:16
 **/

@Data
@Configuration
@Component
@ConfigurationProperties(prefix = "spring.redis.jedis.pool")
public class JedisProperties {
    private Integer maxIdle;

    private Integer maxWait;

    private Integer minIdle;

    private Integer maxActive;
}

Jedis 三种模式的Bean注入

SpringBoot,Jedis Bean注入,通过配置文件里面的redis.model属性决定使用什么模式,注入什么Bean,利用@ConditionalOnProperty注解

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.*;

import java.util.HashSet;
import java.util.Set;

/**
 * @author lisw
 * 微信公众号 ,走进Java
 * @description Redis Bean
 * @createDate 2022-11-01 16:27:56
 **/

@Configuration
public class RedisConfig {
    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private JedisProperties jedisProperties;

    @ConditionalOnProperty(value = "redis.model",havingValue = "standalone",matchIfMissing = true)
    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(jedisProperties.getMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
        if (StringUtils.isNotBlank(redisProperties.getPassword())) {
            return new JedisPool(jedisPoolConfig, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getTimeout(), redisProperties.getPassword(), redisProperties.getDatabase());
        } else {
            return new JedisPool(jedisPoolConfig, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getTimeout(), null, redisProperties.getDatabase());
        }
    }

    @ConditionalOnProperty(value = "redis.model",havingValue = "sentinel",matchIfMissing = false)
    @Bean
    public JedisSentinelPool jedisSentinelPool(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(jedisProperties.getMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
        // 截取集群节点
        String[] sentinels = redisProperties.getSentinel().getNodes().toArray(new String[0]);
        // 创建set集合
        Set<String> nodes = new HashSet<>();
        // 循环数组把集群节点添加到set集合中
        for (String node : sentinels) {
            //添加节点
            nodes.add(node);
        }
        if(StringUtils.isNotBlank(redisProperties.getSentinel().getPassword())){
                return new JedisSentinelPool(redisProperties.getSentinel().getMaster(),nodes,jedisPoolConfig, redisProperties.getTimeout(),redisProperties.getTimeout(),
                        redisProperties.getPassword(),redisProperties.getDatabase(),null,redisProperties.getTimeout(),redisProperties.getTimeout(),
                        redisProperties.getSentinel().getPassword(),null);
        }else{
            return new JedisSentinelPool(redisProperties.getSentinel().getMaster(),nodes,jedisPoolConfig,redisProperties.getTimeout(),redisProperties.getPassword() );
        }
    }

    @ConditionalOnProperty(value = "redis.model",havingValue = "cluster",matchIfMissing = false)
    @Bean
    public JedisCluster getJedisCluster() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(jedisProperties.getMaxIdle());
        poolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
        poolConfig.setMinIdle(jedisProperties.getMinIdle());
        poolConfig.setMaxTotal(jedisProperties.getMaxActive());
        // 截取集群节点
        String[] cluster = redisProperties.getCluster().getNodes().toArray(new String[0]);
        // 创建set集合
        Set<HostAndPort> nodes = new HashSet<>();
        // 循环数组把集群节点添加到set集合中
        for (String node : cluster) {
            String[] host = node.split(":");
            //添加集群节点
            nodes.add(new HostAndPort(host[0], Integer.parseInt(host[1])));
        }
        //需要密码连接的创建对象方式
        return new JedisCluster(nodes, redisProperties.getTimeout(), 2000, redisProperties.getCluster().getMaxRedirects(), redisProperties.getPassword(), poolConfig);
    }
}

定义对业务使用的RedisManager接口

业务上使用时通过RedisManager注入进行使用,三种模式只会注入一个进去。代码如下:

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import com.fibo.ddp.common.utils.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import java.util.*;

public interface RedisManager {

    byte[] get(byte[] key);
    String get(String key);
    byte[] set(byte[] key, byte[] value);
    String set(String key, String value);
    byte[] set(byte[] key, byte[] value, int expire);
    String set(String key, String value, int expire);
    void del(byte[] key);
    void del(String key);

}

RedisManage的集群模式实现

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import java.util.*;

/**
 * @author lisw
 * @program ddp-project
 * @description Redis管理器 集群模式
 * @createDate 2022-11-01 17:19:29
 **/

@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "cluster",matchIfMissing = false)
@Slf4j
public class RedisManagerJedisCluster implements RedisManager{

    private int expire = 0;

    @Autowired(required = false)
    private JedisCluster jedisCluster;

    @Override
    public byte[] get(byte[] key) {
       return jedisCluster.get(key);
    }

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

    @Override
    public byte[] set(byte[] key, byte[] value) {
       jedisCluster.set(key,value);
       if(this.expire!=0){
           jedisCluster.expire(key,expire);
       }
      return value;
    }

    @Override
    public String set(String key, String value) {
        jedisCluster.set(key,value);
        if(this.expire!=0){
            jedisCluster.expire(key,expire);
        }
        return value;
    }

    @Override
    public byte[] set(byte[] key, byte[] value, int expire) {
        jedisCluster.set(key,value);
        if(expire!=0){
            jedisCluster.expire(key,expire);
        }
        return value;
    }

    @Override
    public String set(String key, String value, int expire) {
        jedisCluster.set(key,value);
        if(expire!=0){
            jedisCluster.expire(key,expire);
        }
        return value;
    }

    @Override
    public void del(byte[] key) {
        jedisCluster.del(key);
    }

    @Override
    public void del(String key) {
        jedisCluster.del(key);
    }
}

RedisManager的哨兵模式实现

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import java.util.*;

/**
 * @author lisw
 * @program ddp-project
 * @description Redis管理,哨兵模式实现
 * @createDate 2022-11-02 18:01:03
 **/

@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "sentinel",matchIfMissing = false)
@Slf4j
public class RedisManagerJedisSentinel implements RedisManager{
    private int expire = 0;

    @Autowired(required = false)
    private JedisSentinelPool jedisPool;

    @Override
    public byte[] get(byte[] key) {
        byte[] value = null;
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            value = jedis.get(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            jedis.close();
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String get(String key) {
        String value = null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public byte[] set(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public byte[] set(byte[] key, byte[] value, int expire) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String set(String key, String value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public void del(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
    }
    @Override
    public void del(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

}

RedisManager的单机模式实现

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import java.util.*;

/**
 * @author lisw
 * @program ddp-project
 * @description Redis管理,单机模式实现
 * @createDate 2022-11-01 17:09:01
 **/

@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "standalone",matchIfMissing = true)
@Slf4j
public class RedisManagerJedisStandalone implements RedisManager {

    private int expire = 0;

    @Autowired(required = false)
    private JedisPool jedisPool;
    
    @Override
    public byte[] get(byte[] key) {
        byte[] value = null;
        Jedis jedis =null;
        try {
            jedis = jedisPool.getResource();
            value = jedis.get(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            jedis.close();
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String get(String key) {
        String value = null;
        Jedis jedis = jedisPool.getResource();
        try {
            value = jedis.get(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public byte[] set(byte[] key, byte[] value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (this.expire != 0) {
                jedis.expire(key, this.expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public byte[] set(byte[] key, byte[] value, int expire) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public String set(String key, String value, int expire) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.set(key, value);
            if (expire != 0) {
                jedis.expire(key, expire);
            }
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
        return value;
    }
    @Override
    public void del(byte[] key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } catch (Exception e) {
            //释放redis对象
            jedisPool.returnBrokenResource(jedis);
            e.printStackTrace();
        } finally {
            //返还到连接池
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        }
    }
    @Override
    public void del(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

}

业务代码注入RedisManager即可使用对应实现

@Autowired
private RedisManager redisManager;

3切换配置说明

只需修改配置文件中的redis.model配置值就可以切换redis三种模式,值分别是:standalone(单机),cluster(集群),sentinel(哨兵)



关注我们,发现小秘密




回复【30G】,获取30G容量的Java全方位视频课程资料

回复【面试冲刺】,获取5G容量的Java全方位面试资料

回复【java规范】,获取阿里巴巴Java开发规范手册

回复【插件】,获得开发效率提高10倍的Chrome插件

回复【算法】,获得Java全方位全体系算法视频可能




原文始发于微信公众号(走进Java):从单机到集群,SpringBoot集成Redis让你的架构更强大

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/107969.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!