- N +

JedisClusterMaxRedirectionsException:Too many Cluster redirections

JedisClusterMaxRedirectionsException:Too many Cluster redirections原标题:JedisClusterMaxRedirectionsException:Too many Cluster redirections

导读:

Redis异常信息:redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too&...

文章目录 [+]

Redis异常信息:

redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:143) ~[jedis-3.0.1.g-RELEASE.jar:na]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:203) ~[jedis-3.0.1.g-RELEASE.jar:na]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:203) ~[jedis-3.0.1.g-RELEASE.jar:na]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:203) ~[jedis-3.0.1.g-RELEASE.jar:na]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:203) ~[jedis-3.0.1.g-RELEASE.jar:na]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:203) ~[jedis-3.0.1.g-RELEASE.jar:na]

Redis异常分析:

为什么会runWithRetries,为什么会有Too many Cluster redirections,下面从我们自身程序、JedisCluster源码说起,到如何解决这个问题,以及一些Jedis不足的地方。


1. 我们new一个JedisCluster时,JedisCluster会根据我们传进去的ip跟port建立一个JedisPool实例(JedisPool对应着redis集群的一个节点,假设这个ip跟port对应着Node5),并从这个JedisPool实例中得到一个jedis实例,然后这个jedis实例执行cluster nodes命令,最后我们就知道整个集群的节点情况,包括每个节点的ip跟port,每个节点负责处理的slot(槽位),JedisCluster会缓存这些信息到node pools(Map<String,JedisPool>),slots(Map<Integer,JedisPool>)。

注意:这里已经建立了所有节点对应的JedisPool实例,但这个JedisPool池里面暂时还没有Jedis实例(除了我们指定ip和prot的那个JedisPool里有一个Jedis实例)。

2. 当我们要处理一个key时,正常情况下,根据CRC16得到slot,然后根据这个slot从slots映射中得到对应的JedisPool,然后从这个Pool中得到Jedis(new Socket对象,设置KeepAlive,TcpNoDelay等参数,建立连接,设置read超时时间等),然后操作redis命令。但建立连接时,是有时间期限的,2秒钟,如果2秒钟内没有建立,返回JedisConnectionException异常,我们捕获异常,然后重试。这里的重试就是redirect retry了,重试的流程是不一样的,重试时会Collections.shuffle(pools),这里的pools就是上面的node pools,这时的pools已经乱序了,建立连接,然后访问,然后redis会返回move data指令,告知去哪个正确的节点上执行命令,然后jedis会更新slot到JedisPool的映射关系(我们会操作redis集群,进行线性扩展,槽位可能改变),这样就完成一次redirect了。然后jedis从新开始,试图得到connection,又超时,又redirect,5次一样,抛出一开始所说的异常。

3. redis为什么会连不上,我们知道redis是单线程的,你可以想象当有很多client试图连接redis服务器时,他们排队(其实不是)等待连接,回到我们的程序,当有一个CalculateBolt要连到Node1节点时,这时由于我们处理的数据的不均衡性,很有可能所有其他的CalculateBolt都在这个Node1节点上排队,再加上网络的延迟等等因素,超时了,下次redirect后,还是超时,好,异常抛出。

4. 我们知道异常抛出的原因后,其实我们有很多fix方法的,如建立JedisPool时,先实例化一个到redis节点的jedis实例(jedis实例里有socket连接),但现在只有我们指定ip跟port的那个JedisPool有一个jedis实例,其他的是没有的,要在第一次访问时建立。当然最简单的当然是增大超时时间了,但变态的是,这个超时时间在jedis里竟然是硬编码,Protocol.DEFAULT_TIMEOUT,你要改,下载源码,修改,重新编译打包,我不清楚为什么这个是硬编码,也许jedis作者认为2s已经是很长的时间了,不可能连接超时了。

5. 我是用上面第二点,增大超时时间,幸好有github,幸好有maven,改起来也算快速。但也算是Jedis需要改进的地方了。Jedis还需要改进的是它的异常捕获,很垃圾。举个例子,上面的异常中的71行其实是JedisConnectionException异常,但这个异常的栈信息却丢失了,其实我们知道最先抛出的应该是一个SocketTimeoutException,但这个RuntimeException在外面的上上层方法中,被捕获了,catch(Exception e),然后重新抛出了一个JedisConnectionException,但这个异常信息里却没有原先的异常栈信息,导致异常信息丢失。


本文标题:JedisClusterMaxRedirectionsException:Too many Cluster redirections
本文链接:http://www.kyjszj.com/wdzl/138.html
作者授权:除特别说明外,本文由 开源技术之家 原创编译并授权 开源技术之家 刊载发布。
版权声明:本文不使用任何协议授权,您可以任何形式自由转载或使用。

有好的文章希望我们帮助分享和推广,猛戳这里我要投稿

返回列表
上一篇:
下一篇:

发表评论中国互联网举报中心

快捷回复:

    评论列表 (暂无评论,共589人参与)参与讨论

    还没有评论,来说两句吧...