Redis 异常三连环

请添加图片描述

本文针对一种特殊情况下的Reids连环异常,分别是下面三种异常:

  1. NullPointerException: Cannot read the array length because “arg” is null
  2. JedisDataException: ERR Protocol error: invalid bulk length
  3. JedisConnectionException: Unexpected end of stream.

先说个普遍适用的处理错误经验,当你发现日志最新出现的某个错误的时候,多往前翻翻日志,看看更早的时候有没有其他的错误,很多时候的错误都在更早的时候出现,这个错误看似不影响后续的使用,但是埋下了很多坑,等待时机合适就会爆发出来。如果你只关注最后产生直接感受的这个错误,很可能走弯路,百思不得其解。

这个问题还频繁出现在分页插件PageHelper中,如果你有不规范的分页调用,例如下面这种情况:

PageHelper.start(1, 10);
if(满足条件) {result = mapper.select(params);
} else {result = emptyList();
}

调用PageHelper时,你设置的分页信息已经绑定到线程,当满足条件执行 mybatis 查询时,分页信息会被消费并清除,当不满足条件时,分页信息仍然绑定在线程上,相当于埋了个雷,等其他请求再使用这个线程时,只要有查询,就会消费这里的分页信息,你的感受就是我没有调用分页,为什么查询被分页了?分页插件文档有 安全调用 的多种方式,而且后续版本为了方便识别这种错误,还支持在消费分页信息时,打印设置分页参数时的堆栈信息,通过堆栈信息可以识别不安全的调用方式。很多人吐槽PageHelper不安全,实际上都是不正确使用导致的,如果乱用,Java安全吗,把系统删了怎么办?JDBC安全吗,把库删了怎么办?

回归正题,某个项目在测试环境没有用Redis缓存,在线上环境配置了Redis缓存,之后就遇到了缓存的问题,从日志能看到莫名其妙的 Unexpected end of stream.ERR Protocol error: invalid bulk length 错误信息,以及更靠前有明确其他错误提示的 java.io.NotSerializableException: com.example.SimpleValue,并没有看到上面列的第一个异常。使用 arthas 监控时发现错误2和3时操作的 key 和错误1时完全不相关,所以前期处理的重点是错误2和3,这两个错误执行过程看着都是正常的,所以按照经验先解决序列化的问题,解决这个问题后如何问题解决就说明是序列化导致的后续两个问题。

网上搜后两个问题时,大多数答案都不正确,但是在CSDN看到了一个答案:

  • 关于spring-data操作redis报invalid-bulk-length的错误分析

这里通过分析源码找到了问题的原因,还提供了一个复现的例子,例子有点麻烦,所以我写了一个更简单的复现三个错误的例子:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;import java.nio.charset.StandardCharsets;public class RedisErrorTest {public static void main(String[] args) {JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");try (Jedis jedis = pool.getResource()) {try {jedis.set("parent".getBytes(StandardCharsets.UTF_8), null);} catch (Exception e) {e.printStackTrace();}try {jedis.set("hello", "world");} catch (Exception e) {e.printStackTrace();}try {String val = jedis.get("hello");System.out.println(val);} catch (Exception e) {e.printStackTrace();}}pool.close();}
}

错误的重点是 jedis.set("parent".getBytes(StandardCharsets.UTF_8), null); 这里设置了 null,这会导致下面的异常:

java.lang.NullPointerException: Cannot read the array length because "arg" is nullat redis.clients.jedis.Protocol.sendCommand(Protocol.java:99)at redis.clients.jedis.Protocol.sendCommand(Protocol.java:84)at redis.clients.jedis.Connection.sendCommand(Connection.java:127)at redis.clients.jedis.BinaryClient.set(BinaryClient.java:110)at queue.RedisErrorTest.main(RedisErrorTest.java:17)

这个异常会导致 jedis.set 下面的代码被跳过:

public String set(final byte[] key, final byte[] value) {checkIsInMultiOrPipeline();client.set(key, value);//下面代码没有被执行return client.getStatusCodeReply();
}public String getStatusCodeReply() {//因此不会执行 flushflush();pipelinedCommands--;final byte[] resp = (byte[]) readProtocolWithCheckingBroken();if (null == resp) {return null;} else {return SafeEncoder.encode(resp);}
}protected void flush() {try {//这里也就无法执行了outputStream.flush();} catch (IOException ex) {broken = true;throw new JedisConnectionException(ex);}
}

outputStream.flush() 的代码如下:

@Override
public void flush() throws IOException {flushBuffer();out.flush();
}
private void flushBuffer() throws IOException {if (count > 0) {out.write(buf, 0, count);//这里不执行count = 0;}
}

由于 count 没有置0,等下个命令执行时会在上面未完成命令基础上继续写入。

继续使用这个jedis连接操作 jedis.set("hello", "world") 时,看着很正常,但是会报错:

redis.clients.jedis.exceptions.JedisDataException: ERR Protocol error: invalid bulk lengthat redis.clients.jedis.Protocol.processError(Protocol.java:127)at redis.clients.jedis.Protocol.process(Protocol.java:161)at redis.clients.jedis.Protocol.read(Protocol.java:215)at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239)at redis.clients.jedis.Jedis.set(Jedis.java:121)at queue.RedisErrorTest.main(RedisErrorTest.java:22)

此时当前连接已经不能正常响应了,后续再 jedis.get("hello") 就会报错:

redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:199)at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)at redis.clients.jedis.Protocol.process(Protocol.java:151)at redis.clients.jedis.Protocol.read(Protocol.java:215)at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:259)at redis.clients.jedis.Connection.getBulkReply(Connection.java:248)at redis.clients.jedis.Jedis.get(Jedis.java:153)at queue.RedisErrorTest.main(RedisErrorTest.java:27)

