MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 原文:MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性 作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.
原文: MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性

作者:林冠宏 / 指尖下的幽灵

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities

虫洞区块链专栏:https://www.chongdongshequ.com/article/1536563643883.html


前序

距离上次择文发表,两月余久。2018年也即将要结束了,目前的工作依然是与区块链应用相关的,也很荣幸在9月初受邀签约出版暂名为《区块链以太坊DApp实战开发》一书,预计在明年年初出版。

这次让我有感记录这篇文章的原因是最近在使用Go语言重写一个原来由PHP语言编写的交易所订单撮合模块的时候,发现订单撮合的部分代码在撮合的时候,为保证各表数据在并发情况下不出现读写脏乱而采用了全局锁表的操作。后面我采用了共享锁的形式进行了修改,于刚刚重写完,并进行了并发单元测试,表现正常。

目录

  • 场景描述
  • 解决问题
  • 订单撮合实例
  • 共享锁 与 排他锁
    • 前置知识
    • 行锁与表锁
    • 两种行锁的特点
    • 两种行锁的加锁方式
    • 锁的释放
    • 操作例子
  • 改造代码片段

场景描述

高并发的业务常见是有很多种类的,最常见的例如秒杀抢购。它们都有一个共同的特点就是数据更新都比较频繁,通常涉及到多张业务表的增改操作,且表格越多的,要考虑的问题也越多。

订单撮合可以理解为订单买卖,拿这个为例子进行列举一个可能会导致数据错乱的情形。假设现在买卖手机,A用户是要买手机的,B用户是卖手机的。A的买入单订单1,和B的卖出单订单2,订单2卖出手机,一台手机卖1000元。此时A的网上的钱包余额是1001元,刚好比手机价格高,是可以成交的。

此时记录用户钱包钱数数量的是一张数据表。每次花费了钱或者增加了钱,都要更新这个表。

当这两笔订单进入到系统里面进行撮合。假设系统的订单撮合运行流程如下图所示:

img_bd55a4052657baca48cc609f56145f1d.png

当判断条件进行A用户的钱包余额判断的时候,发现 1001 > 1000,结果是通过,此时准备进入“进行记录更细”步骤。但是,就在这个过程之中的时间差中,A用户使用了系统的网上提现功能,并成功转出了10元,剩余的是1001 - 10 = 991元。但是由于撮合系统的余额判断过程以及通过了,导致下面的交易流程依然能进行,最终A用991元买了B的1000元售价的手机。

解决问题

上述的常见问题是一个很简单的模型,现实的系统中往往是更复杂的。但是它所体现出的问题却是真实存在的,对于这类问题,有很多解决方案。其中,就可以考虑使用数据库的锁。

本文要介绍的是MySQL数据库共享锁排他锁,其它的不作说明或引申。

订单撮合实例

下面的截图就是我所重写好的撮合系统原始的PHP代码,所使用了表锁的方式来解决前面的并发读写导致数据脏乱的问题。这种方式虽然是解决了问题,但是导致了性能低下的问题。

img_aa8fd3befd78a626378ade91d2effeb7.png

共享锁 与 排他锁

前置知识:

  • MySQL 是数据库,不是数据库引擎
  • MySQL有两种常用存储引擎: MyISAMInnoDB
  • MyISAM不支持事务操作,InnoDB支持事务操作
  • MySQL 的锁分有 行锁表锁
  • MyISAM 只有表锁
  • Innodb 行锁,表锁都有
  • 行锁中有共享锁排他锁
  • 共享锁 简称 S锁,排他锁简称 X锁

行锁与表锁

简述:

  • 行锁,锁的是表中对应的行,只限制当前行的读写。

  • 表锁,锁的是整张表,限制的是整张表的数据读写。

比较:

  • 行锁,计算机资源开销大,加锁慢;会出现死锁;锁定粒度最小,锁冲突的概率最低,并发度最高,性能高。
  • 表锁,计算机资源开销小,加锁快;不会出现死锁;锁定粒度大,锁冲突的概率最高,并发度最低,性能低。

两种行锁的特点

共享锁

A 对数据 B 加了 共享锁,A能读取和修改数据B,C 等其它只能读取数据B,但是不能修改。直至A释放了B的锁。

排他锁

A 对数据 B 加了 排他锁,A能读取和修改数据B,C 等其它不能再对数据B加其它的锁。直观体验是不能修改,不能使用含有加锁动作的select读取。

两种行锁的加锁方式

要注意的是:

  • 行锁的实现SQL语句中必须要有索引的限制条件,例如含有 where id=xxx 这类语句。
  • 行锁的实现SQL语句没有索引限制条件会变成表锁
  • InnoDB引擎 默认的修改数据类SQL语句,update,delete,insert等,都会自动给涉及到的数据加上排他锁。

共享锁

  • select 的添加可以使用满足格式:select ... where 索引限制 lock in share mode 的语句。例如“select name from lgh_user where id = 1 lock in share model” 此时 id 是索引。

排他锁

  • 满足格式:select ... where 索引限制 for update 的语句

