【黑马点评】优惠券秒杀(集群模式)

【黑马点评】优惠券秒杀(单体模式)的最后提到:使用userId.toString().intern()作为锁,在集群模式下是有问题的。在本文中通过基于Redis实现的分布式锁来解决这一问题。

基于Redis实现分布式锁

  1. 加锁:SET key value NX EX ttl

    • key:锁。在该业务中为order:用户Id,其中order为业务名,使用order:用户Id作为锁可以保证在该业务中每个用户拥有一把锁。
    • value:加锁线程的线程标识,UUID + 线程Id
      • 不能只用线程Id作为线程标识,因为在每一台JVM中线程Id都是从0开始递增的, 分布式环境下会重复,不再唯一。
      • UUID的作用是区分集群中的每一台JVM,因此我们要为每一台JVM获取一个UUID,可以通过将用于存储UUID的变量设置为static final实现,在加载ILock类时创建并初始化,而且此后不允许修改,这样就可以满足对每一台JVM都是唯一的。
        在这里插入图片描述
    • SETNX用于保证锁的互斥性
    • SET key value NX EX ttl是将加锁SETNX key value和为锁设置过期时间EXPIRE key ttl两个命令合为一个命令了,这样可以保证原子性。
  2. 释放锁:

    • 手动释放:DEL key

      • 在释放前要先判断锁是不是自己的再删除锁,避免误删。
      • “先判断锁是不是自己的,再删除锁” 是典型的线程安全问题,这一可以通过乐观锁来解决,也可以通过lua脚本来保证这两条命令的原子性,本项目中采用了第二种方式。
    • 超时自动释放:兜底,避免锁无法正常释放,避免发生死锁问题。

误删问题

在这里插入图片描述

通过lua脚本确保多条命令执行时的原子性

用lua脚本操作Redis
Redis.call('命令名称', 'key', '其他参数', ...)
比如,在Redis中执行set age 10命令:Redis.call('set', 'age', '10')

两个参数数组
在调用lua脚本时可以传入参数:

  • 通过KEYS传入key类型参数
  • 通过ARGV数组传入其他参数

这两个数组的下标都从1开始。

用lua脚本实现 “先判断锁是不是自己的,再删除锁” 逻辑
在这里插入图片描述在Java代码中调用lua脚本
在这里插入图片描述

黑马rabbitMQ优惠卷秒杀是指利用RabbitMQ消息队列来实现优惠卷的秒杀活动。RabbitMQ是一个开源的消息队列中间件,它可以实现高效的消息传递和异步通信。在秒杀活动中,由于瞬间会有大量用户同时请求抢购,传统的同步处理方式无法满足高并发的需求,而使用RabbitMQ可以将请求异步化,提高系统的并发处理能力。 具体实现过程如下: 1. 创建一个消息队列:首先需要创建一个RabbitMQ消息队列,用于存储用户的秒杀请求。 2. 生成优惠卷:在秒杀活动开始前,需要提前生成一定数量的优惠卷,并将其存储在数据库中。 3. 用户抢购请求:用户在秒杀活动开始时,发送抢购请求到消息队列中。 4. 消费者处理请求:创建多个消费者来监听消息队列中的请求,并进行处理。当有新的请求进入队列时,消费者会从队列中获取请求,并进行相应的处理逻辑。 5. 校验优惠卷:消费者在处理请求时,会先校验用户是否有资格参与秒杀活动,并检查优惠卷的库存情况。 6. 分发优惠卷:如果用户符合条件并且优惠卷有库存,消费者会将优惠卷分发给用户,并更新数据库中的库存信息。 7. 返回结果:消费者处理完请求后,将处理结果返回给用户,告知用户是否成功抢购。 通过使用RabbitMQ消息队列,可以有效地解决高并发场景下的请求处理问题,提高系统的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值