当前位置:   article > 正文

淘淘商城第38讲——使用Jedis操作集群版Redis时,报错:redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException

淘淘商城第38讲——使用Jedis操作集群版Redis时,报错:redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException

问题描述

今天碰到一个问题,那就是在使用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

下面我给出了我的测试代码,你能看懂我写的啥吗?
在这里插入图片描述
这里,我还得说明一点,我使用的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);
}
  • 1
  • 2
  • 3

当我们在使用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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

所以咱们要分析的重点代码应该在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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

看了以上runWithRetries方法之后,我们大概是知道报错原因了,就是redirections这个参数搞的鬼!那么redirections参数到底应该怎么理解呢?该参数代表的是节点调转次数,实际上也可以看做是重试次数,也就是说连接集群中某个节点失败后,重连其他节点的次数。

解决方案

初始化JedisCluster时,设定构造JedisCluster对象的maxRedirections参数,如下图所示。
在这里插入图片描述
运行以上测试方法,虽然需要等待很长时间,Eclipse控制台才打印出结果,但是没有报其他连接重试次数太多的异常了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/638474
推荐阅读
相关标签
  

闽ICP备14008679号