首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

线上问题---又又又又来生产事故了,有人要倒霉了

  • 25-04-18 16:21
  • 3497
  • 9210
juejin.cn

前言

不好啦❗ 天塌了❗ 又又又又来生产事故了❗

最近公司发生了一起生产事故,WMS在库存扣减时产生了 重复扣减,事件报告中指出是因为针对重复MQ消息做幂等控制时,幂等控制方案失效,导致重复处理了两条退款消息,最终造成重复退款。

失效的幂等控制方案其实很简单,就是基于数据库的 唯一索引 来进行幂等控制,这其实是很常用也很简单的一种实现方案,但为什么在这起生产事故中,唯一索引实现幂等就失效了呢,问题就出在这个唯一索引上。

一. 为了便于理解,这里先给出整个场景的抽象交互图。

image.png

上游重复投递消息后,重复投递的消息有两个下游消费,两个下游都基于唯一索引做了幂等控制,但是结果就是下游-1幂等控制失败,另一个下游-2幂等控制成功。

上游投递的消息有四个字段,记为field_1,field_2,field_3和field_4,其中下游-1的幂等控制表的创表语句如下。

java
代码解读
复制代码
CREATE TABLE idempotent_1 ( id BIGINT PRIMARY KEY AUTO_INCREMENT, field_1 VARCHAR(255) NOT NULL, field_2 VARCHAR(255) NOT NULL, field_3 VARCHAR(255) DEFAULT NULL, field_4 VARCHAR(255) NOT NULL, UNIQUE INDEX idempotent_index(field_1, field_2, field_3) )

下游-2的幂等控制表的创表语句如下

java
代码解读
复制代码
CREATE TABLE idempotent_2 ( id BIGINT PRIMARY KEY AUTO_INCREMENT, field_1 VARCHAR(255) NOT NULL, field_2 VARCHAR(255) NOT NULL, field_3 VARCHAR(255) DEFAULT NULL, field_4 VARCHAR(255) NOT NULL, UNIQUE INDEX idempotent_index(field_2) )

二. 问题分析

不知道你猜到没有,原因就是下游-1的唯一索引会失效。

下游-1的唯一索引是一个复合索引,包含field_1,field_2和field_3,其中field_3允许为NULL,而在MySQL中,NULL表示 未知,也就是前后两次插入数据时,如果field_3都是NULL,此时就算field_1和field_2完全一样,也是能够插入成功的,因此唯一索引的唯一约束就失效了,最终幂等控制也就失败了。

我们可以把idempotent_1表创建出来自行做一下测试,执行如下插入语句两次,是可以插入成功的。

sql
代码解读
复制代码
INSERT INTO idempotent_1 (field_1, field_2, field_3, field_4) VALUES ('A', 'B', NULL, 'D')

三. 问题解决

问题的解决很简单,为field_3添加NOT NULL约束,就能够规避因为存在NULL而导致的唯一索引失效,进而幂等控制就能成功。

进一步的,其实建议所有字段都添加上NOT NULL约束,这样能够规避很多问题。

总结

情况是一个简单情况,就是对重复MQ消息基于唯一索引做幂等控制时,因为唯一索引是一个复合索引且存在字段允许为NULL,从而唯一索引失效,最终幂等控制失败。

解决方案也十分简单,就是为所有字段都添加上NOT NULL约束,从而唯一索引就不会因为存在NULL而失效。

那么最后思考一个问题,为什么MySQL允许字段可以为NULL呢,毕竟很多问题都是因为NULL的存在而出现的。

个人认为最本质的原因就是NULL可以节约空间,比如一个字段是VARCHAR,当该字段允许为NULL且实际就是NULL时,是不会占用空间的,但如果该字段不允许为NULL,那么至少都会存储一个空字符串,而空字符串的占用空间包含两部分,即 长度信息 和 实际内容,因为是空字符串,所以实际内容是0字节,但长度信息至少都会占用1字节,所以 节约空间 是NULL存在的意义。

注:本文转载自juejin.cn的后端程序员Aska的文章"https://juejin.cn/post/7494078158217969691"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top