锁的释放

  • 非事务(Transaction) 中,语句执行完毕,便释放锁。

  • 行锁在事务 (Transaction) 中,只有等到当前的事务Transaction 进行了 commit 或 roll back,锁才能释放。

操作例子

演示事务 tx 中的例子,文字解析见图。

img_88612a67a8bd97bd47201f8d3b85855b.png

img_73de200fede02835c80958a8dacd25b7.png

img_536055cea619f84512dc2a0f4287c528.png

img_c788627d3a4edfaeb7285387e86a4dc9.png

img_f91644f73321e777c942a596696536b8.png

img_ea1a516ea428564ee4e07625f3a0c459.png

img_dc1b9c811c2d9dadc49f60c9bb360052.png

img_be31dd8bef8f2e1b44425f3ddb6d67f4.png

改造代码片段

撮合中的所有表锁替换成了共享锁,运行其它业务读取所锁的行数据,在当前事务的批量操作还没结束之前,不允许修改。

img_4bfedfe44d5604f05ae2fff547eac032.png

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
26天前
|
人工智能 算法 前端开发
超越Prompt Engineering:揭秘高并发AI系统的上下文工程实践
本文系统解析AI工程范式从Prompt Engineering到Context Engineering的演进路径,深入探讨RAG、向量数据库、上下文压缩等关键技术,并结合LangGraph与智能体系统架构,助力开发者构建高可靠AI应用。
170 1
|
4月前
|
SQL AliSQL 关系型数据库
MYSQL的全局锁和表锁
本文介绍了MySQL中的锁机制,包括全局锁、表级锁及其应用场景。全局锁通过`Flush tables with read lock (FTWRL)`实现,主要用于全库逻辑备份,但会阻塞更新和结构变更操作。表级锁分为显式表锁(`lock tables`)和元数据锁(MDL),前者用于控制并发访问,后者自动加锁以确保读写正确性。文章还探讨了如何安全地为小表添加字段,建议通过设置DDL等待时间或使用MariaDB/AliSQL的NOWAIT/WAIT功能避免业务阻塞。这些方法有助于在高并发场景下优化数据库性能与安全性。
109 0
|
5月前
|
消息中间件 缓存 弹性计算
纯PHP+MySQL手搓高性能论坛系统!代码精简,拒绝臃肿
本内容分享了一套经实战验证的社交系统架构设计,支撑从1到100万用户的发展,并历经6次流量洪峰考验。架构涵盖客户端层(App、小程序、公众号)、接入层(API网关、负载均衡、CDN)、业务服务层(用户、内容、关系、消息等服务)、数据层(MySQL、Redis、MongoDB等)及运维监控层(日志、监控、告警)。核心设计包括数据库分库分表、多级缓存体系、消息队列削峰填谷、CQRS模式与热点数据动态缓存。同时提供应对流量洪峰的弹性伸缩方案及降级熔断机制,并通过Prometheus实现全链路监控。开源建议结构清晰,适合大型社交平台构建与优化。
215 11
|
2月前
|
缓存 关系型数据库 MySQL
在MySQL中处理高并发和负载峰值的关键技术与策略
采用上述策略和技术时,每个环节都要进行细致的规划和测试,确保数据库系统既能满足高并发的要求,又要保持足够的灵活性来应对各种突发的流量峰值。实施时,合理评估和测试改动对系统性能的影响,避免单一措施可能引起的连锁反应。持续的系统监控和分析将对维护系统稳定性和进行未来规划提供重要信息。
140 15
|
3月前
|
关系型数据库 MySQL 分布式数据库
Super MySQL|揭秘PolarDB全异步执行架构,高并发场景性能利器
阿里云瑶池旗下的云原生数据库PolarDB MySQL版设计了基于协程的全异步执行架构,实现鉴权、事务提交、锁等待等核心逻辑的异步化执行,这是业界首个真正意义上实现全异步执行架构的MySQL数据库产品,显著提升了PolarDB MySQL的高并发处理能力,其中通用写入性能提升超过70%,长尾延迟降低60%以上。
|
4月前
|
开发框架 Java 关系型数据库
在Linux系统中安装JDK、Tomcat、MySQL以及部署J2EE后端接口
校验时,浏览器输入:http://[your_server_IP]:8080/myapp。如果你看到你的应用的欢迎页面,恭喜你,一切都已就绪。
385 17
|
5月前
|
关系型数据库 MySQL Linux
CentOS 7系统下详细安装MySQL 5.7的步骤:包括密码配置、字符集配置、远程连接配置
以上就是在CentOS 7系统下安装MySQL 5.7的详细步骤。希望这个指南能帮助你顺利完成安装。
1397 26
|
5月前
|
Ubuntu 关系型数据库 MySQL
在Ubuntu系统的Docker上安装MySQL的方法
以上的步骤就是在Ubuntu系统的Docker上安装MySQL的详细方法,希望对你有所帮助!
591 12
|
6月前
|
消息中间件 NoSQL 关系型数据库
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?

推荐镜像

更多