【推荐】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官方也是推荐使用它。
来源:oschina
链接:https://my.oschina.net/VILLE/blog/3154994