关于JedisExhaustedPoolException: Could not get a resource since the pool is exhausted的一种解决方案

现状

之前公司的自管理监控项目可以实时监测Redis的运行状态,来检查Redis是否是正常运行的,但是最近经常出现一些问题,就是明明Redis集群是正常的,但是界面上却看不到Redis的运行状态,这就很奇怪了,于是看了下后台服务日志内容,报错内容大致如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMueM7M6-1634977508583)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/74b6af49-c56d-459a-8da9-f139ffcf4176/Untitled.png)]

报错内容

2021-09-17 16:01:24.577 ERROR c.u.b.s.c.a.m.r.RedisStatusDetecter - redis detect error
redis.clients.jedis.exceptions.JedisExhaustedPoolException: Could not get a resource since the pool is exhausted
	at redis.clients.jedis.util.Pool.getResource(Pool.java:53)
	at redis.clients.jedis.JedisPool.getResource(JedisPool.java:288)
	at com.ultrapower.bsms.selfmanage.collector.activedetect.middleware.redis.RedisCollector.doCollect(RedisCollector.java:35)
	at com.ultrapower.bsms.selfmanage.collector.activedetect.middleware.redis.RedisStatusDetecter.detect(RedisStatusDetecter.java:35)
	at com.ultrapower.bsms.selfmanage.collector.ScheduleTasks.redisDetecter(ScheduleTasks.java:182)
	at sun.reflect.GeneratedMethodAccessor318.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at

翻译成中文大致意思就是取不到Redis连接了,因为连接池已经耗尽了,那问题是正常情况下从JedisPool里面获取的redis连接应该会在使用完就会释放,现在给人的感觉就是连接池一直在取redis连接,但是使用完后并没有释放,最终导致连接池中的连接全部用完耗尽,当再也取不到连接的时候就会报上面这个错,而代码处理逻辑就是根据redis连接去获取Redis的活动状态,因为这里获取不到连接,就会认为Redis挂掉,进而就从数据库把redis的节点信息给删除了,所以界面上看不到redis了

根据这里报错的源头找到之前项目里这块代码有这么一段,可以看到这块通过jedisPool获取redis连接后进行了一波信息处理后就直接返回结果了,,,难道说jedisPool有自动释放redis连接的功能呢???还是说这是前人代码留下来的一个坑。。。。

Jedis jedis =null;
jedis = jedisPool.getResource();
String info = jedis.info();
                     //log.info("meKey=" + meKey);
List<Map<String, String>> kpiDataList = getNodeData(info);

result.put(meKey, kpiDataList);            
return result;

在JedisPool的老版本,也就是3.0以前的版本中,关闭释放连接是这么做的

可以看到这里做了两种操作,一种操作是获取连接发生异常的时候调用returnBrokenResource()方法处理,另外一种方式是正常调用,之后在finally里面调用returnResource去释放连接,看来考虑情况还挺多的,,,

public String get(String key) {
    Jedis redis = null;
    try {
        redis = redisPool.getResource();
        return redis.get(key);
    } catch (JedisConnectionException e) {
        if (redis != null) {
            redisPool.returnBrokenResource(redis);
            redis = null;
        }
        throw e;
    } finally {
        if (redis != null) {
            redisPool.returnResource(redis);
        }
    }
}

一开始想用这种方式处理,但是貌似效果不好使。。。于是看了下公司的redie的版本,是3.0以上的版本,难道说3.0以上版本的释放连接功能变了,于是各种一顿查,说是在3.0以上版本直接调用close方法就可以了。。。。我去这么简单粗暴的嘛

<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>3.3.0</version>
		</dependency>

于是代码直接改造成如下这种,看着是不是比之前释放连接方式简介多了,但是为什么比之前这么简洁呢。。。

// 每个节点详细指标信息
            Jedis jedis =null;
                 try{
                      jedis = jedisPool.getResource();
                     String info = jedis.info();
                     //log.info("meKey=" + meKey);
                     List<Map<String, String>> kpiDataList = getNodeData(info);

                     result.put(meKey, kpiDataList);
                 }finally {
                     //新增jedis释放连接的方法,避免运行一段时间后redis连接池耗尽而挂掉
                     if(jedis!=null){
                         jedis.close();
                     }

                 }
        }
        return result;

于是处于好奇点进去看了下close方法,好家伙,原来官方在这里做了一层封装处理,内部其实还是换汤不换药,但是对于使用者去调用可是友好了很多,这点得点个赞
在这里插入图片描述

在改造完毕后重新启动项目,运行了很长一段时间,再也没有报Redis连接池耗尽的问题,。完美解决了

结论

使用JedisPool连接池获取redis连接池一定要记得主动关闭redis连接,避免这种低级错。。。。这又算填了前人的一个坑哈哈

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梦岚如雪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值