P0级事故,项目组慌的一批! 上

简介: P0级事故,项目组慌的一批! 上


一、前言

最近项目的生产环境遇到一个奇怪的问题:

现象 :每天早上客服人员在后台创建客服事件时,都会创建失败 。当我们重启 这个微服务后,后台就可以正常创建了客服事件了。到第二天早上又会创建失败,又得重启这个微服务才行。

初步排查 :创建一个客服事件时,会用到 Redis 的递增操作来生成一个唯一的分布式 ID 作为事件 id。代码如下所示:

return redisTemplate.opsForValue().increment("count", 1);

而恰巧每天早上这个递增操作都会返回 null,进而导致后面的一系列逻辑出错,保存客服事件失败。当重启微服务后,这个递增操作又正常了。

那么排查的方向就是 Redis 的操作为什么会返回 null 了,以及为什么重启就又恢复正常了。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

二、排查

根据上面的信息,我们先来看看 Redis 的自增操作在什么情况下会返回 null。

2.1 推测一

根据重启后就恢复正常,我们推测晚上执行了大量的 job,大量 Redis 连接未释放,当早上再来执行 Redis 操作时,执行失败。重启后,连接自动释放了。

但是其他有使用到 Redis 的业务功能又是正常的,所以推测一的方向有问题,排除

2.2 推测二

可能是 Redis 事务造成的问题。这个推测的依据是根据下面的代码来排查的。

直接看 redisTemplate 递增的方法 increment,如下所示:

官方注释已经说明什么情况下会返回 null:

  • 当在 pipeline(管道)中使用这个 increment 方法时会返回 null。
  • 当在 transaction(事务)中使用这个 increment 方法时会返回 null。

事务 提供了一种将多个命令打包,然后一次性、有序地执行机制.

多个命令会被入列到事务队列中,然后按先进先出(FIFO)的顺序执行。

事务在执行过程中不会被中断,当事务队列中的所有命令都被执行完毕之后,事务才会结束。(内容来自 Redis 设计与实现)

继续看代码,发现在操作 Redis 的 ServiceImpl 实现类的上面添加了一个 @Transactional 注解,推测是不是这个注解影响了 Redis 的操作结果。

2.3 验证推测二

如下面的表格所示,第二行中没有添加 Spring 的事务注解 @Transactional时,执行 Redis 的递增命令肯定是正常的,而接下来要验证的是表格中的第一行:加了 @Transactional 是否对 Redis 的命令有影响。

image.png

为了验证上面的推论,我写了一个 Demo 程序。

Controller 类 ,定义了一个 API,用来模拟前端发起的请求:

Service 实现类 ,定义了一个方法,用来递增 Redis 中的 count 键,每次递增 1,然后返回命令执行后的结果。而且这个 Service 方法加了@Transactional 注解。

Postman 测试下,发现每发一次请求,count 都会递增 1,并没有返回 null。

然后到 Redis 中查看数据,count 的值也是递增后的值 38,也不是 null。

通过这个实验说明在 @Transactional 注解的方法里面执行 Redis 的操作并不会返回 null,结论我记录到了表格中。

所以说上面的推论不成立(加了 @Transactional 注解并不影响),到这里线索似乎断了

2.4 推测三

然后跟当时做这块功能的开发人员说明了情况,告诉他可能是 Redis 事务造成的,然后问有没有其他同学在凌晨执行过 Redis 事务相关的 Job。

他说最近有同事加过 Redis 的事务功能,在凌晨执行 Job 的时候用到事务。我将这位同事加的代码简化后如下所示:

下面是针对这段代码的解释,简单来说就是开启事务,将 Redis 命令顺序放到一个队列中,然后最后一起执行,且保证原子性。

setEnableTransactionSupport表示是否开启事务支持,默认不开启。

难道开启了 Redis 事务,还能影响 Spring 事务中的 Redis 操作?

2.5 验证推测三

如下表,序号 3 和 序号 4 的场景都是开启了 Redis 的事务支持 ,两个场景的区别是是否加了 @Transactional 注解

为了验证上面的场景,我们来做个实验:

  • 先开启 Redis 事务支持,然后执行 Redis 的事务命令 multi  和 exec 。
  • 验证场景 3:在 @Transactional 注解的方法中执行 Redis 的递增操作。
  • 验证场景 4:在非 @Transactional 注解的方法中执行 Redis 的递增操作
