赞
踩
今天碰到一个问题,那就是在使用Jedis操作集群版Redis时,报了一个如下这样一个错误,具体错误信息记录如下:
redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:34)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:67)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:83)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:67)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:83)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:67)
at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:29)
at redis.clients.jedis.JedisCluster.get(JedisCluster.java:91)
at com.taotao.test.jedis.JedisTest.testJedisCluster(JedisTest.java:61)
下面我给出了我的测试代码,你能看懂我写的啥吗?
这里,我还得说明一点,我使用的Redis是redis-3.2.3.tar.gz
这个版本,使用的Jedis是jedis-2.7.2.jar
这个版本。
报了这个异常之后,我试图想找到报错原因,于是我在网上找了好多的文章。终于,皇天不负有心人,这个报错原因我想我是给找出来了。这还得从Jedis的源码说起。
先从Jedis的源码中找到这个异常,这个异常是在JedisClusterCommand类中,如下所示。
if (redirections <= 0) {
throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections? key=" + key);
}
当我们在使用Jedis操作集群版Redis时,会使用到JedisCluster类,该类中所有API的调用方式都类似下面这样:
public String set(final String key, final String value) {
return new JedisClusterCommand<String>(connectionHandler, maxRedirections) {
@Override
public String execute(Jedis connection) {
return connection.set(key, value);
}
}.run(key);
}
所以咱们要分析的重点代码应该在JedisClusterCommand这个类里,重要代码如下:
public T run(int keyCount, String... keys) { if (keys == null || keys.length == 0) { throw new JedisClusterException("No way to dispatch this command to Redis Cluster."); } if (keys.length > 1) { int slot = JedisClusterCRC16.getSlot(keys[0]); for (int i = 1; i < keyCount; i++) { int nextSlot = JedisClusterCRC16.getSlot(keys[i]); if (slot != nextSlot) { throw new JedisClusterException("No way to dispatch this command to Redis Cluster " + "because keys have different slots."); } } } return runWithRetries(SafeEncoder.encode(keys[0]), this.redirections, false, false); } private T runWithRetries(byte[] key, int redirections, boolean tryRandomNode, boolean asking) { // 问题应该出自这里,应该是redirections参数的值小于等于0,才导致抛出了下面这个异常 if (redirections <= 0) { JedisClusterMaxRedirectionsException exception = new JedisClusterMaxRedirectionsException( "Too many Cluster redirections? key=" + SafeEncoder.encode(key)); throw exception; } Jedis connection = null; try { if (asking) { // TODO: Pipeline asking with the original command to make it // faster.... connection = askConnection.get(); connection.asking(); // if asking success, reset asking flag asking = false; } else { if (tryRandomNode) { connection = connectionHandler.getConnection(); } else { connection = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)); } } return execute(connection); } catch (JedisConnectionException jce) { if (tryRandomNode) { // maybe all connection is down throw jce; } // release current connection before recursion releaseConnection(connection); connection = null; // retry with random connection return runWithRetries(key, redirections - 1, true, asking); } catch (JedisRedirectionException jre) { // if MOVED redirection occurred, if (jre instanceof JedisMovedDataException) { // it rebuilds cluster's slot cache // recommended by Redis cluster specification this.connectionHandler.renewSlotCache(connection); } // release current connection before recursion or renewing releaseConnection(connection); connection = null; if (jre instanceof JedisAskDataException) { asking = true; askConnection.set(this.connectionHandler.getConnectionFromNode(jre.getTargetNode())); } else if (jre instanceof JedisMovedDataException) { } else { throw new JedisClusterException(jre); } return runWithRetries(key, redirections - 1, false, asking); } finally { releaseConnection(connection); } }
看了以上runWithRetries方法之后,我们大概是知道报错原因了,就是redirections这个参数搞的鬼!那么redirections参数到底应该怎么理解呢?该参数代表的是节点调转次数,实际上也可以看做是重试次数,也就是说连接集群中某个节点失败后,重连其他节点的次数。
初始化JedisCluster时,设定构造JedisCluster对象的maxRedirections参数,如下图所示。
运行以上测试方法,虽然需要等待很长时间,Eclipse控制台才打印出结果,但是没有报其他连接重试次数太多的异常了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。