防止秒杀重复下单、使用分布式锁解决超卖的问题

防止秒杀重复下单

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

 

 

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

 

分布式锁

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

 

分布式锁应该具备的条件

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

 

分布式的实现的方式

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 ⽅法,redissetnx⽅法等。并且,这些缓存服务也都提供了对数据的过期⾃动删除的⽀持,可以直接设置超时时间来控制锁的释放

 

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

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

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

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

 

 

基于ZooKeeper的实现方式

实现分析

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

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你在狗叫什么、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值