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

news2024/12/26 12:34:05

目录

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

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

案例

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

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

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

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

  @Transactional(rollbackFor = Exception.class)
  public void createOrder(Entity param){
       ...校验等
      //step1 扣减商品库存
      //update products set stock = stock where sku_id = XXX
      deductStock(param);
      //step2 生成订单数据
      //insert into order XXXXXX
      createOrder(param);
      //step3 记录操作记录
      //insert into operation_records XXX
      recordOperation(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 XXXXXX
      createOrder(param);
      //step2 记录操作记录
      //insert into operation_records XXX
      recordOperation(param);
      //step3 扣减商品库存
      //update products set stock = stock where sku_id = XXX
      deductStock(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.coloradmin.cn/o/1185027.html

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

相关文章

MySQL 8.0 Clone 备份恢复演练

文章目录 前言1. 恢复目标2. 环境说明3. 克隆数据4. 恢复全量数据5. 注册增量日志6. 应用增量日志 后记 前言 上一篇文章中,我们介绍了使用 Clone 插件进行备份,相关的恢复流程将在本篇文章介绍。 MySQL 8.0 Clone Plugin 详解 恢复增量数据的方法&…

前端瀑布流怎么布局

假设你需要把页面搭建成这样,有两列元素,每个元素宽度一定,高度不一定。如何实现? 这种瀑布流布局有很多实现方式,比如Grid布局。 什么是Grid布局 Grid布局是一种很灵活的布局方式,他把你的页面划分成了很…

[ACTF2020 新生赛]BackupFile 1

题目环境: 好好好,让找源文件是吧?咱们二话不说直接扫它后台 使用dirsearch工具扫描网站后台(博主有这个工具的压缩包,可以私聊我领取)python dirsearch.py -u http://0d418151-ebaf-4f26-86b2-5363ed16530…

ZYNQ_project:key_beep

通过按键控制蜂鸣器工作。 模块框图: 时序图: 代码: /*1位按键消抖 */ module key_filter (input wire sys_clk ,input wire sys_rst_n ,input wire key_in ,output …

C语言计算1,2,3…100的和

完整代码&#xff1a; // 计算 1&#xff0c;2&#xff0c;3…100 的和。 #include<stdio.h>int main() {int sum0;for (int i 1; i < 100; i){sumi;}printf("1&#xff0c;2&#xff0c;3…100 的和为&#xff1a;%d",sum);return 0; }运行截图&#xff…

【hcie-cloud】【3】华为云Stack规划设计之华为云Stack交付综述【上】

文章目录 前言华为云Stack交付综述交付流程华为云Stack交付流程华为云Stack安装部署流程 交付工具链华为云Stack交付工具链eDesigner - 让解决方案销售更智能eDesigner配置页面 - 基本信息eDesigner配置页面 - 服务及组网配置eDesigner配置页面 - 弹性云服务器/ECSeDesigner配置…

计算机视觉驾驶行为识别应用简述

一、什么是计算机视觉识别&#xff1f; 计算机视觉识别是一种基于图像处理和机器学习的人工智能应用技术&#xff0c;可以用于多个场景。常见应用场景包括人脸识别、场景识别、OCR识别以及商品识别等。今天以咱们国产系统豌豆云为例&#xff0c;为大家梳理一下在车辆驾驶行为中…

如何批量创建文件夹并命名?

如何批量创建文件夹并命名&#xff1f;批量创建文件夹指的是一次性在计算机中创建多个文件夹的操作。通常情况下&#xff0c;用户需要在特定的目录下创建多个具有相似命名规律的文件夹时&#xff0c;可以使用批量创建文件夹的功能&#xff0c;以简化和加快这一过程。这样的功能…

解决kubernetes集群证书过期的问题

现象&#xff1a; 解决办法&#xff1a; 1.在master节点运行&#xff1a; kubeadm alpha certs renew all 2.在master节点运行&#xff1a; rm -f /etc/kubernetes/kubelet.conf && cp /etc/kubernetes/admin.conf /etc/kubernetes/bootstrap-kubelet.conf 3.在maste…

CNVD-C-2023-76801:用友NC uapjs RCE漏洞复现[附POC]

文章目录 用友NC uapjs RCE漏洞复现(CNVD-C-2023-76801) [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 用友NC uapjs RCE漏洞复现(CNVD-C-2023-76801) [附POC] 0x01 前言 免责声明&#xff1a;请勿利用…

擎创动态 | 开箱即用!擎创科技联合中科可控推出大模型一体机

一、金融行业大模型一体机发布 10月26日至27日&#xff0c;2023金融科技安全与创新大会顺利召开。会上&#xff0c;中科可控联合擎创科技、卓世科技、文因互联、百川智能、捷通华声、智谱华章、易道博识等9大厂商&#xff0c;发布了9款金融行业大模型一体机&#xff0c;为金融…

ZYNQ_project:key_led

条件里是十进制可以不加进制说明&#xff0c;编译器默认是10进制&#xff0c;其他进制要说明。 实验目标&#xff1a; 模块框图&#xff1a; 时序图&#xff1a; 代码&#xff1a; include "para.v"module key_filter (input wire …

opengauss权限需求

创建角色 "u_rts" 并授予对数据库 "rts_opsdb" 的只读权限&#xff1a; CREATE ROLE u_rts LOGIN PASSWORD Cloud1234; GRANT CONNECT ON DATABASE rts_opsdb TO u_rts; GRANT USAGE ON SCHEMA public TO u_rts; GRANT SELECT ON ALL TABLES IN SCHEMA pub…

二维码智慧门牌管理系统升级解决方案:轻松实现辖区范围门址统计

文章目录 前言一、系统功能与优势 前言 在这个数字化时代&#xff0c;传统的门牌管理系统已经无法满足现代管理的需求。为了满足辖区内门址的统计需求&#xff0c;我们引入了全新的二维码智慧门牌管理系统升级解决方案。这一升级将让您轻松实现辖区范围门址的统计&#xff0c;…

虹科分享 | 一文带你了解增强现实(AR)技术的前世今生

引言&#xff1a;增强现实&#xff08;Augmented Reality, AR&#xff09;技术在近几年大放光彩&#xff0c;您可能在《头号玩家》或《黑镜》等影视作品中看到过人们对AR技术的其奇思妙想&#xff0c;也可能从科普文章中了解过“元宇宙”、“数字孪生”等概念&#xff0c;您还可…

如何安装 StoneDB 2.0 企业版? | StoneDB 使用教程 #2

通过二进制TAR包安装&#xff08;CentOS 7.X&#xff09; 下载安装包 stonedb-ee-8.0-v2.1.0.el7.x86_64.tar.gz 下载地址&#xff1a;https://www.stoneatom.com/download 解压安装包 tar -zxvf stonedb-ee-8.0-v2.1.0.el7.x86_64.tar.gz -C /opt 依赖检查 ldd -r /opt/st…

Cordova插件开发三:通过广播实现应用间跨进程通信

文章目录 1.最终效果预览2.数据发送3.插件接受数据4.JS页面中点击获取数据返回1.最终效果预览 场景说明:我们给自来水公司开发了一个h5应用,需要对接第三方厂家支持硬件设备以便于获取到高精度定位数据,之前几篇文件写过,我已经集成过南方测绘RTK和高精度定位模块的设备,厂…

传感器数据采集:采样定理(奈奎斯特定理)

采样定理是连续时间信号&#xff08;通常称为“模拟信号”&#xff09;和离散时间信号&#xff08;通常称为“数字信号”&#xff09;之间的基本桥梁。该定理说明采样频率与信号频谱之间的关系&#xff0c;是连续信号离散化的基本依据。 它为采样率建立了一个足够的条件&#x…

Redis 线程、持久化和监控

Redis 线程、持久化和监控 Redis线程模型 Redis主线程模型 图1 Redis 6.0之前的主线程模型 IO多路复用程序指的是单个线程监听多个套接字连接&#xff08;Socket&#xff09;&#xff0c;当IO多路复用程序将多个Socket上的就绪事件放置于队列中&#xff0c; Redis主线程一次处…

Codeforces Round 908 (Div. 2)题解

目录 A. Secret Sport 题目分析: B. Two Out of Three 题目分析: C. Anonymous Informant 题目分析: A. Secret Sport 题目分析: A,B一共打n场比赛&#xff0c;输入一个字符串由A和‘B’组成代表A赢或者B赢&#xff08;无平局&#xff09;&#xff0c;因为题目说明这个人…