Spring-data-redis+Jedis+Redis集群导致的阻塞问题

一、现象

1、项目上使用三个队列来缓存数据,发现其中有一个队列有很多数据,但是消费却非常慢

2、代码使用redisTemplate.opsForList().rightPop 来获取队列里面的数据,这个命令对应的Redis命令是bRPop

3、通过调用链查看,发现brpop命令执行的耗时非常长,最大响应时间达到2秒多

4、在Redis客户端直接使用BRPOP course 30获取数据,执行非常快,并没有感觉到阻塞

 

二、分析过程

1、BRPOP

是列表的阻塞式(blocking)弹出原语,它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。

2、测试环境是否可复现

通过测试环境测试,问题依旧

3、通过JedisCluster进行测试

采用JedisCluster直连的方式,发现并没有阻塞的迹象

4、源码分析

4.1、DefaultListOperations.rightPop()

 

4.2、JedisClusterConnection.bRPop

4.3、ClusterCommandExecutor.executeMuliKeyCommand

在这里我们看到了这个方法其实内部是异步执行的

4.4、executor的创建

4.5、ThreadPoolTaskExecutor.corePoolSize

大家发现了没有,corePoolSize是写死的1,并且在4.4、executor的创建的地方并没有修改它

4.6、能改变corePoolSize的大小吗?

卧槽,这有点出乎我的意料,居然没找到任何地方可以修改它的值

4.7、到此就能解释了为什么有一个队列里面有数据,却消费的非常慢的原因了,其实是另外两个队列里面没数据导致的阻塞,单线程执行,另外两个队列就把这个有数据的队列的阻塞住了。
三、影响范围

1、ClusterCommandExecutor里面使用executor的方法:executeCommandAsyncOnNodes、executeMuliKeyCommand

2、ClusterCommandExecutor.executeCommandAsyncOnNodes调用的地方

3、ClusterCommandExecutor.executeCommandOnAllNodes调用的地方

4、ClusterCommandExecutor.executeMuliKeyCommand调用的地方

红色箭头标识的地方,就是本次问题发生的地方,一头冷汗,我觉得最危险的地方应该是del命令+blpop/brpop,如果这样组合起来,都不知道为什么del命令删不掉键了。

四、解决方案

1、试试高版本的spring-data-redis?

我们现在使用的是spring-data-redis-1.8.18.RELEASE.jar,本来以为高版本的会修复这个问题,然并卵

2、使用Redisson替换Jedis问题解决

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值