redis: jedis连接超时(需要手动注入连接超时检测的配置)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: redis: jedis连接超时(需要手动注入连接超时检测的配置)

相关版本说明

服务端:
redis_version: 6.2.8

客户端:
springBoot: 2.7.7
jedis: 3.8.0

问题

偶发redis连接超时,刷新就又好了,服务日志错误信息如下:

JedisConnectionException: Unexpected end of stream.

原因

服务端连接已超时,但是客户端不知道,去使用时就会报错;

排查

redis服务端配置查看:

# 直接查看配置文件(默认为0,单位:秒, 0表示不设置超时时间):
[root@vm bin]# cat ./redis.conf | grep timeout
timeout 600

# 登录客户端查看当前配置(单位:秒)
127.0.0.1:6379> config get timeout
1) "timeout"
2) "600"

发现服务端设置了连接超时时间为10分钟。

redis默认是不设置超时时间的,也就是 timeout 0
可能是考虑到这样就有可能导致连接回收不及时,最后连接数不够用;
所以项目上设置了10分钟超时,但是没考虑到客户端,所以就出现上面这个偶发的现象了;

解决方案

方案1、redis保持默认配置,不设置超时时间,然后最大连接数设置大一些;
方案2、redis客户端配置一下连接是否超时的检测;

方案1比较简单,直接修改配置就行,但是项目上既然要配置超时时间,那只能看看方案2了。

方案二具体配置

需要手动注入,新增配置类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.data.redis.JedisClientConfigurationBuilderCustomizer;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.util.ClassUtils;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;

@Configuration
public class JedisPoolConfiguration implements JedisClientConfigurationBuilderCustomizer {
   
   

    @Autowired
    private RedisProperties properties;

    private static final boolean COMMONS_POOL2_AVAILABLE = ClassUtils.isPresent("org.apache.commons.pool2.ObjectPool",
            JedisPoolConfiguration.class.getClassLoader());

    /**
     * 连接的最小空闲时间,达到此值后空闲连接将被移除, 默认:30分钟
     */
    @Value(value = "${spring.redis.jedis.pool.minEvictableIdleTime:30M}")
    private Duration minEvictableIdleTime;
    /**
     * 做空闲连接检测时,每次的采样数,默认每次只检测3个
     */
    @Value(value = "${spring.redis.jedis.pool.numTestsPerEvictionRun:3}")
    private int numTestsPerEvictionRun;
    /**
     * 从连接池获取连接时是否先检测(ping),每次执行命令多执行一次ping, 默认:false
     */
    @Value(value = "${spring.redis.jedis.pool.testOnBorrow:false}")
    private boolean testOnBorrow;

    @Override
    public void customize(JedisClientConfiguration.JedisClientConfigurationBuilder clientConfigurationBuilder) {
   
   
        RedisProperties.Pool pool = properties.getJedis().getPool();
        if (isPoolEnabled(pool)) {
   
   
            applyPooling(pool, clientConfigurationBuilder);
        }
    }

    private void applyPooling(RedisProperties.Pool pool,
                              JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
   
   
        builder.usePooling().poolConfig(jedisPoolConfig(pool));
    }

    private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) {
   
   
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(pool.getMaxActive());
        config.setMaxIdle(pool.getMaxIdle());
        config.setMinIdle(pool.getMinIdle());
        if (pool.getTimeBetweenEvictionRuns() != null) {
   
   
            config.setTimeBetweenEvictionRuns(pool.getTimeBetweenEvictionRuns());
        }
        if (pool.getMaxWait() != null) {
   
   
            config.setMaxWait(pool.getMaxWait());
        }
        if (minEvictableIdleTime != null){
   
   
            config.setMinEvictableIdleTime(minEvictableIdleTime);
        }
        config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        config.setTestOnBorrow(testOnBorrow);
        return config;
    }


    protected boolean isPoolEnabled(RedisProperties.Pool pool) {
   
   
        Boolean enabled = pool.getEnabled();
        return (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE;
    }
}

配置文件增加如下配置

spring:
  redis:
    jedis:
      pool:
        # 从连接池获取连接时是否先检测(ping),每次执行命令多执行一次ping
        testOnBorrow: true
        # 多长时间检测一次(-1表示不进行定时检测)
        timeBetweenEvictionRuns: 30S
        # 连接的最小空闲时间,达到此值后空闲连接将被移除, 默认30分钟
        minEvictableIdleTime: 5M
        # 做空闲连接检测时,每次的采样数,默认每次只检测3个
        numTestsPerEvictionRun: 3
  • 其实只需要配置testOnBorrow=true就可以,但是如果发现失效连接,则又要去重新获取一个连接,可能会费时一点;
  • 所以还可以配置主动检测:定时去检测连接的配置,可以根据自己项目的实际超时时间,和连接数,在超时之前可以把所有连接都扫描检测到即可
    (这里是我个人的配置,仅供参考)

至此,问题已得到解决,但为什么不能直接通过配置文件自动注入呢?感兴趣的小伙伴可以继续看看以下内容:

说明

  • 因为spring-boot-autoconfigure中,不支持这三个配置:
    testOnBorrow
    minEvictableIdleTime
    numTestsPerEvictionRun
    
  • 详细可以查看源码:
    org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool
    在这里插入图片描述
    org.springframework.boot.autoconfigure.data.redis.JedisConnectionConfiguration#jedisPoolConfig
    在这里插入图片描述
  • 所以可以把源码复制出来,自己修改一下
    在这里插入图片描述
  • 该问题已经反馈给spring-boot:
    spring-projects/spring-boot/issues/33814
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
NoSQL Redis 数据库
Redis 连接
10月更文挑战第19天
37 0
|
7天前
|
NoSQL 应用服务中间件 API
Redis是如何建立连接和处理命令的
本文主要讲述 Redis 是如何监听客户端发出的set、get等命令的。
|
1月前
|
监控 NoSQL 网络协议
【Azure Redis】部署在AKS中的应用,连接Redis高频率出现timeout问题
查看Redis状态,没有任何异常,服务没有更新,Service Load, CPU, Memory, Connect等指标均正常。在排除Redis端问题后,转向了AKS中。 开始调查AKS的网络状态。最终发现每次Redis客户端出现超时问题时,几乎都对应了AKS NAT Gateway的更新事件,而Redis服务端没有任何异常。因此,超时问题很可能是由于NAT Gateway更新事件导致TCP连接被重置。
|
1月前
|
存储 SQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(1)作者——LJS[含MySQL的下载、安装、配置详解步骤及报错对应解决方法]
Mysql And Redis基础与进阶操作系列(1)之[MySQL的下载、安装、配置详解步骤及报错对应解决方法]
|
1月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
58 5
|
2月前
|
NoSQL 网络协议 算法
Redis 客户端连接
10月更文挑战第21天
45 1
|
2月前
|
存储 NoSQL Redis
Redis 配置
10月更文挑战第14天
37 1
|
2月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
2月前
|
存储 缓存 NoSQL
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
72 1
|
2月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
200 0