【学习笔记】MySQL死锁及热点行问题

目录

      • 案例
      • 优化思路
      • 死锁的一些记录笔记
      • 热点行问题

本文记录下关于MySQL优化的学习和一点点思考。

案例

一个并发比较大的下单接口;
包括

  • step1 扣减商品库存
  • step2 生成订单数据
  • step3 记录操作记录

伪代码如下,底层使用的是MySQL数据库,单体服务(你问我为什么单体,案例需要啦)。

提问:暂时不考虑分布式锁、缓存、异步等使用场景,下面的代码执行步骤有没有值得优化的点?

  @Transactional(rollbackFor = Exception.class)public void createOrder(Entity param){...校验等//step1 扣减商品库存//update products set stock = stock where sku_id = XXXdeductStock(param);//step2 生成订单数据//insert into order XXXXXXcreateOrder(param);//step3 记录操作记录//insert into operation_records XXXrecordOperation(param);... }

上述代码做了哪些事,开启了事务

更新了一个个表:库存表库存分

插入了两条数据:用户订单表,用户操作记录

对于当前的业务,上述代码的DB执行流程是没有问题的,

但是朋友,我们是要有梦想滴,CRUD BOY不是我们的终点,我们的目标是星辰大海。

来,键盘给你,优化下。

优化思路

正常业务情况下,上述代码没毛病,开启事务,库存更新语句会加上行锁,插入语句可能会加上插入意向锁等。

我们重点来关注下 更新语句的行锁,并发高的情况下,同一种库存商品数据是根据sku_id来更新,存在激烈的行锁竞争抢占的问题。

来回忆一下,MySQL事务开启后,是什么时候开始给库存加行锁的?

事务开启就加行锁? 错。
是在执行更新语句的时候加锁的,上述的step1

那么解锁是什么时候呢?

当然是事务提交的时候。

那么对于案例中的语句来说,products表的sku_id = XXX这行数据的行锁,将从step1开始锁定,直到createOrder()方法执行完毕才会解锁。

对于其他的创建订单请求,热点商品,相同的sku_id,同时执行这行代码的时候,只能等待。

这样分析可以发现,持有锁的时间太长了。

没错,是时间太长了,换个场景,或许我会欣喜若狂,彷佛得到了认可,

但此时此刻,这并不是我想要的。

那么,是否可以将更新库存的语句放到最后呢,step1 变成step3,这样对一一次创建订单的请求,加锁的时长会大大减少,并发度会提升。

  @Transactional(rollbackFor = Exception.class)public void createOrder(Entity param){...校验等//step1 生成订单数据//insert into order XXXXXXcreateOrder(param);//step2 记录操作记录//insert into operation_records XXXrecordOperation(param);//step3 扣减商品库存//update products set stock = stock where sku_id = XXXdeductStock(param);... }

这样的优化虽不起眼,但是架不住积少成多,从细节处着手,才能仰望星空。

这样才是泰裤辣!

死锁的一些记录笔记

继续讨论下,上述代码没有问题了,但是

职业生涯中,我并没有真正的面对过MySQL的死锁,很幸运也很不幸,无需面对老大难的风险,但也没有获得实操的经验。

死锁的产生及竞态条件不再赘述。

最接近死锁的一次,还是刚工作的时候在一家保险公司,我还是nobody,当然了现在也还是nobody。

大约记得夜里的批处理更新账户信息,以及客户投保时,都需要保险账户总表账户明细表更新,批处理和客户投保的请求互相竞争对方持有的锁,导致死锁,疯狂报警,处理方案则是DBA大半夜爬起来 kill掉其中一个session,解除死锁。

很明显上述处理的方案是不可持续的。

完全避免死锁不太现实,我们需要做的是尽可能减少死锁发生的概率。

MySQL给我们提供了两种方案

  • 互相等待锁释放,直至超时,通过innodb_lock_wait_timeout来设置
  • 死锁检测,innodb_deadlock_detect设置为on (8.0之后版本提供)

第一种策略,我们固然可以设置很短的超时时间,但是对于慢SQL来说很容易误伤。

所以一般会有第二种方案,超时检测。
MySQL会自动查询是否存在连接相互等待获取对方连接的情况,如果存在,会回滚其中一个事务来打破死锁。

但是高并发情况下,比如上述的案例接口,死锁检测会影响到MySQL执行速度和效率,我们就只能通过第一这种方案来等待超时释放。

热点行问题

正如我们上面讨论的,案例中的某个热门产品的库存对于MySQL来说就是热点行,会存在频繁的锁竞争死锁等问题,会导致性能下降,MySQL本身也没有更好的方案来避免。

我们考虑下从业务层来解决这个问题。

  • redis预扣减

使用redis缓存热点商品,借助redis的高性能、高并发特性,承担大部分的请求压力。

但是redis会增加复杂度,可能会带来数据不一致的情况,例如超卖和少卖。

  • 库存拆分

往往库存只有一条数据,作为共享资源,为了保证安全,MySQL会对这条数据加锁,请求只能排一条长队等待锁的释放,如果我们把这条数据拆分成多条,10条数据,20条数据,性能的提升是可以预见的,大量请求的锁竞争可被分散在多条数据上,请求的耗时根据拆分的力度逐渐降低。

拆分缺点也很明显,对于拆分后的数据,某条库存用完了怎么办,怎么判断库存超卖不超卖,以及库存数据的增加维护等等等,系统复杂度会提升。

  • 请求合并

对于反馈需要及时的电商场景,请求合并并不一定适合,但是对于实时性没那么强的业务场景,比如说银行或者保险的热点账户,多个账户变动请求同时变更同一个账户,我们可以在1s、5s或者更长一段时间内将这段时间的多个请求在内存中计算合并后,再去更新数据库,可以大大降低数据库的压力。

  • 更新转插入

这种方式也是针对异步场景 UPDATE语句转INSERT语句,原来更新一条数据,改为插入单独的一个明细表,通过异步的方式将明细表进行汇总计算,再合并到原数据中。

这么一想设计思想是否和MySQL redo log的使用方式比较接近了,先顺序写磁盘,然后异步写入MySQL数据表中。
很多设计思想都是一致的,无非是实现的区别

理论上我们上述说的方案,也都可以通过MySQL进行改造,比如请求合并,改为在MySQL层对相同的SQL语句(这里的相同指更新逻辑基本一致)进行合并。

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

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

相关文章

Linux应用开发基础知识——文件IO操作(三)

前言: 在 Linux 系统中,一切都是“文件”:普通文件、驱动程序、网络通信等等。 所有的操作,都是通过“文件 IO”来操作的。所以,很有必要掌握文件操作的常用接口。 目录 一、文件IO 1.什么是文件: 2.怎么…

【Android】画面卡顿优化列表流畅度一

卡顿渲染耗时如图: 卡顿表现有如下几个方面: 网络图片渲染耗时大上下滑动反应慢,甚至画面不动新增一页数据加载渲染时耗时比较大,上下滑动几乎没有反应,画面停止没有交互响应 背景 实际上这套数据加载逻辑已经运行…

绝对力作:解锁string的所有关键接口,万字深度解析!

W...Y的主页 😊 🍔前言: 通过博主的上篇文章,我相信大家已经认识了STL并且已经迫不及待想学习了,现在我们就走近STL的第一种类——string。 目录 为什么学习string类? C语言中的字符串 标准库中的str…

【机器学习】梯度下降预测波士顿房价

文章目录 前言一、数据集介绍二、预测房价代码1.引入库2.数据3.梯度下降 总结 前言 梯度下降算法学习。 一、数据集介绍 波士顿房价数据集:波士顿房价数据集,用于线性回归预测 二、预测房价代码 1.引入库 from sklearn.linear_model import Linear…

筹码穿透率指标选股公式,衡量筹码抛压

在前面的文章中,介绍了博弈K线,它是根据筹码分布的原理结合普通K线的方法绘制出来的。当博弈K线的实体部分比较长的时候,说明当天穿越筹码密集区,有大量的筹码解套。通过引入换手率,可以衡量套牢盘的抛压程度。如果穿越…

Xcode 最好用的 11 个快捷键

今天来分享一下我觉得很好用的 Xcode 12 个快捷键 1. Command Shift O 快速打开,可让你快速导航到项目中的任何文件、函数、变量 2. Command Shift J 快速定位到当前代码所在的文件夹位置,并切换到项目导航器中显示 3. Command Shift Y 快速…

2011年03月31日 Go生态洞察:Godoc —— Go代码的文档化

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

list部分接口模拟实现(c++)

List list简介list基本框架list构造函数list_node结构体的默认构造list类的默认构造 push_back()iteartor迭代器迭代器里面的其他接口const迭代器通过模板参数实现复用operator->() insert()erase()clear()析构函数迭代器区间构造拷贝构造operator() list简介 - list可以在…

【Java】本地开发环境正常、测试或生产环境获取的文件路径不对的问题

引 Java 中经常获取本地文件或者resource下的文件,要获取文件,首先要获得本地路径。 Java 本身或一些开源工具包都提供了很多获取路径的方法。但使用时经常遇到本地开发环境正常、测试或生产环境获取的文件路径不对的问题。 本文将列出几种常见的获取…

python开发过程中注意编码规范~

文章目录 一、 代码编排二、 文档编排三、 空格的使用四、 注释五、 文档描述六、 命名规范总体原则,新编代码必须按下面命名风格进行,现有库的编码尽量保持风格。七 编码建议关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、…

【三维重建】摄像机几何

针孔相机模型 为了方便我们对针孔相机模型进行数学建模,我们往往对虚拟像平面进行研究,因为虚拟像平面的方向与我们实际物体的方向一致。 通过相似三角形法可以得到三维坐标到二维坐标映射 将像平面原点坐标移动到左下角: 加上现实世界单位&a…

【神经网络】【GoogleNet】

1、引言 卷积神经网络是当前最热门的技术,我想深入地学习这门技术,从他的发展历史开始,了解神经网络算法的兴衰起伏;同时了解他在发展过程中的**里程碑式算法**,能更好的把握神经网络发展的未来趋势,了解神…

【Linux笔记】Linux环境变量与地址空间

【Linux笔记】Linux环境变量与地址空间 一、命令行参数1.1、main函数的参数1.2、main函数的第三个参数 二、环境变量的概念与内容2.1、环境变量的概念2.2、环境变量的分类2.3、环境变量的组织形式2.4、常见的环境变量 三、设置环境变量3.1、通过命令获取或设置环境变量3.2、通过…

补偿 FIR 滤波器引入的延迟

补偿 FIR 滤波器引入的延迟 对信号进行滤波会引入延迟。这意味着相对于输入,输出信号在时间上有所偏移。此示例向您说明如何抵消这种影响。 有限冲激响应滤波器经常将所有频率分量延迟相同的时间量。这样,我们就很容易通过对信号进行时移处理来针对延迟…

SMART PLC模拟量上下限报警功能块(梯形图代码)

博途PLC模拟量偏差报警功能块请参考下面的文章链接: 模拟量偏差报警功能块(SCL代码)_RXXW_Dor的博客-CSDN博客文章浏览阅读594次。工业模拟量采集的相关基础知识,可以查看专栏的系列文章,这里不再赘述,常用链接如下:PLC模拟量采集算法数学基础(线性传感器)_plc傳感器數…

目标检测算法 - YOLOv1

文章目录 1. 作者简介2. 目标检测综述3. YOLOv1算法3.1 预测阶段3.2 预测阶段后处理3.3 训练阶段 YOLO的全称是you only look once,指只需要浏览一次就可以识别出图中的物体的类别和位置。 YOLO是目标检测模型。目标检测是计算机视觉中比较简单的任务,用…

OpenHarmony创新赛|赋能直播第五期

OpenHarmony创新赛赋能直播课程即将再次与大家见面!本期基于之前的青蛙影院的UI界面设计的课程,介绍综合性APP的需求介绍和技术栈整合等内容。此外,课程同步赋能OpenHarmony创新赛,为参赛开发者带来新的思路和方法,也欢…

卷积神经网络中 6 种经典卷积操作

深度学习的模型大致可以分为两类,一类是卷积神经网络,另外一类循环神经网络,在计算机视觉领域应用最多的就是卷积神经网络(CNN)。CNN在图像分类、对象检测、语义分割等经典的视觉任务中表现出色,因此也早就…

【Python3】【力扣题】242. 有效的字母异位词

【力扣题】题目描述: 【Python3】代码: 1、解题思路:若字符串长度相同,依次遍历元素,比较两个字符串的该元素个数是否相同。【耗时长】 知识点:len(...):获取序列(字符串、列表等&…

【uniapp】通用列表封装组件

uniapp页面一般都会有像以下的列表页面,封装通用组件,提高开发效率; (基于uView前端框架) 首先,通过设计图来分析一下页面展示和数据结构定义 w-table组件参数说明 参数说明类型可选值默认值toggle列表是…