实战篇-22.秒杀优化-异步秒杀思路_哔哩哔哩_bilibili
1.流程回顾
1.1超卖问题
判断秒杀时间,加乐观锁(比较标记/版本),检查库存是否大于0
1.2一人一单问题
看看数据库里有没有这个这个人下的订单:
1.单机模式中加悲观锁sychronized,锁监视器和用户线程id字符串绑定,购买之前检查。
2.多线程模式有并发安全问题,要加分布式锁才能在不同jvm之前唯一标识一把锁,
通过uuid + 线程id去唯一标识一个线程,避免其他线程误删;
通过lua脚本保证原子性(加锁和设置过期/线程id判断和解锁)
黑马点评06分布式锁 2Redisson-CSDN博客
多线程分布式锁可以用Redission来替代,并且能够解决 重试、重入、超时刷新(看门狗)机制
2.并发模拟测试jmeter
创建好1000个token(用户),放到txt文件。
在jmeter里指定该文件作为token来源,就能模拟1000个用户
因为之前每一步是串行操作的,其中有大量的数据库操作会很影响效率,所以把资格判断和下单业务分离开。
实战篇-23.秒杀优化-基于Redis完成秒杀资格判断_哔哩哔哩_bilibili
3.优化后流程
4.新增优惠券
调用crud
5.基于Lua脚本,判断秒杀库存、一人一单,决定用户是否抢购成功
新lua脚本
6.如果抢购成功,将优惠券id和用户id封装后存入阻塞队列
因为流程改了,所以原来很多java业务转到lua脚本里去了,需要改造代码。
大致流程
具体操作
6.1阻塞队列
没有元素的时候取对象会阻塞,直到有新内容进来。
6.2开启异步下单线程(线程池)
7.新流程
1.先判断资格,有资格就创建订单对象(但没有下单到数据库)把订单加到阻塞队列,否则返回错误。这里用户已经得到结果了,理论上用户知道自己能不能下单。
2.然后执行异步下单,类初始化执行线程池。线程池里的线程不断从阻塞队列取出需要下单的订单信息,然后去进行下单数据库操作。
1)阻塞队列在jvm里,内存有限,订单多了容易溢出
2)如果订单加入阻塞队列,但是服务宕机了,订单会丢失
这里使用的阻塞队列很简单,容易出现很多问题,所以后面引入消息队列。