文档章节

JedisRedirectionException:Too many Cluster redirections

黑_麦
 黑_麦
发布于 2017/06/05 15:35
字数 1252
阅读 217
收藏 0

最近用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,但这个异常信息里却没有原先的异常栈信息,导致异常信息丢失。

本文转载自:http://blog.csdn.net/xiansky2015/article/details/51597405

共有 人打赏支持
黑_麦
粉丝 0
博文 5
码字总数 315
作品 0
昌平
程序员
私信 提问
jedis 2.7集群异常

在使用jedis2.7测试redis集群的时候出现异常: Exception in thread "main" redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections? at red......

小心有诈
2015/04/08
861
1
Redis 3.0.7 和 3.2.0 rc2 发布

Redis 3.0.7 和 3.2.0 rc2 发布,3.2.0 rc2 更新如下: --[ Redis 3.2.0 RC2 (version 3.1.102) ] Release date: 25 jan 2016 Upgrade urgency MODERATE: this release fixes important Red......

oschina
2016/01/26
2.6K
4
美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题

转载请注明出处哈:http://carlosfu.iteye.com/blog/2254154 由于演讲时间有限,有关Redis-Cluster,演讲者没做太多介绍,简单的介绍了一些Redis-Cluster概念作用和遇到的两个问题,我们在Red...

lirulei90
01/05
0
0
Jedis cluster命令执行流程剖析

在Redis Cluster集群模式下,由于key分布在各个节点上,会造成无法直接实现mget、sInter等功能。因此,无论我们使用什么客户端来操作Redis,都要考虑单一key命令操作、批量key命令操作和多节...

九州暮云
2017/11/02
0
0
【Spring Cloud】Redis缓存接入监控、运维平台CacheCloud

CacheCloudCacheCloud提供一个Redis云管理平台:实现多种类型(Redis Standalone、Redis Sentinel、Redis Cluster)自动部署、解决Redis实例碎片化现象、提供完善统计、监控、运维功能、减少运...

冷冷gg
01/02
0
2

没有更多内容

加载失败,请刷新页面

加载更多

docker快速搭建几个常用的第三方服务

本次和大家分享的内容是使用docker快速搭建工作中常用的第三方的服务,对于有一些互联网背景的公司来说,以下几个服务都是很需要的:redis,rabbit,elasticsearch; 如果想学习Java工程化、...

编程SHA
23分钟前
3
0
我的Linux系统九阴真经

在今天,互联网的迅猛发展,科技技术也日新月异,各种编程技术也如雨后春笋一样,冒出尖来了。各种创业公司也百花齐放百家争鸣,特别是针对服务行业,新型互联网服务行业,共享经济等概念的公...

linuxprobe16
32分钟前
10
0
Dubbo标签解析详解

在Spring继承dubbo时,会使用dubbo自定义的标签来定义相关的属性,常见的标签有<dubbo:application/>,<dubbo:registry/>,<dubbo:service/>等。对于这些标签的解析,dubbo都是使用的统一的方...

爱宝贝丶
37分钟前
5
0
网站彩蛋

图形类彩蛋 知乎 https://www.zhihu.com/ 想来知乎工作?请发送邮件到 jobs@zhihu.com 天猫 https://www.tmall.com/ 喵~ 加入我们吧 http://tb.cn/iS8NBOy 超级课程表 http://www.super.cn/...

临江仙卜算子
44分钟前
9
0
ThreadLocal父子线程之间的数据传递问题

一、问题的提出 在系统开发过程中常使用ThreadLocal进行传递日志的RequestId,由此来获取整条请求链路。然而当线程中开启了其他的线程,此时ThreadLocal里面的数据将会出现无法获取/读取错乱...

nonnetta
53分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部