曾纠缠了我三个月的Redis报错Could not get a resource from the pool

  • 我写这篇日志是为了纪念这个错误的,它是我遇到过的最坑人的错误,也是我自己独立解决,没有抄袭网上答案的一个问题。之所以发个博客纪念它,确实是太坑了。

  • 初次遇到这个错,还是在去年年底的时候,那个时候,服务器老是出现这个错误,然后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();
		}
	}
  • 以上就是这个问题的解决思路,大家遇到过这种错误吗?在下方留言一起讨论讨论吧!
原创文章 123 获赞 50 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_39076203/article/details/106158321