记一次线上环境 redis偶尔连接超时报错 解决
贴出本地控制台日志
说实话,很痛苦,跟进很久了,一直认为的jvm程序所使用的配置的连接池框架问题
因为程序为 springboot 2 spring 5 ;那么默认连接池为 lettuce
起初认为是原有的jedis 转换到 lettuce存在的各种bug问题,可能没配置好;
网上也寻找了相关的文章,发现大多数人的解决方案,就是在springboot的自动注入的配置文件中,配置不对,说spring.redis.timeout配置为0,导致不允许超时,那么就会抛出该异常;
所以只需要将其改为合理的范围即可,比如10s,那么本人也试过了,发现不顶用。
此处贴出配置文件(注:rediss不是写错,是故意不使用自动配置注入的):
然后就是连接池的问题了,本人尝试使用自定义注入连接池使用,不使用自动注入(此处怀疑是自动注入问题)结果也发现不行,
那么再怀疑是配置项不对,例如连接池的最小空闲链接、最大空闲链接数不合理,那么我本地在尝试调整的时候,本地模拟运行一段时间,发现还是会时不时抛出超时问题;
此处贴出本人的自定义注入配置文件(一个lettuce连接工厂)
/**
* @description: LettuceConfiguration
* @author: Wang Ji
* @create: 2021/01/22 21:24
*/
@Slf4j
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class LettuceConfig {
@Value("${spring.rediss.database}")
private int database = 0;
@Value("${spring.rediss.host}")
private String host;
@Value("${spring.rediss.port}")
private int port;
@Value("${spring.rediss.password}")
private String password = null;
@Value("${spring.rediss.timeout}")
private int timeout = 5000;
@Value("${spring.rediss.lettuce.pool.max-idle}")
private int maxIdle = 8;
@Value("${spring.rediss.lettuce.pool.min-idle}")
private int minIdle = 0;
@Value("${spring.rediss.lettuce.pool.max-active}")
private int maxActive = 8;
@Value("${spring.rediss.lettuce.pool.max-wait}")
private long maxWait;
/**
* lettuce 连接工厂
*
* @param genericObjectPoolConfig
* @return
*/
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory(@Qualifier("genericObjectPoolConfig") GenericObjectPoolConfig<?> genericObjectPoolConfig) {
// 单机版配置
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(database);
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
// 集群版配置
// RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
// String[] serverArray = clusterNodes.split(",");
// Set<RedisNode> nodes = new HashSet<RedisNode>();
// for (String ipPort : serverArray) {
// String[] ipAndPort = ipPort.split(":");
// nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
// }
// redisClusterConfiguration.setPassword(RedisPassword.of(password));
// redisClusterConfiguration.setClusterNodes(nodes);
// redisClusterConfiguration.setMaxRedirects(maxRedirects);
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(timeout))
.poolConfig(genericObjectPoolConfig)
.build();
RedisConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
if (ConnectionUtils.isLettuce(redisConnectionFactory)) {
log.warn("// RedisConnectionFactory is Lettuce");
} else if (ConnectionUtils.isJedis(redisConnectionFactory)) {
log.warn("// RedisConnectionFactory is Jedis");
}
return redisConnectionFactory;
}
/**
* GenericObjectPoolConfig 连接池配置
*
* @return
*/
@Bean("genericObjectPoolConfig")
public GenericObjectPoolConfig<?> genericObjectPoolConfig() {
GenericObjectPoolConfig<?> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
genericObjectPoolConfig.setMaxIdle(maxIdle);
genericObjectPoolConfig.setMinIdle(minIdle);
genericObjectPoolConfig.setMaxTotal(maxActive);
genericObjectPoolConfig.setMaxWaitMillis(maxWait);
return genericObjectPoolConfig;
}
}
然后在一篇文章中也看到,可能存在一个这样的问题,redis在长时间空闲状态,会自动重启?
本人没验证过,猜测可能是某种垃圾回收策略,内存碎片化整理。有兴趣的同学可以去研究一下。
那么本人再次怀疑,可能就是redis本身的config配置不对,因为笔者对于redis的自己的服务器上的部署都是全部自定义过的,也就是说,很多配置,都对其进行了适合自己项目的配置,比如回收策略,数据库数量,最大连接数量,等等等,那么按常理来说,redis的本身服务上也会有一个超时配置。
一找,果不其然有个超时配置;
但是这个配置是:客户端闲置N秒后关闭连接(0禁用)
按道理来说,0应该是禁用了主动关闭连接的配置
这里,我将尝试改为300s 后 超时
那么并且修改配置文件中的 多少秒检测一次空闲状态
修改这样,然后我后面再尝试运行一段时间,看看结果怎样
注意,此调试方案建议不要直接用于生产环境
因为每个公司服务的策略都不一样,毕竟脱离业务的架构方案都是耍流氓,建议可以以拓展知识面的方式阅读本文章。