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缓存使用规范,值得读。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/16977131.html