上个月线上生产环境有几个接口出现异常响应,查看生产日志后发现,如下谬误
线上 Redis 客户端应用的是 SpringBoot
默认的 Lettuce
客户端,并且没有指定连接池,connection reset by peer
这个谬误是以后客户端连贯在不知情的状况下被服务端断开后产生,也就是说以后客户端 Redis 连贯曾经在服务端断开了,然而客户端并不知道,当申请进来时,Lettuce
持续应用以后 Redis 连贯申请数据时,就会提醒connection reset by peer
。
个别状况下服务端断开连接都会发送 FIN
包告诉客户端,然而当我在用 tcpdump
监控服务端 tcp 传输后,发现 Redis 服务端 tcp 连贯在无流动一段时间,比方 10 分钟后会收到来自客户端的 RST
包,然而我的客户端也在应用 wireshark 抓包中,并没有发送给服务端 RST
包,这就很奇怪了,猜想这里是可能是服务器对 tcp 连贯的限度导致,对长时间无流动的 tcp 连贯强制断开解决。所以这里线上环境 Redis 连贯偶然产生 connection reset by peer
谬误是被我复现进去了。
既然这里晓得是 Redis 连贯长时间无流动后被断开导致的 bug,那怎么解决?
博主一开始认为重试能够解决,然而发现事件没有设想的简略。上代码
// 查问 Redis
public <T> T getCacheObject(final String key) {
try {ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
} catch (Exception e) {log.error(e.getMessage(), e);
return retryGetCacheObject(key, 3);
}
}
// 重试查问 Redis
public <T> T retryGetCacheObject(final String key, int retryCount) {
try {log.info("retryGetCacheObject, key:{}, retryCount:{}", key, retryCount);
if (retryCount <= 0) {return null;}
Thread.sleep(200L);
retryCount--;
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
} catch (Exception e) {log.error(e.getMessage(), e);
return retryGetCacheObject(key, retryCount);
}
}
下面代码的意思是第一次查问 Redis 产生异样后,每隔 200 毫秒在查 3 次。当理论运行时,发现这里会提醒三次 connection reset by peer
谬误,始终没有取到新的 Redis 连贯。
到这里这个问题的我的解决思路其实就是怎么在 Redis 连贯产生异样后,怎么创立一条新的连贯进行代替。
不多说间接上代码:
// Lettuce 连贯工厂
@Autowired
private LettuceConnectionFactory lettuceConnectionFactory;
/**
* 取得缓存的根本对象。*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
try {ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
} catch (Exception e) {log.error(e.getMessage(), e);
return retryGetCacheObject(key, 1);
}
}
public <T> T retryGetCacheObject(final String key, int retryCount) {
try {log.info("retryGetCacheObject, key:{}, retryCount:{}", key, retryCount);
if (retryCount <= 0) {return null;}
lettuceConnectionFactory.resetConnection();
Thread.sleep(200L);
retryCount--;
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
} catch (Exception e) {log.error(e.getMessage(), e);
return retryGetCacheObject(key, retryCount);
}
}
在用以后 Redis 连贯获取数据产生异样超过 timeout
距离后,抛出异样,进入重试办法,应用 lettuceConnectionFactory.resetConnection()
办法进行连贯重置,创立一条新的连贯后,持续获取数据,从而失常响应客户端。lettuceConnectionFactory
对象是对 Lettuce
无池化连贯的工厂实现,提供了 ` lettuceConnectionFactory.getConnection();
lettuceConnectionFactory.initConnection();
lettuceConnectionFactory.resetConnection();` 等获取、初始化、重置连贯的办法
配合 springboot
配置 timeout
将获取数据的超时工夫设置为 2 秒,从而将接口申请耗时也管制在 2 秒左右
redis:
xx: xx
timeout: 2000
到此生产环境这里 SpringBoot
我的项目下 Lettuce
客户端无池化连贯偶然断开的 bug 算是解决了
最初贴一下实战我的项目地址 newbeemall,newbee-mall 商城的 mybatis plus 版本 实现了优惠卷支付, 支付宝沙箱领取, 后盾增加搜寻,RedisSearch 分词检索