redis学习开发(二)- 单机/集群/主从/哨兵

一,四大模式简单实现

1,单机模式
    服务器层:一个可连接的redis服务器即可
    java层:
        配置项:
            # spring.redis.host=10.215.208.65
            #数据库索引
            # spring.redis.database=0
            #spring.redis.port=6379
java代码:

RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host,port);
        redisStandaloneConfiguration.setDatabase(database);
        if(!StringUtils.isEmpty(password)){
            redisStandaloneConfiguration.setPassword(password);
        }
        //根据配置和客户端配置创建连接工厂
        return new LettuceConnectionFactory(redisStandaloneConfiguration,lettuceClientConfiguration());


2,集群模式
    服务器层:多个可连接的redis服务器
    java层:
        配置项:
            # 最大的连接重试次数
            spring.redis.cluster.max-redirects=2
            # 集群 192.168.74.135:26379,192.168.74.136:26379
            spring.redis.sentinel.nodes=10.215.208.104:7000,10.215.208.104:7001,10.215.208.104:7002
  java代码:
 

source.put("spring.redis.cluster.nodes", nodes);
            source.put("spring.redis.cluster.max-redirects", maxRedirects);
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
            if(!StringUtils.isEmpty(password)){
                redisClusterConfiguration.setPassword(password);
            }
            //根据配置和客户端配置创建连接
            lettuceConnectionFactory = new
                    LettuceConnectionFactory(redisClusterConfiguration,lettuceClientConfiguration());

3,主从模式
    服务器层:

         一个master服务器,设置Redis服务只监听本机,并将masterport设置为本机的端口号
         其他slave服务器,可以是多个,设置Redis服务只监听本机,并将masterip和masterport分别设置为第一台服务器上的ip地址和端口号
    

$redis-cli slaveof  


    java层:
    

String masterHost = "";
        String slaves = ",";
        RedisStaticMasterReplicaConfiguration configuration = new RedisStaticMasterReplicaConfiguration(
                masterHost, this.port);
        if(StringUtils.isNotBlank(slaves)){
            String[] slaveHosts=slaves.split(",");
            for (int i=0;i<slaveHosts.length;i++){
                configuration.addNode(slaveHosts[i], this.port);
            }
        }
        return new LettuceConnectionFactory(configuration, lettuceClientConfiguration());

方式二,只配置master节点信息,有服务器配置redis,自动获得slave节点

@Configuration
class WriteToMasterReadFromReplicaConfiguration {

  @Bean
  public LettuceConnectionFactory redisConnectionFactory() {

    LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
      .readFrom(ReadFrom.SLAVE_PREFERRED)
      .build();

    RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration("server", 6379);

    return new LettuceConnectionFactory(serverConfig, clientConfig);
  }
}


    

4,哨兵模式

RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(
                redisProperties.getSentinel().getMaster(), new HashSet<>(redisProperties.getSentinel().getNodes())
        );
//        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
//                .master("mymaster")
//                // 哨兵地址
//                .sentinel("192.168.80.130", 26379)
//                .sentinel("192.168.80.130", 26380)
//                .sentinel("192.168.80.130", 26381);
        // 配置读写分离
        LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
                // 读写分离,这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择
                // MASTER   仅读取主节点
                // MASTER_PREFERRED   优先读取主节点,如果主节点不可用,则读取从节点
                // REPLICA_PREFERRED   优先读取从节点,如果从节点不可用,则读取主节点
                // REPLICA   仅读取从节点
                // NEAREST   从最近节点读取
                // ANY   从任意一个从节点读取
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(redisSentinelConfiguration, lettuceClientConfiguration);

java代码:redis其他配置

自定义slave读取规则

