-
我写这篇日志是为了纪念这个错误的,它是我遇到过的最坑人的错误,也是我自己独立解决,没有抄袭网上答案的一个问题。之所以发个博客纪念它,确实是太坑了。
-
初次遇到这个错,还是在去年年底的时候,那个时候,服务器老是出现这个错误,然后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;
}
- 我怀疑是 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;
}
-
再次运行项目之后,再也没有出现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();
}
}
- 以上就是这个问题的解决思路,大家遇到过这种错误吗?在下方留言一起讨论讨论吧!