防重复下单与超卖问题

news/2024/10/21 14:22:12

防止秒杀重复下单
在Redis中记录一个hash值,用户每次秒杀,值加1,是否大于1作为判断

 

 

 

使用分布式锁解决超卖的问题

分布式锁
为了保证一个方法 或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用java并发处理相关的API(ReentrantLock或Synchronized)进行互斥控制,在单击环境汇总,java中提供了很多并发处理的API。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程。多进程并且分布在不同机器上,这使原单击部署情况下的并发控制锁策略失效,单纯的java Api并不能提供分布式的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问 ,这就是分布式锁要解决的问题

 

分布式锁应该具备的条件
在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
高可用的获取锁与释放锁
高性能的获取锁与释放锁
具备可重入的特性
具备锁失效机制,防止死锁
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

分布式的实现的方式
1、基于数据库的实现方式
基于数据库的实现的核心思想是:在数据库中创建一个表,表中包含方法名等字段,并在方法名字端上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。

数据库实现有以下几个问题:

这把锁强依赖数据库可用性,数据库是一个单点,一旦数据库挂掉,会导致业务不可用
这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得这把锁
这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作
这把锁是非重入的,同一个线程没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了

基于数据库排他锁

除了可以通过增删操作数据表中的记录以外,其实还可以借助数据库中自带的锁来实现分布式的锁。我们还用刚刚创建的那张数据库表。可以通过数据库的排它锁来实现分布式锁。

 

 

在查询语句后面增加 for update,数据库在查询过程中给数据表增加排他锁(InnoDb引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。我们希望使用行级锁,就要给method_name添加索引,这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时访问的问题)当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

 

我们可以认为获得排他锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,在通过以下方法解锁

 

通过connection.commit()操作来释放锁

这种方法可以有效的解决上面提到的无法释放锁和阻塞锁的问题。

阻塞锁? for update 语句会在执行成功后立即返回,在执行失败时一直处于阻塞状态,直到成功
锁定之后服务宕机,无法释放?使用这种方式,服务宕机之后数据库会把自己释放掉
但是还是⽆法直接解决数据库单点问题。

这⾥还可能存在另外⼀个问题,虽然我们对 method_name 使⽤了唯⼀索引,并且显示使⽤ for update 来使⽤⾏级锁。但是,MySql会对查询进⾏优化,即便在条件中使⽤了索引字段,但是否使⽤索

引来检索数据是由 MySQL 通过判断不同执⾏计划的代价来决定的,如果 MySQL 认为全表扫效率更⾼, ⽐如对⼀些很⼩的表,它就不会使⽤索引,这种情况下 InnoDB 将使⽤表锁,⽽不是⾏锁。如果发⽣这

种情况就悲剧了。。。

还有⼀个问题,就是我们要使⽤排他锁来进⾏分布式锁的lock,那么⼀个排他锁⻓时间不提交,就会占

⽤数据库连接。⼀旦类似的连接变得多了,就可能把数据库连接池撑爆

 

数据库实现分布式的缺点:
会有各种各样的问题,在解决问题的过程中会使整个方案变得越来越复杂
操作数据库需要一定的开销,性能问题需要考虑
使用数据库的行级锁并不一定靠谱,尤其是当我们的锁表并不大的时候(有可能锁住整张表)

基于Redis的实现方式
redis实现分布式的优点:
1、Redis有很高的性能

2、Redis命令对此支持较好,实现起来比较方便

 

命令介绍
1、SETNX

SETNX key val : 当且仅当key不存在时,set一个key为val的字符串,返回1,若key存在,则什么都不做,返回0

 

2、expire

expire key timeout : 为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。

 

3、delete

delete key : 删除key

使用redis分布式的时候,主要就会使用到这三个命令

 

实现思想
1、获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间自动释放锁,所得value值为一个随机生成的UUID,通过此在释放锁的时候判断

2、获取锁的时候还设置一个获取超时时间,若超过这个时间则放弃获取锁

3、释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行所释放

 

