【问题分析】配置Redisson后某些redis命令出现StackOverFlow原因分析

一、场景及代码

1.场景

卡内编号全量下发黑白名单时 如果redis中的全量名单被删除/重启后消失 当设备访问接口时 会初始化一份全量黑白名单到缓存
而这段代码执行时间太长(25分钟)

在这里插入图片描述

2.

报错如下

在这里插入图片描述

代码如下

@GetMapping("/test")
    public void test(){
        long before = System.currentTimeMillis();
        // 获取底层的RedisConnection
        List<DdCardCode> cardCodeList = cardCodeComponent.list();
        List<List<DdCardCode>> cardCodeListList = CollUtil.split(cardCodeList, 32);
        List<Long> integerList = cardCodeListList.stream().map(e -> {
            StringBuilder sb = new StringBuilder();
            for (DdCardCode ddCardCode : e) {
                sb.append(ddCardCode.getRecFlag());
            }

            return Long.parseLong(String.valueOf(sb),2);

        }).collect(Collectors.toList());
        long after = System.currentTimeMillis();

        log.error("数据库100w条数据到缓存所需要的时间"+ (after-before)/1000 + "s");

        long redisBefore = System.currentTimeMillis();
        byte[] keyBytes = "test111".getBytes();

        redisTemplate.execute((RedisCallback<Object>) connection -> {
            BitFieldSubCommands.BitFieldSetBuilder builder = BitFieldSubCommands.create().set(BitFieldSubCommands.BitFieldType.unsigned(32));
            for (int i = 0; i < integerList.size(); i++) {
                long offset = i * 32;
                BitFieldSubCommands subCommand = builder.valueAt(offset).to(integerList.get(i));
                connection.bitField(keyBytes, subCommand);
            }


            return "success";

        });



        long redisAfter = System.currentTimeMillis();

        log.error("同步100w条数据到缓存所需要的时间"+ (redisAfter-redisBefore)/1000 + "s");
    }

二、思路

1.是代码的问题还是环境的问题?

(1)在统一身份认证的项目中 运行了同样的命令 可以成功
(2)在redis的控制台中直接执行, 可以成功

在这里插入图片描述

推断为环境问题

2.data-redis被redisson封装

在这里插入图片描述

3.身份核验中配置了Redissson而没有引入springboot-data-redis 有没有可能是这个原因?

(1)百度找了一下有没有类似问题(不用看英文) 大概说了原因和解决方案 但没debug代码的过程
https://blog.csdn.net/qq_38783304/article/details/129042816
(2)github上找到Redisson的开源项目 看看issue中有没有同样的问题
在这里插入图片描述

有同样的问题 并且作为一个bug被fixed了
在这里插入图片描述

(3)在3.15.6版本中被更新 理论上将目前的版本升级到这个版本 就没问题了

在这里插入图片描述

(4)根据commit的标题Missed implementation of few methods in Spring Data’s RedissonConnection知道大约是连接器的问题 根据栈溢出的报错看一下源码

三、源码分析

1.报错的代码

调用DefaultedRedisConnection中的bitField命令(已被废弃)
在这里插入图片描述

f7进入bitField时,自己调用了自己 导致了栈溢出
在这里插入图片描述

2.查看调用处 bitField 抽象方法有4个实现类

在这里插入图片描述

3.到此为止 无法得知 springboot的自动配置使用的哪个实现类

redisson提供了spring.factories文件,文件中的类被优先加载
在这里插入图片描述

配置类如下
在这里插入图片描述

4.代码中redis回调的入参是RedisConnection RedisConnection有很多实现类 实际使用哪个要根据RedisConnectionFactory来判断

在这里插入图片描述
在这里插入图片描述

5.RedissonConnectionFactory的配置

重写了getConnection方法 返回了RedissonConnection

在这里插入图片描述

6.所以connection.bitField方法应该是调用的RedissonConnection被重写的方法

在这里插入图片描述

7.但低版本的RedissonConnection没有重写 故调用了RedisConnection的默认实现接口DefaultedRedisConnection 造成了栈溢出(以下命令都没被重写)

bitField(byte[] key, BitFieldSubCommands subCommands)
exists(byte[]... keys)
touch(byte[]... keys)
encodingOf(byte[] key)
idletime(byte[] key)
refcount(byte[] key)
bitPos(byte[] key, boolean bit, org.springframework.data.domain.Range<Long> range)
restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolean replace)

8.而在新版本中RedissonConnection中 bitfield命令被重写 就不会有这种情况了

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值