JedisException:Could not get a resource from the pool

一、问题描述

最近一个老项目线上出现一个问题,操作 redis 的地方全都报错

org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:281)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:464)
at org.springframework.data.redis.cache.DefaultRedisCacheWriter.execute(DefaultRedisCacheWriter.java:238)
at org.springframework.data.redis.cache.DefaultRedisCacheWriter.get(DefaultRedisCacheWriter.java:109)
at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:82)
at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:554)
at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:519)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:401)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)

Caused by: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:51)
at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:210)
at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:17)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:271)
… 89 common frames omitted
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:456)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:365)
at redis.clients.util.Pool.getResource(Pool.java:49)
… 92 common frames omitted

二、问题排查

看报错,感觉是连接池资源耗尽了,看了下配置,最大连接数配的128,然后有四台服务器,不觉得是配少的原因,所以怀疑是连接池资源使用后未释放,但是看了下代码,都是直接用 redisTemplate 操作的,不存在自己操作资源,因为是老项目,使用的版本都比较低,于是怀疑是不是 Jedis 的bug,这边使用的是 Jedis 的 2.9.1 版本,在网上搜了之后,发现确实存在bug,参考:https://github.com/redis/jedis/issues/1920

image-20241112103747014

image-20241112103757930

image-20241112103845312

意思就是:

1、当线程A在 Jedis 类中操作到 returnResource,还没执行到 this.dataSource = null;

2、线程B在 JedisSentinelPool 类里执行到 jedis.setDataSource(this);

3、这时候线程A执行了 this.dataSource = null;

4、这时候线程B里的 dataSource 就是null了,当线程B执行到 Jedis 类里的 close 方法时,就永远不会走到 returnResource

这就导致在高并发的时候,有可能存在线程资源没有正常的回收,长时间运行下来,线程池中可用的资源会越来越少,最终导致没有资源可用,我们这个老项目服务确实有大半年没有重启了,符合这个场景

Jedis在 2.10.2 版本对 Jedis 类的 close 方法做了修改,解决了这个问题

image-20241112105224640

三、解决问题

升级 Jedis 的版本到2.10.2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步亿点点的小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值