SpringBoot整合redis, Redi@R_502_6063@plate默认使用Lettuce客户端超时问题
问题
在开发的时候,使用到Lettuce连接redis,一段时间后不操作,再去操作redis,会报连接超时错误,在其重连后又可使用。
原因是:Lettuce 自适应拓扑刷新(Adaptive updates)与定时拓扑刷新(Periodic updates) 是默认关闭的导致问题的出现
解决的方案
方法一:
1、重写连接工厂实例,更改其LettuceClientConfiguration 为开启拓扑更新
@Configuration
public class RedisConfig {
@Autowired
private RedisProperties redisProperties;
//这是固定的模板
//自己定义了一个Redi@R_502_6063@plate
@Bean
@SuppressWarnings("all")
public Redi@R_502_6063@plate<String, Object> redi@R_502_6063@plate(@Qualifier("lettuceConnectionFactoryUvPv") RedisConnectionFactory factory) {
Redi@R_502_6063@plate<String, Object> template = new Redi@R_502_6063@plate<>();
template.setConnectionFactory(factory);
//Json序列化配置
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(om.getpolymorphicTypeValidator());
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//解决序列化问题
om.configure(DeserializationFeature.FAIL_ON_UNKNowN_PROPERTIES, false);
jackson2JsonRedisSerializer.setobjectMapper(om);
//String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* 为Redi@R_502_6063@plate配置Redis连接工厂实现
* LettuceConnectionFactory实现了RedisConnectionFactory接口
* UVPV用Redis
*
* @return 返回LettuceConnectionFactory
*/
@Bean(destroyMethod = "destroy")
//这里要注意的是,在构建LettuceConnectionFactory 时,如果不使用内置的destroyMethod,可能会导致Redis连接早于其它Bean被销毁
public LettuceConnectionFactory lettuceConnectionFactoryUvPv() throws Exception {
// List<String> clusterNodes = redisProperties.getCluster().getNodes();
// Set<RedisNode> nodes = new HashSet<>();
// 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());
//我使用的是单机redis,集群使用上面注释的代码
Set<RedisNode> nodes = new HashSet<>();
nodes.add(new RedisNode(redisProperties.getHost(), redisProperties.getPort()));
RedisStandaloneConfiguration redisStandaloneConfiguration=new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisProperties.getHost());
redisStandaloneConfiguration.setPassword(redisProperties.getpassword());
redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
redisStandaloneConfiguration.setPort(redisProperties.getPort());
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(redisStandaloneConfiguration, getLettuceClientConfiguration(poolConfig));
}
/**
* 配置LettuceClientConfiguration 包括线程池配置和安全项配置
*
* @param genericObjectPoolConfig common-pool2线程池
* @return lettuceClientConfiguration
*/
private LettuceClientConfiguration getLettuceClientConfiguration(GenericObjectPoolConfig genericObjectPoolConfig) {
/*
ClusterTopologyRefreshOptions配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,Redis集群变更时将会导致连接异常!
*/
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
//开启自适应刷新
//.enableAdaptiveRefreshTrigger(ClusterTopologyRefreshOptions.RefreshTrigger.MOVED_REDIRECT, ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS)
//开启所有自适应刷新,MOVED,ASK,PERSISTENT都会触发
.enableAllAdaptiveRefreshTriggers()
// 自适应刷新超时时间(默认30秒)
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(25)) //默认关闭开启后时间为30秒
// 开周期刷新
.enablePeriodicRefresh(Duration.ofSeconds(20)) // 默认关闭开启后时间为60秒 ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60 .enablePeriodicRefresh(Duration.ofSeconds(2)) = .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
.build();
return LettucePoolingClientConfiguration.builder()
.poolConfig(genericObjectPoolConfig)
.clientOptions(ClusterClientOptions.builder().topologyRefreshOptions(topologyRefreshOptions).build())
//将appID传入连接,方便Redis监控中查看
//.clientName(appName + "_lettuce")
.build();
}
}
2、SpringBoot2.3.x后,可使用配置文件中开启lettuce的拓扑刷新
lettuce:
pool:
max-active: 20
max-wait: -1ms
max-idle: 10
min-idle: 2
cluster:
refresh:
adaptive: true
#20秒自动刷新一次
period: 20
方法二:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
spring:
redis:
password: xxx
host: 172.16.0.x
port: 6579
timeout: 5000
jedis:
pool:
#最大连接数据库连接数,设 0 为没有限制
max-active: 8
#最大等待连接中的数量,设 0 为没有限制
max-idle: 8
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
max-wait: -1ms
#最小等待连接中的数量,设 0 为没有限制
min-idle: 0
#lettuce:
#pool:
#max-active: ${redis.config.maxTotal:1024}
#max-idle: ${redis.config.maxIdle:50}
#min-idle: ${redis.config.minIdle:1}
#max-wait: ${redis.config.maxWaitMillis:5000}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。