当前位置:   article > 正文

JAVA-redis报错:JedisConnectionException: Could not get a resource from the pool_redis.clients.jedis.exceptions.jedisconnectionexce

redis.clients.jedis.exceptions.jedisconnectionexception: could not get a res

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)
                ...................
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
                ...................
Caused by: java.net.SocketTimeoutException: connect timed out

网上能搜到的解决方法无非分为以下几个:

Redis没有启动,需要启动redis:我的不是这个原因,使用RedisDesktopManager工具连接正常。
防火墙、安全组没有关闭:防火墙压根没开过、安全组早已经把6379端口开放了。
IP地址或端口错误:查看以下程序中写的自己云服务器的IP和端口,没问题。
Jedis 对象用完以后未释放掉,池中无可用资源,所以会出现无法获取新的资源。

网上说,客户端去redis服务器拿连接的时候,池中无可用连接,即池中所有连接被占用,且在等待时候设定的超时时间后还没拿到时,报出此异常。 解决办法:调整JedisPoolConfig中maxActive为适合自己系统的阀值。

网上一篇博客中提到:如果你用的jedis 2.4.2以及以前版本,用完之后别忘了return连接到资源池。不过2.5.0版本之后,jedis使用了try-with-resource,jedis用完了就会自动归还了,不用每次都自己return了。相应的他还给出了一个完整的,带有return资源到连接池的Jedis工具类,我一想,我使用的Jedis版本是2.8.0啊,按他说的讲道理jedis用完了就会自动归还了,我就把我之前的工具类给替换掉了。不过他写的这个工具类确实挺好的,后面一直使用的也是这个,我贴到下面哈:

  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. import redis.clients.jedis.Jedis;
  4. import redis.clients.jedis.JedisPool;
  5. import redis.clients.jedis.JedisPoolConfig;
  6. import java.util.Map;
  7. import java.util.concurrent.ConcurrentHashMap;
  8. /**
  9. * @说明: Redis操作工具类
  10. * @return
  11. * @author:Jeremiah Yu
  12. * @date 2019/3/5 11:36
  13. */
  14. public class JedisUtil {
  15. private static final Log logger = LogFactory.getLog(JedisUtil.class);
  16. //Redis服务器IP
  17. private static String IP = "127.0.0.1";
  18. //Redis的端口号
  19. private static int PORT = 6379;
  20. //Redis服务密码
  21. private static String password = "******";
  22. //可用连接实例的最大数目,默认值为8;
  23. //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
  24. private static int MAX_ACTIVE = 64;
  25. //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
  26. private static int MAX_IDLE = 20;
  27. //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
  28. private static int MAX_WAIT = 3000;
  29. private static int TIMEOUT = 3000;
  30. //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
  31. private static boolean TEST_ON_BORROW = true;
  32. //在return给pool时,是否提前进行validate操作;
  33. private static boolean TEST_ON_RETURN = true;
  34. private static Map<String, JedisPool> maps = new ConcurrentHashMap<String, JedisPool>();
  35. private JedisUtil() {
  36. }
  37. /**
  38. * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
  39. */
  40. private static class RedisUtilHolder {
  41. private static JedisUtil instance = new JedisUtil();
  42. }
  43. /**
  44. * 当getInstance方法第一次被调用的时候,它第一次读取 RedisUtilHolder.instance,导致RedisUtilHolder类得到初始化;
  45. * 而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建RedisUtil的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,
  46. * 并由虚拟机来保证它的线程安全性。 这个模式的优势在于,getInstance方法并没有被同步,
  47. * 并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。
  48. */
  49. public static JedisUtil getInstance() {
  50. return RedisUtilHolder.instance;
  51. }
  52. /**
  53. * 获取连接池.
  54. */
  55. private JedisPool getPool(String ip, int port) {
  56. String key = ip + ":" + port;
  57. JedisPool pool = null;
  58. if (!maps.containsKey(key)) {//根据ip和端口判断连接池是否存在.
  59. JedisPoolConfig config = new JedisPoolConfig();
  60. config.setMaxTotal(MAX_ACTIVE);
  61. config.setMaxIdle(MAX_IDLE);
  62. config.setMaxWaitMillis(MAX_WAIT);
  63. config.setTestOnBorrow(TEST_ON_BORROW);
  64. config.setTestOnReturn(TEST_ON_RETURN);
  65. //false:如果连接池没有可用Jedis连接,立即抛出异常;默认true时:如果连接池没有可用Jedis连接,
  66. //会等待maxWaitMillis(毫秒),依然没有获取到可用Jedis连接
  67. //config.setBlockWhenExhausted(false);
  68. try {
  69. pool = new JedisPool(config, ip, port, TIMEOUT,password);
  70. maps.put(key, pool);
  71. } catch (Exception e) {
  72. logger.error("初始化Redis连接池异常:", e);
  73. }
  74. } else {
  75. pool = maps.get(key);
  76. }
  77. return pool;
  78. }
  79. /**
  80. * 获取Jedis实例
  81. */
  82. public Jedis getJedis() {
  83. Jedis jedis = null;
  84. try {
  85. jedis = getPool(IP, PORT).getResource();
  86. } catch (Exception e) {
  87. logger.error("获取Jedis实例异常:", e);
  88. // 销毁对象
  89. getPool(IP, PORT).returnBrokenResource(jedis);
  90. }
  91. return jedis;
  92. }
  93. /**
  94. * 释放jedis资源到连接池
  95. */
  96. public void returnResource(final Jedis jedis) {
  97. if (jedis != null) {
  98. getPool(IP, PORT).returnResource(jedis);
  99. }
  100. }
  101. /**
  102. * 获取数据
  103. */
  104. public Object get(String key) {
  105. Object value = null;
  106. Jedis jedis = null;
  107. try {
  108. jedis = getJedis();
  109. value = jedis.get(key);
  110. } catch (Exception e) {
  111. logger.warn("获取数据异常:", e);
  112. } finally {
  113. //返还到连接池
  114. returnResource(jedis);
  115. }
  116. return value;
  117. }
  118. //设置数据
  119. public boolean set(String key,String value){
  120. Jedis jedis = null;
  121. try {
  122. jedis = getJedis();
  123. jedis.set(key,value);
  124. return true;
  125. }catch (Exception e){
  126. logger.warn("设置数据异常",e);
  127. return false;
  128. }finally {
  129. //返还到连接池
  130. returnResource(jedis);
  131. }
  132. }
  133. //删除数据
  134. public void delete(String key){
  135. Jedis jedis = null;
  136. try {
  137. jedis = getJedis();
  138. jedis.del(key);
  139. }catch (Exception e){
  140. logger.warn("删除数据异常",e);
  141. }finally {
  142. //返还到连接池
  143. returnResource(jedis);
  144. }
  145. }
  146. public static void main(String[] args) {
  147. JedisUtil.getInstance().set("lp","yuzhsaneh");
  148. Object val = JedisUtil.getInstance().get("lp");
  149. System.out.println(val);
  150. }
  151. }

连接池参数blockWhenExhausted = true(默认)如果连接池没有可用Jedis连接,会等待maxWaitMillis(毫秒),如果依然没有获取到可用Jedis连接,会抛出如下异常:

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)

连接池参数blockWhenExhausted = false;设置该参数,如果连接池没有可用的Jedis连接,立即抛出异常:

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)

上述异常是客户端没有从连接池(最大数量maxTotal)获得可用的Jedis连接造成的,可能有如下原因:

(1) 连接泄露:JedisPool默认的maxTotal=8,下面的代码从JedisPool中获取了8个Jedis资源,但是没有归还资源,当第9次尝试获取Jedis资源的时候,无法获得(jedisPool.getResource().ping())(我已经换成了别人写好的Redis工具类,别人封装的很好了啊,用完就放回资源池里,这种情况可以排除)

(2) 业务并发量大,maxTotal设置得过小了。(我的项目压根就没有上线,不存在什么并发)

(3) Jedis连接阻塞:例如Redis发生了阻塞(例如慢查询等原因),所有连接在超时时间范围内等待,并发量较大时,会造成连接池资源不足。(我重新安装过Redis,第一次连接也是同样的问题,所以这种情况也可以排除)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/676848
推荐阅读
相关标签
  

闽ICP备14008679号