一个Java Web的系统需要动态根据Redis地址获取数据,截取相关代码如下:
获取连接的方法:
public static JedisCluster getConn(String host, int port)
{
String key = getKey(host, port);
JedisCluster jedisCluster = (JedisCluster)jedisConnMap.get(key);
if (jedisCluster == null) {
try {
LOG.debug("jedisCluster is empty.");
HostAndPort hostAndPort = new HostAndPort(host, port);
Set hpset = Sets.newHashSet(new HostAndPort[] { hostAndPort });
jedisCluster = new JedisCluster(hpset, 30);
} catch (JedisException e) {
LOG.error("create jediscluster error: {}", e);
}
if (jedisCluster != null) {
jedisConnMap.put(key, jedisCluster);
}
}
return jedisCluster;
}
调用的代码块:
JedisCluster jedisCluster = JedisConnCacheUtil.getConn(host, port);
if (jedisCluster == null) {
LOG.debug("get jedisCluster error.");
return;
}
Map jedisPools = jedisCluster.getClusterNodes();
for (String jedisAdr : jedisPools.keySet()){
JedisPool jedisPool = (JedisPool)jedisPools.get(jedisAdr);
Jedis jedis = jedisPool.getResource();
//后面是对Jedis的具体操作
}
由于调用的代码是跑在一个定时任务里,出现的异常情况是,前几次数据都可以正常获取,大约几分钟后,定时任务就没有运行了,也没有任何报错。
通过捕获JVM ThreadDump,发现有一个线程在Jedis jedis = jedisPool.getResource()这行一直waiting。
也就是这行代码长时间无响应阻塞了整个定时任务。很奇怪,如果无法获取Resource应该也要报错,可是什么也没有。
查询了官方文档,原来new JedisCluster(hpset, 30)中默认了MaxWaitMillis为-1。
BlockWhenExhausted:连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
MaxWaitMillis:获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常,小于零:阻塞不确定的时间, 默认-1
由于BlockWhenExhausted默认为true,连接耗尽时会阻塞到超时,但是MaxWaitMillis默认为-1,超时时间是一个不确定的时间,所以就一直阻塞着了。
修改配置后问题解决。