-
我写这篇日志是为了纪念这个错误的,它是我遇到过的最坑人的错误,也是我自己独立解决,没有抄袭网上答案的一个问题。之所以发个博客纪念它,确实是太坑了。
-
初次遇到这个错,还是在去年年底的时候,那个时候,服务器老是出现这个错误,然后redis就无法使用了,然后各种连锁反应接踵而至,搞得我慌的一屁。
-
2020年春节后三月份来公司后,决定要彻底解决一下。于是,在尝试了各种方法都没有效果的情况下,更换了redis 版本,jedis版本,都咩有一点效果,过段时间还是报这个错,而且错误的日志还是一模一样。
-
要炸了,如果再不解决,我特么就会天天被这个问题烦死,以后可咋办。我不打算就此放弃治疗,我想,一定是有什么问题没有被发现。我看了看代码,发现连接池的配置没有什么问题。存取值的时候也还没有发现特别大的问题。但是它总是在jedis的那个类取值的代码区域报错,说明,存取的时候出了问题的。
-
于是看了一下代码。
/** * 获取抓取任务 * @return */ public static JSONObject takeEmsTraceInfoUploadFromQue() {
Jedis jedis = getJedis(); if(jedis == null){ Logger.info("can not get a jedis from pool..."); return null; } // 从jedis中获取 String jsonStr = ""; try { List<String> jsonList = jedis.blpop(500, "ems_traceinfo_upload_que"); if (jsonList.size() > 0) { jsonStr = jsonList.get(1); } if (StringUtils.isNotBlank(jsonStr)) { return JSONObject.fromObject(jsonStr); } } catch (Exception ex) { ex.printStackTrace(); } finally { close(jedis); } return null; }
123456789101112131415161718192021222324252627282930313233
-
我怀疑是 blpop 这个方法有什么问题。查了下这个方法
-
“会阻塞列表直到等待超时或发现可弹出元素为止” 这句话意思不就是 如果没有元素可取,则会一直等待,那么我如果没有元素不停的去取,这样不就占用了redis 的资源了吗?难道是这里的问题?
-
如果是这样,我换个取值的方式怎么样,用lpop (因为我存元素的时候是用rpush 的所以用lpop,如果你用lpush存元素,一定要用rpop,这样才像队列)
*
由此可见,lpop 在取值的时候是没有等待时间的,有的话就去取,没有的话就返回null。这样就避开了等待的时间。
-
于是我更换成这样
/** * 获取抓取任务 * @return */ public static JSONObject takeEmsTraceInfoUploadFromQue() {
Jedis jedis = getJedis(); try { String jsonList = jedis.lpop("ems_traceinfo_upload_que"); if (StringUtils.isNotBlank(jsonList)) { return JSONObject.fromObject(jsonList); } } catch (Exception ex) { ex.printStackTrace(); } finally { close(jedis); } return null; }
1234567891011121314151617181920212223
-
再次运行项目之后,再也没有出现Could not get a resource from the pool 这个报错了,而且系统正常运行,说明这样改是正确滴!
-
网上还有说是 JedisPool 配置的原因,但我改了无数次配置,发现还是报错。于是索性保留之前的配置。如下
/** * 初始化Redis连接池 */ static { try { JedisPoolConfig config = new JedisPoolConfig(); // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true config.setBlockWhenExhausted(true); // 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数) config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy"); // 是否启用pool的jmx管理功能, 默认true config.setJmxEnabled(true); // 最大空闲连接数, 默认8个 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。 config.setMaxIdle(40); config.setMaxTotal(100); config.setMinIdle(10); // 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException; config.setMaxWaitMillis(1000 * 2000); // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; config.setTestOnBorrow(true);
String serverAddress = Play.configuration.getProperty("redis.server.address"); int serverPort = Integer.valueOf(Play.configuration.getProperty("redis.server.port")); String serverPassword = Play.configuration.getProperty("redis.server.password"); jedisPool = new JedisPool(config, serverAddress, serverPort, 3000, serverPassword); } catch (Exception e) { e.printStackTrace(); } }
123456789101112131415161718192021222324252627282930
-
以上就是这个问题的解决思路,大家遇到过这种错误吗?在下方留言一起讨论讨论吧!
总结:
感谢大家阅读完本文章,也为大家准备了Java进阶的架构资料,需要的朋友可以关注微信公众号**【Java程序员聚集地】**获取架构资料。