Redis报错:JedisConnectionException: Could not get a resource from the pool

文章分析了JedisConnectionException的出现原因,涉及连接池资源不足、连接泄露、配置错误等,提供了解决方案,包括检查Redis配置、调整连接池参数和优化代码规范。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、问题描述:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

2、简要分析:
redis.clients.util.Pool.getResource会从JedisPool实例池中返回一个可用的redis连接。分析源码可知JedisPool 继承了 redis.clients.util.Pool ,而这个Pool是通过commons-pool开源工具包中的org.apache.commons.pool2.impl.GenericObjectPool来实现对Jedis实例的管理的。所以我们分析一下GenericObjectPool或许能找到答案。

其中GenericObjectPool三个重要个几个属性是:

MaxActive: 最大连接数
MaxIdle: 最大空闲数
MaxWait: 最大等待时间,单位毫秒(million seconds)

连接池中无可用连接时会会进行等待maxWait时间,若超出泽抛Could not get a resource from the pool异常。所以应根据程序实际情况合理设置这三个参数的值,尽量避免这个异常。

分析结果:
如果连接池没有可用Jedis连接,会等待maxWaitMillis(毫秒),依然没有获取到可用Jedis连接,会抛出这个异常:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

3、发生异常可能的情况

异常原因一、客户端没有从连接池(最大maxTotal个)拿到可用Jedis连接造成的【简称连接泄露 (常见)

分析图如下:
在这里插入图片描述

JedisPool默认的maxTotal=8,下面的代码从JedisPool中借了8次Jedis,但是没有归还,当第9次(jedisPool.getResource().ping())

GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
//向JedisPool借用8次连接,但是没有执行归还操作。
for (int i = 0; i < 8; i++) {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        jedis.ping();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
}
jedisPool.getResource().ping();

所以推荐使用的代码规范是:

执行命令如下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具体的命令
    jedis.executeCommand()
} catch (Exception e) {
    //如果命令有key最好把key也在错误日志打印出来,对于集群版来说通过key可以帮助定位到具体节点。
    logger.error(e.getMessage(), e);
} finally {
    //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
    if (jedis != null) 
        jedis.close();
}

异常原因二: 业务并发量大,maxTotal确实设置小了!

举个例子:

一次命令时间(borrow|return resource + Jedis执行命令(含网络) )的平均耗时约为1ms,一个连接的QPS大约是1000,业务期望的QPS是50000,那么理论上需要的资源池大小是50000 / 1000 = 50个,实际maxTotal可以根据理论值合理进行微调。

异常原因三: Jedis连接还的太慢

例如Redis发生了阻塞(例如慢查询等原因),所有连接在超时时间范围内等待,并发量较大时,会造成连接池资源不足。

异常原因四: 其他问题

例如丢包、DNS、客户端TCP参数配置,具体可以参考:Jedis介绍及常见问题分析

异常原因五: 检查Redis的配置是否正确,IP端口【值得反思】
 

4、解决方案:
1、检查Redis的配置是否正确,IP端口【值得反思】
2、调整配置参数。但是,不要被异常的表象所迷惑,简单地认为连接池不够就盲目加大maxTotal,要具体问题具体分析。连接池参数优化可以参考:JedisPool资源池优化
3、客户端没有从连接池(最大maxTotal个)拿到可用Jedis连接造成的,简称连接泄露 (常见),所以推荐使用的代码规范是如下:
 

执行命令如下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具体的命令
    jedis.executeCommand()
} catch (Exception e) {
    //如果命令有key最好把key也在错误日志打印出来,对于集群版来说通过key可以帮助定位到具体节点。
    logger.error(e.getMessage(), e);
} finally {
    //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
    if (jedis != null) 
        jedis.close();
}

参考:Jedis常见异常汇总 | 程序猿DD

### 解决无法从连接池获取资源的问题 当遇到无法从连接池获取资源的情况时,通常是因为连接池中的所有连接都在使用中或已损坏。为了有效处理这一问题,可以采取以下措施: #### 1. 清理连接池 ADO.NET 提供了两种方法来清理连接池:`ClearAllPools` 和 `ClearPool` 方法。前者用于清除给定提供程序的所有连接池,而后者则专门针对特定连接的连接池进行清理。如果调用这些方法时有正在使用的连接,则会标记它们;当这些连接关闭时,会被丢弃而不是返回到连接池[^1]。 ```csharp // 使用 ClearAllPools 方法清理所有连接池 SqlConnection.ClearAllPools(); // 或者使用 ClearPool 方法清理指定连接的连接池 using (var conn = new SqlConnection(connectionString)) { SqlConnection.ClearPool(conn); } ``` #### 2. 增加最大连接数 另一个常见的解决方案是增加应用程序配置文件 (`app.config` 或 `web.config`) 中的最大允许并发连接数量。这可以通过设置 `Max Pool Size` 参数实现。 ```xml <connectionStrings> <add name="MyConnectionString" connectionString="Server=myServer;Database=myDB;User Id=myUsername;Password=myPassword;Max Pool Size=200;" providerName="System.Data.SqlClient"/> </connectionStrings> ``` #### 3. 检查异常情况下的连接释放 确保在任何情况下都正确关闭数据库连接非常重要。即使发生未处理的异常也应如此操作。建议总是将连接对象放在 `using` 语句块内以自动管理其生命周期。 ```csharp try { using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); // 执行查询... } } catch (Exception ex) { Console.WriteLine($"An error occurred: {ex.Message}"); } finally { // 如果不是通过 using 关键字创建连接,在这里显式关闭它 } ``` #### 4. 调整超时时间 适当调整命令执行和打开新连接的时间限制也可能有助于缓解此问题。可以在连接字符串中定义这两个参数。 ```xml <connectionStrings> <add name="MyConnectionString" connectionString="Server=myServer;Database=myDB;User Id=myUsername;Password=myPassword;Connect Timeout=30;Command Timeout=60;" providerName="System.Data.SqlClient"/> </connectionStrings> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值