2.1.2. 动脑学院 - 阿里双11秒杀模式管理与实现
秒杀只是一个特殊的购物流程。特点:
- 很多人抢(高并发)
- 不能超卖
如:浏览 -> 下单 -> 支付 -> 发货
2.1.2.1. 浏览
浏览量大:可增加缓存解决
2.1.2.2. 下单
2.1.2.2.1. 下单流程
- 修改库存
- 创建订单
- 支付状态:一般有时间限制,会弄一个定时任务,去检查关闭未付款订单
2.1.2.3. 支付
2.1.2.4. 发货
2.1.2. 秒杀模式
- 向上面那种,阿里的模式
- 浏览 -> 下单 -> 支付 -> 发货: 但是修改库存是在支付成功之后。(我自己感觉很不合理)
2.1.2. 修改库存
2.1.2.1. 利用数据库的乐观锁
并发量底,实现起来简单。
int i = update xxx set 库存 = 库存-购买量
where id = xxx and 库存 - 购买量 >= 0
判断i是否更新成功。
缺点: 并发量太低:300 or 700;mysql在HDD硬盘上300左右,SSD上面700左右
2.1.2.2. Memcached
long result = MemCachedClient.decr(key,value);
decr的特性:
原有值 > value = 正常
原有值 < value = 0
有线程安全保证,一旦失败则失败之前的值都没了
但是该API有一个坑,当原有值(100) < value(1000) 的时候,原有值会直接被变成0;
或许我猜测该api就是只要有值就直接减。那么后面如果有用户购买10个产品的时候,也购买不到了,所以不能直接符合需求
曲线救国解决方案:
注:该方法失败,视频中也翻车了。因为不能一步搞定。读取判断再写入就会存在并发脏数据。而又不能在代码中使用同步块和锁等手段。
针对该api的特性,另外增加一个变量来记录成功剪掉的库存数量。
MemCachedClient.set(key1,0); // 用来记录成功剪掉的库存
MemCachedClient.set(key,100); // 用来初始化库存
long result = MemCachedClient.decr(key,value);
if(result > 0){ // 如果成功,累加记录成功的数量
MemCachedClient.incr(key1,value);
}else{ // 如果失败,把 (总的限制库存 - 成功的数量) set回去。
MemCachedClient.set(key,total - MemCachedClient.get(key1));
}
2.1.2.3. redis
优点:事务 - 单进程,单线程
缺点:优点即是缺点。在大规模的并发写入效率不高