• Java连接redis报错timed out问题解决


    现象

    • 之前写了一篇文章:Spring redis使用报错Read timed out排查解决,解决超时问题
    • 后面发现解决的不彻底,仍有报错
    • 详细查看了下源码,发现不同版本里,参数名不一样,之前的参数设置,并没有在新版本里生效

    报错一

    • 核心报错提示是这一句:JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    • 使用jedis连接时,连接超时SocketTimeout,即与Redis服务器的连接超时
    2023-03-29 10:54:38.186 ERROR 9136 --- [ntainer#7-0-C-1] c.n.r.service.IntersectionQueryService   : Exception in getIntersectionById() with cause = 'redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out' and exception = 'java.net.SocketTimeoutException: Read timed out; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out'
    
    org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketTimeoutException: Read timed out; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:65)
    	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:42)
    	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
    	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
    	at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:187)
    	at org.springframework.data.redis.connection.jedis.JedisConnection.doWithJedis(JedisConnection.java:802)
    	at org.springframework.data.redis.connection.jedis.JedisConnection.doInvoke(JedisConnection.java:160)
    	at org.springframework.data.redis.connection.jedis.JedisConnection.lambda$new$0(JedisConnection.java:69)
    	at org.springframework.data.redis.connection.jedis.JedisInvoker$Synchronizer.invoke(JedisInvoker.java:1027)
    	at org.springframework.data.redis.connection.jedis.JedisInvoker$DefaultSingleInvocationSpec.getOrElse(JedisInvoker.java:946)
    	at org.springframework.data.redis.connection.jedis.JedisStringCommands.setEx(JedisStringCommands.java:176)
    	at org.springframework.data.redis.connection.DefaultedRedisConnection.setEx(DefaultedRedisConnection.java:334)
    	at org.springframework.data.redis.connection.DefaultStringRedisConnection.setEx(DefaultStringRedisConnection.java:1138)
    	at org.springframework.data.redis.core.DefaultValueOperations$8.potentiallyUsePsetEx(DefaultValueOperations.java:337)
    	at org.springframework.data.redis.core.DefaultValueOperations$8.doInRedis(DefaultValueOperations.java:330)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:223)
    	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:190)
    	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:97)
    	at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:325)
    	at com.newatc.radar.service.IntersectionQueryService.getAllIntersections(IntersectionQueryService.java:70)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    报错二

    • 核心报错提示是这一句: Error while validating pooled Jedis object
    • 连接池内的Jedis对象已经失效或已经关闭,没有可用的jedis客户端
    2023-08-24 09:44:23.721 ERROR 92250 --- [ns-pool-evictor] redis.clients.jedis.JedisFactory         : Error while validating pooled Jedis object.
    
    redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:205)
    	at redis.clients.jedis.util.RedisInputStream.readByte(RedisInputStream.java:43)
    	at redis.clients.jedis.Protocol.process(Protocol.java:162)
    	at redis.clients.jedis.Protocol.read(Protocol.java:227)
    	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:352)
    	at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:270)
    	at redis.clients.jedis.BinaryJedis.ping(BinaryJedis.java:380)
    	at redis.clients.jedis.JedisFactory.validateObject(JedisFactory.java:214)
    	at org.apache.commons.pool2.impl.GenericObjectPool.evict(GenericObjectPool.java:745)
    	at org.apache.commons.pool2.impl.BaseGenericObjectPool$Evictor.run(BaseGenericObjectPool.java:160)
    	at org.apache.commons.pool2.impl.EvictionTimer$WeakRunner.run(EvictionTimer.java:113)
    	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
    	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
    	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    	at java.base/java.lang.Thread.run(Thread.java:829)
    Caused by: java.net.SocketTimeoutException: Read timed out
    	at java.base/java.net.SocketInputStream.socketRead0(Native Method)
    	at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:126)
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:199)
    	... 16 common frames omitted
    
    2023-08-24 09:44:25.724 ERROR 92250 --- [ns-pool-evictor] redis.clients.jedis.JedisFactory         : Error while validating pooled Jedis object.
    
    redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:205)
    	at redis.clients.jedis.util.RedisInputStream.readByte(RedisInputStream.java:43)
    	at redis.clients.jedis.Protocol.process(Protocol.java:162)
    	at redis.clients.jedis.Protocol.read(Protocol.java:227)
    	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:352)
    	at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:270)
    	at redis.clients.jedis.BinaryJedis.ping(BinaryJedis.java:380)
    	at redis.clients.jedis.JedisFactory.validateObject(JedisFactory.java:214)
    	at org.apache.commons.pool2.impl.GenericObjectPool.evict(GenericObjectPool.java:745)
    	at org.apache.commons.pool2.impl.BaseGenericObjectPool$Evictor.run(BaseGenericObjectPool.java:160)
    	at org.apache.commons.pool2.impl.EvictionTimer$WeakRunner.run(EvictionTimer.java:113)
    	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    	at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
    	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
    	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    	at java.base/java.lang.Thread.run(Thread.java:829)
    Caused by: java.net.SocketTimeoutException: Read timed out
    	at java.base/java.net.SocketInputStream.socketRead0(Native Method)
    	at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
    	at java.base/java.net.SocketInputStream.read(SocketInputStream.java:126)
    	at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:199)
    	... 16 common frames omitted
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    解决

    • 报错是发生在我们的环境,事实上,我们的平台并没有那么高的并发量,只有一些造数据脚本在跑和调用redis
    • 而且所有应用服务和redis服务,都在一个内网环境里,不应该有网络波动的问题,但发生这个报错时,使用可视化工具连接redis,可以发现,Redis服务是正常的
    • 最终发现,是我们没有针对新版本,配置好超时参数
    • 原有配置
    spring:
      redis:
        host: 192.168.1.50
        port: 6379
        password:
        database: 0
        jedis:
          pool:
            min-idle: 10
            max-idle: 400
            max-wait: 30000
            max-active: 200
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 查看了源码后发现,少了对于redis客户端连接维护的超时时间设置,这个超时时间默认是2s,有时候是不够用的
    • 当大并发量来临,或者大量对象存储更新时,阻塞可能会超过2s时,就会报错SocketTimeoutException
    • 新的配置(时间可以写毫秒,也可以带单位)
    • spring.redis.timeout:是指与redis服务器的读写超时时间,读写操作时会判断这个
    • spring.redis.connect-timeout:是指与redis服务器的连接超时时间,默认2s,这个可以设置大一点,例如30s,保证短时的网络波动不影响连接
    • spring.redis.jedis.pool.min-idle:最小空闲连接,可以根据需要写,我这里设置为8
    • spring.redis.jedis.pool.max-idle:最大空闲连接,可以根据需要写,我这里设置为200,够用了
    • spring.redis.jedis.pool.max-wait:连接池最大阻塞等待时间(使用负值表示没有限制),这个是指服务从连接池获取连接的等待时间,我这里设置为30s,够用了
    • spring.redis.jedis.pool.max-active:连接池最大连接数(使用负值表示没有限制),根据我们的应用数量设置,我这里设置256,足够用了
    spring:
      redis:
        host: 192.168.1.50
        port: 6379
        password:
        database: 0
        timeout: 30s # 读写超时
        connect-timeout: 60s #连接超时
        jedis:
          pool:
            min-idle: 8 # 最小空闲连接
            max-idle: 200 # 最大空闲连接
            max-wait: 30s # 连接池最大阻塞等待时间(使用负值表示没有限制)
            max-active: 256 # 连接池最大连接数(使用负值表示没有限制)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 总结一下,一开始只配置了参数spring.redis.jedis.pool.max-wait连接池最大阻塞等待时间,而没有配置spring.redis.timeoutspring.redis.connect-timeout,导致偶发的超时
    • 配置上这两个参数后,就没有遇到超时报错了
    • 最后再介绍下Jedis连接池吧

    Jedis连接池

    Jedis连接池是用于管理Jedis客户端连接的一种机制。Jedis是一个非常流行的Java Redis客户端,它允许Java开发人员与Redis服务器进行交互。

    Jedis连接池的目的是为了提高应用程序与Redis服务器之间的性能和可扩展性。通过连接池,应用程序可以重复利用现有的连接而不是创建新的连接,从而减少连接的创建和销毁的开销。

    Jedis连接池的实现中有几个主要的组件:

    1. 连接池配置(Config):用于设置连接池的参数,如最大连接数、最大空闲连接数、连接超时时间等。

    2. 连接池对象(JedisPool):用于创建和管理Jedis连接。

    3. Jedis连接(Jedis):用于与Redis服务器进行交互的对象。

    连接池的工作原理如下:

    • 初始化:当连接池被创建时,它会根据配置参数建立一定数量的连接,并放入连接池中。
    • 借用连接:当应用程序需要与Redis服务器进行交互时,它可以从连接池中获取一个空闲连接。
    • 使用连接:应用程序使用连接进行操作,如执行命令、读写数据等操作。
    • 归还连接:应用程序完成操作后,将连接归还给连接池,以便其他线程或请求可以继续使用该连接。
    • 连接池管理:连接池会根据预设的策略来管理连接的状态,如连接的获取、释放、逐出等。

    使用Jedis连接池可以提高应用程序与Redis服务器之间的性能和资源利用率。通过合理配置连接池的参数,可以控制连接数、连接超时时间、最大空闲连接数等,以适应不同规模的应用程序需求。同时,连接池还可以提供连接的可用性检查、自动重连、连接汇报等功能,提高应用的可靠性和稳定性。

  • 相关阅读:
    有哪些挣钱软件一天能赚几十元?盘点十个能长期做下去的挣钱软件
    二、链表(linked-list)
    mybatis、mybatisPlus
    开源数据备份工具 Duplicati
    2022-2028全球绕线片线圈行业调研及趋势分析报告
    MySQL优化
    数字孪生的技术开发平台
    好看又好用的办公好物,电脑手机都能打字,双飞燕剪刀脚键盘体验
    0基础学习VR全景平台篇第119篇:利用蒙版航拍补天 - PS教程
    使用HTML制作静态网站作业——我的校园运动会(HTML+CSS)
  • 原文地址:https://blog.csdn.net/u010882234/article/details/134010358