生产环境Redis连接,长时间无响应被服务器断开问题

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Redis 版,经济版 1GB 1个月
简介: 生产环境Redis连接,长时间无响应被服务器断开问题

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

image.png

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



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4天前
|
安全 Unix Linux
服务器怎么连接?服务器远程连接图文教程
服务器操作系统可以实现对计算机硬件与软件的直接控制和管理协调,任何计算机的运行离不开操作系统,服务器也一样,服务器操作系统主要分为四大流派:Windows Server、Netware、Unix和Linux。 今天飞飞就给你们分享下常用的Windows、Linux、Unix三种系统的远程连接图文操作方法
10 0
服务器怎么连接?服务器远程连接图文教程
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
|
9天前
|
前端开发 NoSQL 数据库
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
|
10天前
|
弹性计算 NoSQL 网络安全
软件开发常见之云数据库Redis连接不上如何解决,修改配置后,需要重启下redis服务,配置才能生效呢,是重启,而不是重载配置,最后导致的问题是点击了的重启,配置修改了之后必须点击重启,而不是修改
软件开发常见之云数据库Redis连接不上如何解决,修改配置后,需要重启下redis服务,配置才能生效呢,是重启,而不是重载配置,最后导致的问题是点击了的重启,配置修改了之后必须点击重启,而不是修改
|
10天前
|
NoSQL JavaScript Redis
若依后端部署---若依部署,Redis在D盘的project的应用工具当中,在连接过程中,先用Xshell连接若依,RDM在应用工具里,同时host的主机也要写好
若依后端部署---若依部署,Redis在D盘的project的应用工具当中,在连接过程中,先用Xshell连接若依,RDM在应用工具里,同时host的主机也要写好
|
10天前
|
NoSQL Java 关系型数据库
软件开发常用之若依修改之添加数据库,添加redis,利用RDM连接宝塔
软件开发常用之若依修改之添加数据库,添加redis,利用RDM连接宝塔
|
10天前
|
数据安全/隐私保护
xshell通过堡垒机连接服务器和winscp 通过堡垒机传输文件
【7 月更文挑战第 3 天】xshell通过堡垒机连接服务器和winscp 通过堡垒机传输文件
|
10天前
|
Java Redis 数据安全/隐私保护
Redis14----Redis的java客户端-jedis的连接池,jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,最好用jedis连接池代替jedis,配置端口,密码
Redis14----Redis的java客户端-jedis的连接池,jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,最好用jedis连接池代替jedis,配置端口,密码
|
10天前
|
Java Redis 数据安全/隐私保护
Redis13的Java客户端-Jedis快速入门,建立连接的写法,ip地址,设置密码密码,选择库的写法
Redis13的Java客户端-Jedis快速入门,建立连接的写法,ip地址,设置密码密码,选择库的写法
Redis06-Redis常用的命令,模糊的搜索查询往往会对服务器产生很大的压力,MSET k1 v1 k2 v2 k3 v3 添加,DEL是删除的意思,EXISTS age 可以用来查询是否有存在1
Redis06-Redis常用的命令,模糊的搜索查询往往会对服务器产生很大的压力,MSET k1 v1 k2 v2 k3 v3 添加,DEL是删除的意思,EXISTS age 可以用来查询是否有存在1