2.5.1 执行 Redis 事务

首先就用 Redis 的 multi 和 exec 命令来设置两个 key 的值。

如下图所示,设置成功了。

2.5.2 @Transactional 中执行 Redis 命令

接下来在标注有 @Transactional 注解的方法中执行 Redis 的递增操作。

多次执行这个命令返回的结果都是 null,这不就正好重现了!

再来看 Redis 中 count 的值,发现每执行一次 API 请求调用,都会递增 1,所以虽然命令返回的是 null,但最后 Redis 中存放的还是递增后的结果。

相关文章
|
小程序 安全 JavaScript
从零开始uniapp微信小程序项目到发布(超级详细)
最近微信小程序又掀起一波风潮,本文站在新手的角度出发,比较适合第一次使用uniapp 开发微信小程序的伙伴,或者没有过实战经验的小伙伴参考,从零搭建uniapp小程序项目
3121 1
|
Android开发 iOS开发
iOS 替换WebView网页图片为本地图片
iOS 替换WebView网页图片为本地图片
535 0
|
测试技术
elf格式转换为hex格式文件的两种方法
这周工作终于不太忙了,可以写点笔记总结一下了。 之前的文章如何在Keil-MDK开发环境生成Bin格式文件,介绍了如何在Keil开发环境使用fromelf软件,将生成的axf文件转换为bin文件,这次我们再来介绍一下如何将elf文件转换为hex文件。
2181 0
|
机器学习/深度学习 存储 人工智能
人工智能的伦理困境与挑战
在本文中,我们将探讨人工智能技术的快速发展所带来的一系列伦理问题和挑战。随着AI技术的不断进步和应用范围的扩大,如何确保其发展符合道德标准、保护个人隐私以及避免潜在的社会不公成为了亟待解决的问题。本文旨在通过分析当前AI领域面临的主要伦理困境,并提出可能的解决方案或缓解措施,以促进更加负责任地使用和发展人工智能技术。
1326 1
|
弹性计算 人工智能 安全
蚂蚁数科MAPPIC密态计算云平台入驻阿里云计算巢,打造云上密态计算服务
阿里云计算巢新添成员——蚂蚁数科的MAPPIC密态计算云平台,旨在为企业提供安全的大数据和模型密态计算服务,促进数据资产和模型资产的挖掘。MAPPIC是融合AI和BI的隐私保护平台,支持N+接入方式和弹性计算。通过阿里云计算巢,企业能快速创建密态计算集群,降低使用门槛,同时提升业务可靠性和审计追溯能力。双方合作将加速密态计算在云上的应用,应对数据隐私和安全挑战。
蚂蚁数科MAPPIC密态计算云平台入驻阿里云计算巢,打造云上密态计算服务
|
持续交付 Python
解决Python执行命令时路径空格引发的困扰
在Python编程中,执行含空格的系统路径可能导致命令执行失败。本文介绍了三种解决方法:1) 使用引号包裹路径;2) 转义空格字符;3) 利用`os`模块的`normpath`或`join`处理路径。推荐使用`subprocess`模块以获得更精确的命令控制。最佳实践包括避免路径空格、使用`os.path.join()`构建路径及充分测试。
PADS Router进行PCB布线的基本操作
PCB布局好之后就可以进行布线。在PADS Layout中点击工具栏右边的“PADS Router”图标导入到PADS Router进行布线。如下图所示:
1633 0
|
存储 人工智能 算法
探索AI在后端开发中的应用与挑战
随着人工智能技术的飞速发展,AI在后端开发领域扮演着越来越重要的角色。本文将深入探讨AI在后端开发中的应用现状和面临的挑战,分析其带来的影响与发展趋势。
815 1
|
安全 关系型数据库 MySQL
万里数据库加入龙蜥社区,打造基于“龙蜥+GreatSQL”的开源技术底座
欢迎万里数据库和GreatSQL社区加入,将继续发挥数据库厂商的优势,推动数据库与龙蜥操作系统的兼容适配工作。
万里数据库加入龙蜥社区,打造基于“龙蜥+GreatSQL”的开源技术底座
|
JavaScript 前端开发 Java
小笔记:表 - 各种语言的 CommonMark Markdown解析器 实现
小笔记:表 - 各种语言的 CommonMark Markdown解析器 实现
776 1