JedisRedirectionException:Too many Cluster redirections

最近用Jedis作为redis客户端,经常碰到这个问题,程序刚启动,没几秒钟,就出现这个问题:

redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:38)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:86)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:71)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:86)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:71)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:86)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:71)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:86)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:71)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:86)
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:71)
at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:32)
at redis.clients.jedis.JedisCluster.hsetnx(JedisCluster.java:325)

一开始怀疑redis集群没搭好,网络不稳定,程序写的不好导致,排查了很长时间,最后还是从错误log去排查,为什么会runWithRetries,为什么会有Too many Cluster redirections,下面从我们自身程序、JedisCluster源码说起,到如何解决这个问题,以及一些Jedis不足的地方。

1. 我们系统用jstorm+redis集群对数据进行处理,并导出统计结果。Spout每分钟要分发100万条记录给下游的CalculateBolt(50个Task,在不同的节点上运行),CalculateBolt对每条记录进行处理,与redis现有数据比对,更新计数器等等。最后由OutputBolt导出统计结果。在每个CalculateBolt中都有一个JedisCluster全局变量(private JedisCluster jedisCluster),并在prepare方法中初始化,在execute方法中处理记录。

2. 我们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实例)。

3. 当我们要处理一个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次一样,抛出一开始所说的异常。

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

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

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

转载于:https://my.oschina.net/lzm3/blog/914797

### CLUSTER概念 #### 什么是集群(Cluster) 在IT领域,集群(Cluster)是指一组协同工作的计算机节点,这些节点通过高速网络互联并作为一个单一系统来管理和操作。集群的主要目的是提高系统的性能、可靠性和可用性。 集群技术被广泛应用在不同的场景中,包括但不限于高性能计算(HPC),数据库管理系统(DBMS),Web服务器等领域。对于特定的任务需求,集群可以通过负载均衡的方式分发任务到多个节点上执行,从而显著提升处理速度和效率[^1]。 #### 集群的工作原理 在一个典型的集群环境中: - **高可用性**:当某个成员失败时,其他成员接管其工作负荷而不中断服务; - **资源共享**:所有成员共享相同的文件系统或其他资源池; - **分布式处理**:数据或作业可以在不同机器之间划分开来完成更高效的运算过程; 为了实现上述功能,通常会采用心跳检测机制来监控各个节点的状态,并利用专门的软件工具来进行故障转移配置与管理。 #### Redis集群实例 以Redis为例,它支持构建一个分布式的键值存储解决方案——即所谓的“Redis Cluster”。在这个体系结构下,客户端请求会被路由至相应的主节点(master node), 而副本(replica nodes)则用于保障数据冗余及读取扩展能力。然而,在实际部署过程中可能会遇到诸如`JedisClusterException: CLUSTERDOWN The cluster is down` 或者 `JedisClusterMaxRedirectionsException: Too many Cluster redirections` 这样的异常情况,这表明集群内部出现了通信障碍或者是重定向次数超过了允许的最大值等问题[^3][^4]。 ```java // Java代码片段展示如何正确初始化Jedis连接池 import redis.clients.jedis.*; public class JedisExample { public static void main(String[] args){ Set<String> nodes = new HashSet<>(); nodes.add("localhost:7000"); nodes.add("localhost:7001"); try (JedisSlotBasedConnectionHandler connectionHandler = new JedisCluster(nodes).getBinaryJedisCluster().getConnectionHandler()) { // 使用connectionHandler进行操作... } catch(Exception e){ System.err.println(e.getMessage()); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值