这个错误信息是因为没有收到服务器端响应(in.read() == -1)导致的,后续发送的所有命令都收不到响应,都会是这个错误。

这个错误和前面普遍适用的经验一样,和分页插件遇到的问题类似,当你使用不对埋下雷时,解决炸雷是解决不了问题的,解决了埋雷的问题才能从根本解决问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/341382.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++ - list常用接口模拟实现

文章目录 一、模拟list类的框架二、函数接口实现1、迭代器接口2、常用删除、插入接口3、常用其他的一些函数接口4、默认成员函数 一、模拟list类的框架 1、使用带哨兵的双向链表实现。 2、链表结点&#xff1a; // List的结点类 template<class T> struct ListNode {Li…

Docker之路(三)docker安装nginx实现对springboot项目的负载均衡

Docker之路&#xff08;三&#xff09;dockernginxspringboot负载均衡 前言&#xff1a;一、安装docker二、安装nginx三、准备好我们的springboot项目四、将springboot项目分别build成docker镜像五、配置nginx并且启动六、nginx的负载均衡策略七、nginx的常用属性八、总结 前言…

Android WebView上传文件/自定义弹窗技术,附件的解决方案

安卓内核开发 其实是Android的webview默认是不支持<input type"file"/>文件上传的。现在的前端页面需要处理的是&#xff1a; 权限 文件路径AndroidManifest.xml <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"/&g…

计算机网络ppt和课后题总结(上)

试在下列条件下比较电路交换和分组交换。要传送的报文共 x(bit)。从源点到终点共经过 k 段链路&#xff0c;每段链路的传播时延为 d(s)&#xff0c;数据率为 b(b/s)。在电路交换时电路的建立时间为 s(s)。在分组交换时分组长度为 p(bit)&#xff0c;且各结点的排队等待时间可忽…

数据觉醒时代,以“存力”激活数据资产潜能

近日&#xff0c;质汇“杨数浦”主题研讨会首场活动在杨浦滨江举行&#xff0c;是杨浦区筹推进数字经济与城市数字化发展的一大重要举措&#xff0c;各行业协会、科研院所及企业代表参加活动&#xff0c;共商行业发展新机遇。活动现场&#xff0c;优刻得董事长兼CEO季昕华被授予…

Mysql的两种安装方式

文章目录 第一种安装方式国内镜像库下载解压安装配置环境变量初始化数据库安装mysql登录mysql设置root密码退出登录假如忘记了密码&#xff0c;重置密码的步骤1、步骤一&#xff1a;停止 MySQL 服务2、步骤二&#xff1a;使用安全模式启动 MySQL3、步骤三&#xff1a;重置密码4…

大数据之Schedule调度错误(一)

当我们在利用ooize发起整个任务的调度过程中,如果多个调度任务同时运行并且多个调度任务操作了相同的表,那么就会出现如下的错误关系: Invalid path hdfs://iZh5w01l7f8lnog055cpXXX:8000/user/admin/xxx: No files matching path hdfs://iZh5w01l7f8lnog055cpXXX:8000/user/ad…

线性表、单循环链表学习

