jedis+redis pipeline诡异的链接损坏、数据读取异常问题解决

文章目录

问题现象

栈溢出(不断的重连)

shell 复制代码
		at redis.clients.jedis.Connection.sendCommand(Connection.java:163)
        at redis.clients.jedis.Connection.sendCommand(Connection.java:154)
        at redis.clients.jedis.BinaryClient.auth(BinaryClient.java:815)
        at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:145)
        at redis.clients.jedis.Connection.sendCommand(Connection.java:163)
        at redis.clients.jedis.Connection.sendCommand(Connection.java:154)
        at redis.clients.jedis.BinaryClient.auth(BinaryClient.java:815)
        at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:145)

读取超时

未知响应

尝试读取损坏的链接

读取到的数据和自己要读的无关,导致空指针、类型转换错误,数据读取错乱



问题写法

对Redis操作封装了一个Redis类

同事对pipeline加了这个方法

使用的时候

java 复制代码
   public Map<String, AnswerModel> batchGetAnswersPipeline(List<String> answerIdList) {
        Map<String, AnswerModel> resultMap = new HashMap<>();
        try (Pipeline pipelined = redis.pipelined()) {
            List<Response<Map<String, String>>> responses = new ArrayList<>();
            for (String answerId : answerIdList) {
                String key = String.format(MOMENT_ANSWER_INFO, answerId);
                responses.add(pipelined.hgetAll(key));
            }
            pipelined.sync();
            for (Response<Map<String, String>> response : responses) {
                Map<String, String> map = response.get();
                AnswerModel answers = BeanUtil.mapToBean(map, AnswerModel.class);
                if (answers != null){
                    resultMap.put(answers.getAnswerId(), answers);
                }
            }
        } catch (Exception e) {
            log.error("执行batchGetAnswersPipeline发生异常, redis pipeline error", e);
            throw new CatVillageException();
        }
        return resultMap;
    }

问题分析

在redis这个工具类中调pipelined时获取一个Pinelined对象,而获取这个方法里用了try with ,with了一个jedis链接,当try结束时链接会被归还jedispool连接池。而返回的这个pipeline仍然在用这个链接,当其他线程去拿链接的时候可能拿到的正好是这个链接,导致多个线程共用一个链接,一个线程在执行pipeline多条命令,另一个线程也在用这个链接。而jedis底层执行命令的时候是使用的OutputStream流式去执行命令,使用二进制流读取结果。当出现这种线程不安全问题的时候,读取写入就会有问题。

修复

删除Redis工具类中的pipelined方法,使用getJedis方法获取链接对象,再获取管道Pineline对象,自行close管道,最后执行完释放管道,链接。

java 复制代码
public Map<String, QuestionModel> batchGetQuestionPipeline(List<String> questionIdList) {
        if (CollectionUtils.isEmpty(questionIdList)){
            return new HashMap<>();
        }
        Map<String, QuestionModel> resultMap = new HashMap<>();
        try (Jedis jedis = redis.getJedis()) {
            Pipeline pipelined = jedis.pipelined();
            List<Response<Map<String, String>>> responses = new ArrayList<>();

            for (String questionId : questionIdList) {
                String key = String.format(MOMENT_QUESTION_INFO, questionId);
                responses.add(pipelined.hgetAll(key));
            }

            pipelined.sync();

            for (Response<Map<String, String>> response : responses) {
                Map<String, String> map = response.get();
                QuestionModel question = convertFromMap(map);
                if (question != null) {
                    resultMap.put(question.getPostId(), question);
                }
            }
            pipelined.close();
        } catch (Exception e) {
            log.error("执行batchGetQuestionPipeline发生异常, redis pipeline error", e);
            throw new CatVillageException();
        }

        return resultMap;
    }

注意点

若jedis在3.7版本以下的版本也会有管道二进制读取异常问题,请升级到3.7.0+版本

相关推荐
Narutolxy4 小时前
DMZ层Nginx TLS 终止与安全接入配置实战20250829
redis·nginx·安全
三贝8 小时前
Java面试实战:Spring Boot微服务在电商场景的技术深度解析
spring boot·redis·微服务·分布式事务·java面试·电商系统·技术面试
zml_20159 小时前
docker 1分钟 快速搭建 redis 哨兵集群
linux·redis·docker·docker-compose
草履虫建模10 小时前
若依微服务一键部署(RuoYi-Cloud):Nacos/Redis/MySQL + Gateway + Robot 接入(踩坑与修复全记录)
redis·mysql·docker·微服务·云原生·nacos·持续部署
拾忆,想起15 小时前
Redis红锁(RedLock)解密:分布式锁的高可用终极方案
java·数据库·redis·分布式·缓存·性能优化·wpf
it_czz15 小时前
Flink Redis广播方案
大数据·redis·flink
ZLRRLZ16 小时前
【Docker/Redis】服务端高并发分布式结构演进之路
redis·docker·架构
叫我阿柒啊1 天前
Java全栈开发面试实战:从基础到微服务的深度探索
java·spring boot·redis·微服务·vue3·全栈开发·面试技巧
chen_note2 天前
Redis集群介绍——主从、哨兵、集群
redis·主从模式·集群模式·哨兵模式
拾忆,想起2 天前
Redis发布订阅:实时消息系统的极简解决方案
java·开发语言·数据库·redis·后端·缓存·性能优化