Spring boot2.x与redis Lettuce集成操作redis集群case

柔情痞子 提交于 2020-01-08 18:44:10

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

Spring boot2.x与redis Lettuce集成操作redis集群case

场景

redis cluster集群有一台机崩了之后,后台服务的redis会一直报错,无法连接到redis集群。通过命令查看redis集群,发现redis cluster集群是正常的,备用的slave机器已经升级为master。

猜想与验证

初步猜测是Spring-redis的连接池框架在redis的其中一台master机器崩了之后,并没有刷新连接池的连接,仍然连接的是挂掉的那台redis服务器. 通过寻找资料在Spring boot2.x改为默认使用Lettuce框架与redis 连接在Lettuce官文档中找到了关RedisCluster的相关信息 《Refreshing the cluster topologyview》文中大概意思是自适应拓扑刷新(Adaptive updates)与定时拓扑刷新(Periodicupdates) 是默认关闭的,可以通过代码打开。

验证

  • 官方给出代码示例如下:

      RedisClusterClient clusterClient =
      RedisClusterClient.create(RedisURI.create("localhost", 6379));
    
      ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                                      .enablePeriodicRefresh(10, TimeUnit.MINUTES)
                                      .build();
    
      clusterClient.setOptions(ClusterClientOptions.builder()
                                      .topologyRefreshOptions(topologyRefreshOptions)
                                      .build());
      ...
    
      clusterClient.shutdown();
    
    
      RedisURI node1 = RedisURI.create("node1", 6379);
      RedisURI node2 = RedisURI.create("node2", 6379);
    
      RedisClusterClient clusterClient = RedisClusterClient.create(Arrays.asList(node1, node2));
    
      ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                                      .enableAdaptiveRefreshTrigger(RefreshTrigger.MOVED_REDIRECT, RefreshTrigger.PERSISTENT_RECONNECTS)
                                      .adaptiveRefreshTriggersTimeout(30, TimeUnit.SECONDS)
                                      .build();
    
      clusterClient.setOptions(ClusterClientOptions.builder()
                                      .topologyRefreshOptions(topologyRefreshOptions)
                                      .build());
      ...
    
      clusterClient.shutdown();
    
  • 修改在Spring boot2.x中配置连接redis cluster客户端代码如下:

      @Configuration
      public class LettuceRedisConfig {
    
          @Autowired
          private RedisProperties redisProperties;
    
          [@Bean](https://my.oschina.net/bean)
          public RedisTemplate redisTemplate(@Qualifier("lettuceConnectionFactoryUvPv") RedisConnectionFactory lettuceConnectionFactoryUvPv) {
              RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
              template.setConnectionFactory(lettuceConnectionFactoryUvPv);
              Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
                      new Jackson2JsonRedisSerializer(Object.class);
              ObjectMapper om = new ObjectMapper();
              om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
              jackson2JsonRedisSerializer.setObjectMapper(om);
              StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
              template.setKeySerializer(stringRedisSerializer);
              template.setHashKeySerializer(stringRedisSerializer);
              template.setValueSerializer(jackson2JsonRedisSerializer);
              template.setHashValueSerializer(jackson2JsonRedisSerializer);
              template.afterPropertiesSet();
              return template;
          }
    
    
          @Bean(destroyMethod = "destroy")
          public LettuceConnectionFactory lettuceConnectionFactoryUvPv(){
    
              List<String> clusterNodes = redisProperties.getCluster().getNodes();
              Set<RedisNode> nodes = new HashSet<RedisNode>();
              clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(),
                      Integer.parseInt(address.split(":")[1]))));
              RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
              clusterConfiguration.setClusterNodes(nodes);
              clusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
              clusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
    
              GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
              poolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
              poolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
              poolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
    
              return new LettuceConnectionFactory(clusterConfiguration,
                      getLettuceClientConfiguration(poolConfig));
          }
    
          private LettuceClientConfiguration getLettuceClientConfiguration(GenericObjectPoolConfig genericObjectPoolConfig) {
              ClusterTopologyRefreshOptions topologyRefreshOptions =
                      ClusterTopologyRefreshOptions.builder()
                      .enableAllAdaptiveRefreshTriggers()
                      .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(25)) 
                      .enablePeriodicRefresh(Duration.ofSeconds(20))  
                      .build();
              return LettucePoolingClientConfiguration.builder()
                      .poolConfig(genericObjectPoolConfig)
                      .clientOptions(ClusterClientOptions.builder().topologyRefreshOptions(topologyRefreshOptions).build())
                      .build();
          }
      }
    

在上述代码中需要设置自动刷新让其连接池连接新的master节点,方可避免问题不需要再去换成jedis,有点人可能会说直接替换掉lettuce采用jedis这种方式也行就是效率会有降低。 还是推荐使用lettuce官方也是推荐使用它。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!