背景&#xff1a; 单循环链表是一种链表结构&#xff0c;其中最后一个节点指向第一个节点&#xff0c;从而形成一个环。 实现单循环链表通常涉及节点定义、插入节点、删除节点以及遍历链表等操作。以下是如何在Python中实现单循环链表的示例。 单循环链表的实现 1. 节点类 …

掌握ChatGPT的正确打开方式

引言 随着人工智能技术的飞速发展&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域取得了显著的突破。其中&#xff0c;聊天生成预训练变换器&#xff08;ChatGPT&#xff09;作为一种新型的对话式AI模型&#xff0c;引起了广泛关注。本文将详细介绍ChatGPT的正确使用…

使用html2canvas和jspdf导出pdf包含跨页以及页脚

首先要下载两个文件&#xff0c;一个为html2canvas.min.js&#xff0c;另一个是jspdf.umd.min.js这两个文件分别下载的地址我也附录上&#xff0c;都在官网git&#xff1a; html2canvas.min.js: https://html2canvas.hertzen.com/dist/html2canvas.min.js jspdf.umd.min.js: …

vue-pdf 部分中文显示错误,第二次打开是空白,解决方法

首先鸣谢 1. https://blog.csdn.net/m0_71537867/article/details/131614868?spm1001.2014.3001.5506 2. https://blog.csdn.net/weixin_43763952/article/details/133769647 3. https://github.com/FranckFreiburger/vue-pdf/issues/229 4. https://blog.csdn.net/weixin_449…

康谋技术 | 自动驾驶:揭秘高精度时间同步技术(一)

众所周知&#xff0c;在自动驾驶中&#xff0c;主要涵盖感知、规划、控制三个关键的技术层面。在感知层面&#xff0c;单一传感器采集外界信息&#xff0c;各有优劣&#xff0c;比如摄像头采集信息分辨率高&#xff0c;但是受外界条件影响较大&#xff0c;一般缺少深度信息&…

推荐一个免费的相亲工具

推荐一个免费的相亲工具&#xff0c;步骤如下&#xff1a; 1&#xff09;微信里面搜索公众号“光源桥”&#xff0c;并关注 2&#xff09;输入搜索条件进行搜索对象 例如下面搜索&#xff1a;

Pinterest免费引流实操演示

这篇文章中你将了解到 1.Pinterest网站介绍&#xff0c;用户群体&#xff0c;适合做什么品类。 2.现在的商家都在上面做什么&#xff1f;案例展示。 3.我们在这个站免费引流要怎么做以及注意事项。 1.Pinterest网站介绍&#xff0c;用户群体&#xff0c;适合做什么品类。 P…

【Excel】Excel中将日期格式转换为文本格式,并按日期显示。

【问题需求】 在使用excel进行数据导入的过程中&#xff0c; 有的软件要求日期列必须是文本格式。 但是直接将日期列的格式改为文本后&#xff0c;显示一串数字&#xff0c;而不按日期显示。 进而无法导入使用。 【解决方法】 使用【TXET】函数公式进行处理&#xff0c; 在单…

百度ERNIE系列预训练语言模型浅析(4)-总结篇

总结&#xff1a;ERNIE 3.0与ERNIE 2.0比较 &#xff08;1&#xff09;相同点&#xff1a; 采用连续学习 采用了多个语义层级的预训练任务 &#xff08;2&#xff09;不同点&#xff1a; ERNIE 3.0 Transformer-XL Encoder(自回归自编码), ERNIE 2.0 Transformer Encode…

泛微开发修炼之旅--05Ecode入门讲解、接口调用源码示例及踩坑总结

文章链接&#xff1a;泛微开发修炼之旅--05Ecode入门讲解、接口调用源码示例及踩坑总结

操作系统复习-linux的进程管理

linux的进程管理 linux进程的相关概念 进程的类型 前台进程 前台进程就是具有终端&#xff0c;可以和用户交互的进程&#xff0c;会占用终端shell&#xff0c;不可以输入其他的命令。 后台进程 前台进程就是具有终端&#xff0c;可以和用户交互的进程。 不会占用终端shell&a…

数据分析必备:一步步教你如何用Pandas做数据分析(17)

1、Pandas 连接 Pandas 连接的操作实例 Pandas具有与SQL等关系数据库非常相似的功能齐全的高性能内存中连接操作。 Pandas提供单个功能merge作为DataFrame对象之间所有标准数据库联接操作的入口点 pd.merge(left, right, howinner, onNone, left_onNone, right_onNone,left_i…

实战|基于YOLOv10与MobileSAM实现目标检测与分割【附完整源码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…