LettuceClientConfiguration clientConfig =
                LettucePoolingClientConfiguration.builder().readFrom(new ReadFrom() {
                    @Override
                    public List<RedisNodeDescription> select(Nodes nodes) {
                        List<RedisNodeDescription> allNodes = nodes.getNodes();
                        int ind = Math.abs(index.incrementAndGet() % allNodes.size());
                        RedisNodeDescription selected = allNodes.get(ind);
                        logger.info("Selected random node {} with uri {}", ind, selected.getUri());
                        List<RedisNodeDescription> remaining = IntStream.range(0, allNodes.size())
                                .filter(i -> i != ind)
                                .mapToObj(allNodes::get).collect(Collectors.toList());
                        return Stream.concat(
                                Stream.of(selected),
                                remaining.stream()
                        ).collect(Collectors.toList());
                    }
                }).commandTimeout(Duration.ofMillis(timeout))
                        .poolConfig(genericObjectPoolConfig).build();
        return new LettuceConnectionFactory(configuration, clientConfig);

连接配置,客户端配置

private LettuceClientConfiguration lettuceClientConfiguration() {
        //连接池配置
        GenericObjectPoolConfig genericObjectPoolConfig =  new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(maxActive);
        genericObjectPoolConfig.setMaxWaitMillis(maxWait);
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMinIdle(minIdle);

        //redis客户端配置
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder
                builder =  LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofSeconds(timeOut));
        builder.poolConfig(genericObjectPoolConfig);
        return builder.build();
    }

CacheManager

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认超时时间:30分钟
        redisCacheConfiguration.entryTtl(Duration.ofMinutes(30L));
        // 如果是空值,不缓存
        redisCacheConfiguration.disableCachingNullValues();
        // 设置key序列化器
        redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        // 设置value序列化器
        redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        RedisCacheManager.RedisCacheManagerBuilder build = RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory));
        RedisCacheManager cacheManager = build.cacheDefaults(redisCacheConfiguration).build();

        return cacheManager;
    }

四大模式对比:

主从:

优点: 主从结构具有读写分离,提高效率、数据备份,提供多个副本等优点。
不足: 最大的不足就是主从模式不具备自动容错和恢复功能,主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预。
普通的主从模式,当主数据库崩溃时,需要手动切换从数据库成为主数据库:
在从数据库中使用SLAVE NO ONE命令将从数据库提升成主数据继续服务。
启动之前崩溃的主数据库,然后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可同步数据。

哨兵:

核心还是主从模式,不同的是解决主机宕机后的,从slave中自动选择一个slave作为master的机制。

优点
哨兵模式是基于主从模式的,解决可主从模式中master故障不可以自动切换故障的问题。

不足-问题
是一种中心化的集群实现方案:始终只有一个Redis主机来接收和处理写请求,写操作受单机瓶颈影响。
集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响master的性能。
Redis主机宕机后,哨兵模式正在投票选举的情况之外,因为投票选举结束之前,谁也不知道主机和从机是谁,此时Redis也会开启保护机制,禁止写操作,直到选举出了新的Redis主机。

集群:

优点:

1,解决主从模式的每个节点存储的数据都是全量的数据,数据量过大。大家内容相同存在的浪费内存空间,且数据量过大也会牺牲同步性能。一个master带来的写操作性能瓶颈。

2,客户端sharding技术使用hash一致性算法分片的好处是所有的逻辑都是可控的,不依赖于第三方分布式中间件。服务端的Redis实例彼此独立,相互无关联,每个Redis实例像单服务器一样运行,非常容易线性扩展,系统的灵活性很强。开发人员清楚怎么实现分片、路由的规则,不用担心踩坑。

3,代理分片:中间件作为查找redis服务器的逻辑中间方。Twemproxy,Codis

Redis Cluster

服务器Sharding技术(分片和路由都是在服务端实现),采用多主多从,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是相互平行的。Redis Cluster集群采用了P2P的模式,完全去中心化。

虚拟哈希槽分区而非一致性hash算法,预先分配一些卡槽

参考:

Redis的四种模式:单机、主从、哨兵、集群简介

    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值