buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

JedisPool异常:Could not get a resource from the pool

JedisConnectionException: Could not get a resource from the pool  -------无法从连接池中获取到连接(资源)。

具体原因主要看异常堆栈信息里的Caused By子句。

 

下面Caused by可知,在调用borrowObject获取idle连接时,由于池中没有idle连接,出现阻塞等待,结果发生等待超时。

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  …
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)

 

下面Caused by可知,同样在从池中获取idle连接时,由于池中没有idle连接,并且设置了不等待(blockWhenExhausted=false),故出现异常。

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  …
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)

 

而我们的优付trans今天出现了如下Caused by的异常--- Pool not open。

2022-12-12 10:09:10.080 WARN  [clientBusiness_common_1670810950078S930,TID:d09088df43334542893d6ffc06399ff6.132.16708109500416701,0308d204b0a94d8eb6dd1b48ae72bcec] com.yft.opencommon.cache.JedisUtils:854 :getResource.
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
        at redis.clients.util.Pool.getResource(Pool.java:53)
        at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226)
        at com.yft.opencommon.cache.JedisUtils.getResource(JedisUtils.java:851)
        at com.yft.opencommon.cache.JedisUtils.get(JedisUtils.java:53)
        at com.cn.yft.cache.RedisCacheUtil.getMerReqLimit(RedisCacheUtil.java:213)
        …
Caused by: java.lang.IllegalStateException: Pool not open
        at org.apache.commons.pool2.impl.BaseGenericObjectPool.assertOpen(BaseGenericObjectPool.java:759)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:395)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:346)
        at redis.clients.util.Pool.getResource(Pool.java:49)
        ... 76 common frames omitted

持续时间从上午10:09:10.080~10:17:00.306,影响部分客户下发。运营反馈后,立即重启服务暂时得到解决。

排查:

优付trans有4个节点做负载:两台在IDC机房、两台在联通云机房,双机房有专线。redis是单节点,服务器在IDC机房。当时只有联通云机房5号节点出现这个异常,其他节点未发现。 当然,这与各节点QPS以及redis操作数量有关,并不一定都会出现这个异常。

抛出Pool not open异常的源码在commons-pool2的BaseGenericObjectPool里

    /**
     * Verifies that the pool is open.
     * @throws IllegalStateException if the pool is closed.
     */
    final void assertOpen() throws IllegalStateException {
        if (isClosed()) {
            throw new IllegalStateException("Pool not open");
        }
    }

而后发现程序里JedisPool的配置,maxIdle配置的是1。

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="1" /> <!-- 资源池允许最大空闲的连接数  -->
        <property name="maxTotal" value="300" /> <!-- 资源池中最大连接数 -->
        <property name="testOnBorrow" value="true" /> <!-- 当调用borrowObject方法时,是否进行有效性检查 -->
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg index="0" ref="jedisPoolConfig"/>
        <constructor-arg index="1" value="${redis_ip}" type="java.lang.String"/>
        <constructor-arg index="2" value="${redis_port}" type="int"/>
        <constructor-arg index="3" value="${redis_expire}" type="int"/>
        <constructor-arg index="4" value="${redis_password}" type="java.lang.String"/>
    </bean>

分析最大原因应该是当时系统需要操作redis的逻辑太多,而jedis配置不合理,导致了这个异常的出现。一个同学在本地测试环境通过并行测试,也有模拟出来这个异常。

当天晚上,将maxIdle改为200上线,经过持续一天的观察未见异常。

 

关于Pool not open异常,网上这篇技术贴写的不错。JedisPool 在关闭情况下为什么 还能提供连接资源 并且 只有一个线程一直拿不到连接资源

 

 

微信公众号里也发现一篇文章,https://mp.weixin.qq.com/s/EWH-buDjBthxH6UGrFdP1w 列举jedis常见问题及redis缓存使用规范,值得读。

posted on 2022-12-12 21:17  buguge  阅读(890)  评论(0编辑  收藏  举报