likes
comments
collection
share

通过策略模式实现Redis几种集群模式

作者站长头像
站长
· 阅读数 15

前言

Redis常用的几种部署模式分别为Standalone(单节点部署方式)、Sentinel (哨兵部署方式)、Cluster(集群方式)、Masterslave(主从部署方式),我们通过Java代码去连接redis的服务端实现不同的部署模式,当然也需要部署在服务端的Redis支持这种部署方式,我们可以根据策略模式来实现Redis不同的连接方式。

Redis连接策略枚举类

首先需要去定义Redis连接的枚举类,这里会将redis的几种连接方式定义成枚举;

public enum RedisConnectionTypeEnum {

    STANDALONE("standalone", "单节点部署方式"),
    SENTINEL("sentinel", "哨兵部署方式"),
    CLUSTER("cluster", "集群方式"),
    MASTERSLAVE("masterslave", "主从部署方式");

    private final String connectionType;
    private final String connectionDesc;

    private RedisConnectionTypeEnum(String connectionType, String connectionDesc) {
        this.connectionType = connectionType;
        this.connectionDesc = connectionDesc;
    }

    public String getConnectionType() {
        return connectionType;
    }

    public String getConnectionDesc() {
        return connectionDesc;
    }
}

Redis连接属性配置类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedissonProperties {

    private String nodeAddresses;
    /**
     * 连接类型,支持standalone-单机节点,sentinel-哨兵,cluster-集群,masterslave-主从
     */
    private String serverType;
    /**
     * redis 连接密码
     */
    private String password;
    /**
     * 如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,
     * 那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。默认10000
     */
    private int idleConnectionTimeout;
    /**
     * 建立连接等待超时时间
     */
    private int connectTimeout;
    /**
     * 等待节点回复命令的时间。该时间从命令发送成功时开始计时。默认3000
     */
    private int timeOut;
    /***
     * 失败重试次数
     */
    private int retryAttempts;
    /**
     * 选取那个数据库
     */
    private int database;

}

}

主要是一些Redis连接配置的常用属性,定义成Properties配置文件类,可以通过读取Nacos配置文件获取对应的属性

Redis Config创建的接口方法

public interface RedissonConfigService {

    Config createRedissonConfig(RedissonProperties redissonProperties);
}

提供创建config连接的方法,可扩展不同连接模式可以实现RedissonConfigService接口,实现不同的连接模式,就是前面所说的策略模式,通过不同的策略类来定义不一样的连接模式;

ClusterConfigImpl实现类

@Slf4j
public class ClusterConfigImpl implements RedissonConfigService {

    @Override
    public Config createRedissonConfig(RedissonProperties redissonProperties) {
        Config config =new Config();
        try{
            String nodeAddresses = redissonProperties.getNodeAddresses();
            String password = redissonProperties.getPassword();
            String[] split = nodeAddresses.split(",");

            //设置cluster节点的服务IP和端口
            for (int i = 0; i < split.length; i++) {
                config.useClusterServers()
                        .addNodeAddress("redis://" + split[i]);
                if (StringUtils.hasText(password)) {
                    config.useClusterServers().setPassword(password);
                }
            }
            log.info("初始化[集群部署]方式Config,redisAddress:" + split);
        }catch (Exception e){
            log.error("集群部署 Redisson init error", e);
        }
        return config;
    }
}

Cluster方式至少6个节点,3主3从,从节点用于主节点宕机后的高可用 还有几种连接模式的实现类,这里就进行省略了,只需要实现RedissonConfigService接口,重写createRedissonConfig方法即可,实际业务场景Cluster模式使用的是比较多的。

Redis核心配置

/**
 * @Description: Redisson核心配置,用于提供初始化的redisson实例
 *
 */
@Slf4j
public class RedissonManager {


private Config config = new Config();

private RedissonClient redisson = null;

public RedissonManager() {
}

public RedissonManager(RedissonProperties redissonProperties) {
    try {
        //通过不同部署方式获得不同config实体
        config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
        redisson =Redisson.create(config);
    } catch (Exception e) {
        log.error("Redisson init error", e);
        throw new IllegalArgumentException("please input correct configurations," +
                "connectionType must in standalone/sentinel/cluster/masterSlave");
    }
}

public RedissonClient getRedisson() {
    return  redisson;
}


    /**
     * Redisson连接方式配置工厂
     * 双重检查锁
     */
    static class RedissonConfigFactory {

        private RedissonConfigFactory() {
        }

        private static volatile RedissonConfigFactory factory = null;

        public static RedissonConfigFactory getInstance() {
            if (factory == null) {
                synchronized (Object.class) {
                    if (factory == null) {
                        factory = new RedissonConfigFactory();
                    }
                }
            }
            return factory;
        }


        /**
         * 根据连接类型获取对应连接方式的配置,基于策略模式
         *
         * @param redissonProperties redis连接信息
         * @return Config
         */
        Config createConfig(RedissonProperties redissonProperties) {
            Preconditions.checkNotNull(redissonProperties);
            Preconditions.checkNotNull(redissonProperties.getAddress(), "redisson.lock.server.address cannot be NULL!");
            Preconditions.checkNotNull(redissonProperties.getServerType(), "redisson.lock.server.password cannot be NULL");
            Preconditions.checkNotNull(redissonProperties.getDatabase(), "redisson.lock.server.database cannot be NULL");
            String connectionType = redissonProperties.getServerType();
            //声明配置上下文
            RedissonConfigService redissonConfigService = null;
            if (connectionType.equals(RedisConnectionTypeEnum.STANDALONE.getConnectionType())) {
                redissonConfigService = new StandaloneConfigImpl();
            } else if (connectionType.equals(RedisConnectionTypeEnum.SENTINEL.getConnectionType())) {
                redissonConfigService = new SentineConfigImpl();
            } else if (connectionType.equals(RedisConnectionTypeEnum.CLUSTER.getConnectionType())) {
                redissonConfigService = new ClusterConfigImpl();
            } else if (connectionType.equals(RedisConnectionTypeEnum.MASTERSLAVE.getConnectionType())) {
                redissonConfigService = new MasterslaveConfigImpl();
            } else {
                throw new IllegalArgumentException("创建Redisson连接Config失败!当前连接方式:" + connectionType);
            }
            return redissonConfigService.createRedissonConfig(redissonProperties);
        }
    }

}

这里我们将config实体换成Redisson包下的config,因为我们要构建Redisson 实例,毕竟Redisson相对来说更好用一些; RedissonManager的构造方法通过静态内部连接工厂RedissonConfigFactory ,来实现不同部署方式获取不同的config实体, 当然工厂类里也是使用懒汉单例的duoble check 模式来进行单例工厂的初始化,防止RedissonConfigFactory工厂的频繁创建,从而带来redisson连接频繁创建,带来不必要的性能影响;

总结

至此Redis的集群连接模式,通过Java来实现连接的部分已经实现完毕,剩下的需要在本地构建Redis Cluster环境,通过我们实现的客户端进行连接,完成集群模式的全部搭建,下一篇会写本地搭建Redis Cluster集群。