问题描述
秒杀系统优化以及解决超卖问题_dazou的博客-CSDN博客_秒杀超卖解决方案blog.csdn.net![bc0d4055dc706037bf47ba9f5db9073b.png](https://i-blog.csdnimg.cn/blog_migrate/8f8a788cf412730b7f0676249be9d64a.png)
在众多抢购活动中,在有限的商品数量的限制下如何保证抢购到商品的用户数不能大于商品数量,也就是不能出现超卖的问题;还有就是抢购时会出现大量用户的访问,如何提高用户体验效果也是一个问题,也就是要解决秒杀系统的性能问题。
解决超卖问题
每一个用户只能抢购一件商品的限制;在数据库减库存时加上库存数量判断,库存数量为0时阻止秒杀订单的生成。
- 在数据库减库存时加上库存数量判断,防止数据变为负数
- 数据库加唯一索引,防止用户重复购买
解决性能问题
- 使用Redis缓存预减库存,减少数据库的访问。因为缓存的访问速度比数据库访问快得多。
- 使用内存标记,减少Redis缓存的访问次数。
- 使用队列等异步手段,请求先入队缓冲,异步下单,将数据写入数据库,增强用户体验。
性能解决方案
总体思路就是要减少对数据库的访问,尽可能将数据缓存到Redis缓存中,从缓存中获取数据。
- 在系统初始化时,将商品的库存数量加载到Redis缓存中;
- 接收到秒杀请求时,在Redis中进行预减库存,当Redis中的库存不足时,直接返回秒杀失败,否则继续进行第3步;
- 将请求放入异步队列中,返回正在排队中;
- 服务端异步队列将请求出队,出队成功的请求可以生成秒杀订单,减少数据库库存,返回秒杀订单详情。
- 用户在客户端申请秒杀请求后,进行轮询,查看是否秒杀成功,秒杀成功则进入秒杀订单详情,否则秒杀失败。
缺陷
- 由于是通过异步队列写入数据库中,可能存在数据不一致。
其他解决方案(超卖)
1.redis事务处理
我们可以使用redis中的监听(watch)方法,去监听库存数量,一旦库存数量在其他客户端发生改变,后续操作则会失败。
2. redis分布式锁
分布式锁确保只有一个线程会操作库存
- 加锁(占个位置,后续的进不来):setnx命令: 只在键key不存在的情况下,将键key的值设置为value 。若键key已经存在, 则不做任何动作。
- 解锁(用完了,就把位置让出来):del(key)
- 锁超时(万一中间出现点意外,没有解锁,过几秒会自动释放)expire(key,30)
3.redis队列(rpoplpush的安全队列)
把每一件商品都lpush到redis队列中,利用lpop从队列中去取