问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

秒杀系统关键技术详解:缓存预热、库存预扣与异步下单、超时未支付库存回填

创作时间:
作者:
@小白创作中心

秒杀系统关键技术详解:缓存预热、库存预扣与异步下单、超时未支付库存回填

引用
CSDN
1.
https://m.blog.csdn.net/weixin_43889578/article/details/140833350

缓存预热

缓存预热是应对秒杀场景瞬时高并发读请求的一种有效手段。假设我们没有对缓存做预热处理,即使我们的系统使用了缓存,由于系统刚上线时缓存中数据为空,数据库依然有被击垮的可能性。由于热点数据没有加载到缓存中,当秒杀开始时,大量请求由于缓存缺失,都涌向了数据库,此时数据库就会面临很大的压力。

因此,我们要加入缓存预热的处理,处理逻辑如下:

  1. 运营在后台管理系统发布了一个秒杀活动。
  2. 保存秒杀活动信息,经过各种处理,处理完毕后,发一条消息到MQ,消息携带秒杀活动涉及到的商品的商品ID。
  3. 异步服务监听MQ消息,取得秒杀活动涉及的商品的商品ID。
  4. 开启定时任务(确保定时任务在秒杀开始前到期)
  5. 定时任务到期时,查询商品信息、库存等数据,加载到缓存中。

或者使用RocketMQ的延时队列,也能达到同样的效果:

此时就不需要定时任务了,但是要确保延时队列的延时时间在秒杀活动开始前到期。缓存预热处理的关键就在于确保秒杀涉及的热点数据在秒杀活动开始前被加载到缓存中。

库存预扣 & 异步下单

由于扣库存和下单涉及到写数据库,在秒杀这种高并发场景下,采取扣库存和保存订单信息同步处理的方式的话,很容易成为性能瓶颈。因此在秒杀场景下,一般的做法是库存预扣,然后异步进行订单信息的落库以及数据库中的库存扣减。

由于我们前面预热的时候已经把库存加载到缓存中,因此库存预扣直接在缓存中扣减即可:

  1. 秒杀下单服务接收到用户的下单请求
  2. 检查Redis中对应商品的库存是否充足,如果充足,则扣减库存,如果不充足,则返回下单失败
  3. 如果扣减库存成功,则发送异步下单消息
  4. 返回下单成功

“检查Redis中的库存”,“以及扣减Redis中的库存两个动作”,必须保证原子性,因此这里可以使用Lua脚本来处理。Lua脚本在Redis中执行可以保证脚本中的多个动作具有原子性。

然后异步服务监听到异步下单消息时,就可以保存订单信息到数据库,以及在数据库中做真正的库存扣减:

超时未支付库存回填

下单成功后,用户就会跳转到支付页面,用户要在指定时间内(比如15分钟)完成支付,用户支付成功后,就返回秒杀成功。但是有时候用户超时了也没有进行支付,此时除了要告知用户比如“超时未支付,秒杀失败”等的消息外,还要把扣减的库存回填回去,如果缓存中还有售罄标志,那么还要把该标志修改为false,此时秒杀按钮再次从灰变成亮。

除此之外,还要更新各秒杀服务的本地缓存,这里可以使用Redis的Pub/Sub(发布订阅)功能进行处理。

  1. 下单成功后,往RocketMQ的延迟队列发送一条消息,延迟时间取决于支付的超时时长。
  2. 当该消息的延迟时间到时,异步服务监听到消息,查询数据库该订单的状态,如果状态为已支付,则不做处理;如果订单状态不是已支付状态,那么就要进行库存回填处理。
  3. 首先往Redis回填库存数量,并且如果有售罄标志为true的话,还要修改为false。
  4. 然后使用Redis的Pub/Sub功能,往Redis中的指定Channel中Pub一条消息。
  5. 此时各秒杀下单服务监听(Sub)到消息,于是更新本地缓存。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号