【redis面试题】如何实现秒杀

1. 秒杀注意事项

限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量(无购买用户限制访问),只允许少部分流量进入服务后端。

异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。

削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。

内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。

2. 设计思路

限流:将请求拦截在系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。

消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。

充分利用缓存:利用缓存可极大提高系统读写速度。

2.1 前端方案

禁止重复提交:用户提交之后按钮置灰,禁止重复提交
用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流

2.2 后端方案

2.2.1 网关服务

限制uid(UserID)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。

2.2.2 服务层

上面只拦截了一部分访问请求,当秒杀的用户量很大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有100W用户同时抢100台手机,服务层并发请求压力至少为100W。
redis设置售罄标记:可以快速返回响应。KV格式:product_sold_productId:true
redis预设置库存:增强并发,减少数据库压力。KV格式:product_stock_productId:100
**采用消息队列缓存请求:**既然服务层知道库存只有100台手机,那完全没有必要把100W个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,消费者redis校验库存,有库存的情况下执行下单返回秒杀成功,无库存返回秒杀结束。

注意事项:
订单超时支付取消订单,退还库存,并重置售罄状态

2.2.3 数据库层

数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。

3. demo

3.1 防止重复下单

用户请求接口的时候,会主动往redis放一个key【proId_userId】,value【userId】。
这里用redis分布式锁。

3.2 售罄标记

当库存为0的时候,会主动往redis放一个key【sold_proId】,value【ture】。
当订单超时取消的时候,会及时更新售罄标记。

3.3 库存值

活动进行之前,可以通过定时,提前把库存放入缓存。key【stock_proId】,value【库存值】
后续通过incr/decr对库存进行操作

3.3 伪代码

sale(productId,userId){
	//todo:0.分布式锁防止用户重复提交 proId_userId
   //1.判断售罄标记
   if(售罄标记为空 or 售罄标记是false){
   		//库存-1
   		库存.decr();
   		//2.判断剩余库存(注意没有=0,因为最后一个秒杀到商品的用户,操作完了库存-1,这时候库存值应该是0)
   		if(剩余库存 < 0){
   			库存.incr(); //因为额外的请求会把库存这个值更新复数,因此如果没有秒杀到的用户需要把预删除的库存做一个返还
   			return "秒杀失败";
   		}
   }
   //3.下单逻辑
   try{
   		...
   }catch(E e){
   		//库存返回
   		库存.inctr();
   		//售罄标记
   		set(售罄标记,false);
   }
}

3.4 可优化点

请求可以放入队列
用一个原子类型的变量值(AtomicInteger)作为key,把用户id作为value,库存数量便是原子变量的最大值。对于每个用户的秒杀,我们使用 RPUSH key value插入秒杀请求, 当插入的秒杀请求数达到上限时,停止所有后续插入。

下单过程可以利用MQ异步处理
消费方启动多个工作线程,
LPOP key 读取秒杀成功者的用户id,执行下单操作。
LRANGE key start end 读取秒杀成功者的用户id,执行下单操作。

文章来源:https://blog.csdn.net/zxc456733/article/details/78864986
视频来源:https://www.bilibili.com/video/BV1CE411s7xN?p=5&vd_source=b901ef0e9ed712b24882863596eab0ca

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值