上个月线上生产环境有几个接口出现异常响应,查看生产日志后发现,如下谬误

线上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分词检索