总结
可以使用缓存来替代数据库来实现分布式锁,这个可以提供更好的性能,同时,很多缓存服务器都是集群部署的,可以避免单点问题。并且很多缓存服务都提供了可以用来实现分布式的方法,比如Tair的put ⽅法,redis的setnx⽅法等。并且,这些缓存服务也都提供了对数据的过期⾃动删除的⽀持,可以直接设置超时时间来控制锁的释放

 

使用缓存实现分布式锁的优点

性能好,实现起来较为方便
使用缓存实现分布式锁的缺点
使用缓存实现分布式锁的优点

通过超时时间来控制锁的失效时间并不是十分的靠谱

 

 

基于ZooKeeper的实现方式
实现分析
ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录数结构,规定同一个目录下文件名不能重复。基于ZooKeeper实现分布式锁的步骤如下:

创建一个目录 mylock
线程A想获取锁就在mylock目录下创建临时顺序节点
获取mylock目录下的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁
线程B获取锁节点,判断自己不是最小节点,设置监听比自己小的节点
线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁

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

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

相关文章

在使用的CSS渲染的网页上进行编辑时光标乱跳,导致编辑不正常

前一阵子发现notion网页版突然抽风,输入时光标总是会莫名移到最前,起初认为是notion的问题,但是搜索无果。遂下载了notion客户端。后来在使用chatGPT时,也发现了此问题,这说明该问题与notion很大概率是无关的。于是我将目标转移到了浏览器上,果然,经过测试是我安装的一款…

如何使用WebSockets

使用WebSockets你需要遵循以下步骤:一、理解WebSockets与传统HTTP的差异;二、选择合适的库和框架;三、建立WebSocket服务器;四、构建WebSocket客户端;五、确保连接的安全性。在开始使用WebSockets前,我们首先需要明白其背后的设计理念和技术特点。一、理解WebSockets与传…

count(*)、count(1)哪个更快?面试必问:通宵整理的十道经典MySQL必问面试题Jv

合集 - 面渣逆袭(10)1.阿里面试:Java开发中,应如何避免OOM02-212.美团面试:Kafka如何处理百万级消息队列?02-203.Java异常处理的20个最佳实践:告别系统崩溃02-224.揭秘一线大厂Redis面试高频考点(3万字长文、吐血整理)02-235.美团面试:说说OOM三大场景和解决方案? (绝…

如何使用Python调用API数据

为什么使用Python调用API数据? 简洁的语法:Python的简洁性使得编写API调用代码变得直观易懂。 强大的库支持:Python拥有如requests这样的库,极大地简化了HTTP请求的发送和响应的处理。 数据处理能力:Python的数据处理库,如Pandas,使得数据的分析和处理变得简单。 社区支…

解除网页文本禁止复制限制的六种方法

# 方法一:浏览器扩展 最简单也是最省事的方法,直接安装解除复制限制的扩展完事儿。 下面推荐两款扩展:Simple Allow Copy:Chrome & Edge(Chromium 系的应该都可以) Absolute Enable Right Click & Copy:Chrome & Edge & Firefox使用方法也很简单,在有复…

CAE教程:HyperMesh概述与有限元分析简介

1.1 HyperMesh 概述 本节将介绍有限单元法基本原理,HyperMesh 软件基本功能及界面介绍,获取在线帮助等内容。1.1.1 有限元分析方法简介 有限单元法(FEM)是一种可以精确预测复杂结构在外界载荷作用下响应的方法,该数值方法起源于上世纪 50 年代。在有限单元法出现之前,验证…

使用 Optimum-Intel 和 OpenVINO GenAI 优化和部署模型

在端侧部署 Transformer 模型需要仔细考虑性能和兼容性。Python 虽然功能强大,但对于部署来说有时并不算理想,特别是在由 C++ 主导的环境中。这篇博客将指导您如何使用 Optimum-Intel 和 OpenVINO™ GenAI 来优化和部署 Hugging Face Transformers 模型,确保在最小依赖性的情…

【STC15】面向对象的.h/.c程序架构

.h 文件 #ifndef __MAIN_H_ #define __MAIN_H_/* Includes ------------------------------------------------------------------*/ #include <STC15.h>/* extern variables-----------------------------------------------------------*//* extern function prototype…