如何设计一个可靠的秒杀系统

本文介绍了秒杀活动的技术挑战及应对策略,包括页面静态化减少服务器压力,设置特殊秒杀按钮避免无效请求,利用读多写少原则和缓存优化库存检查,使用lua脚本防止超卖,采用异步处理提高用户体验,实施限流措施确保公平性,以及通过Token防止重复购买。这些优化方案旨在提升秒杀系统的稳定性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        秒杀一般出现在商城的促销活动中,指定了一定数量的商品,以极低的价格,让大量用户参与活动,但只有极少数用户能够购买成功。这类活动商家绝大部分是不赚钱的,说白了是找个噱头宣传自己。

虽说秒杀只是一个促销活动,但对技术要求不低。我们在设计秒杀系统时可以做以下优化

一 .页面静态化

        一般在进入抢购页面时,需要向服务器端发送请求,获取商品名称、商品描述等信息,如果此时有很多用户进入抢购页面,服务器端是承受不住这么大的压力的。我们可以将抢购页面作为静态页面,只有当用户点击抢购按钮时才发请求到服务器。

二 .秒杀按钮特殊化

        一般用户为了抢到商品,会在未到抢购时间时疯狂点击抢购按钮,白白给服务器端带来压力,在前端中可以考虑把抢购按钮变为灰色,只有到了抢购时间才能点击,或者限制用户在10s内只能点击几次。

三 .读多写少

        因为用户在进行商品秒杀前都需要检查库存是否足够(读),只有在库存充足的情况下才会减库存(写),由于秒杀商品有限,故大部分的情况是库存不足,这是典型的读多写少的场景。其中一种解决方案是引入缓存,缓存中和数据库中同时保存库存的数量,当用户下订单的时候,先读取缓存中的数据,如果还有库存,先扣减缓存中的库存,然后扣减数据库中的库存,没库存的时候就不会到达数据库。此外,缓存也要使用高可用的主从复制方式。

四 .超卖问题

        显然获取库存数量和更新库存不是原子操作,假设仅有1个库存时,两个线程同时获取到库存数量,并且同时进入stock>0的逻辑,那么就会扣减两次库存,导致超卖。我们可以通过加锁保证两个操作的原子性,但是效率过低。我们可以使用redis并配合lua脚本,保证判断库存数目和更新库存的原子性。

int stock = mapper.getStockById(123);//获取库存数量
if(stock > 0) {
  int count = mapper.updateStock(123);//更新库存
  if(count > 0) {
    addOrder(123); //下订单
  }
}

 五 .异步处理

        一般的秒杀系统中,秒杀成功之后,需要下单和支付,点击下单之后用户应该尽快得到下单成功的提示,并执行后续支付流程,而不用等待后续与订单数据库操作完成之后,有必要将下单服务拆分出来并用mq做异步处理。 值得注意的是在使用mq时要注意消息丢失和重复消费问题。

六 .限流处理

        秒杀场景如果不做特殊的处理,一般会有一些高手通过使用机器或程序直接请求秒杀接口,这比人们手动点击速度要快太多,显然时不公平的。我们需要对同一用户或者ip的请求次数进行限流,或者是在抢购前添加验证码验证是人为操作。

七 .重复购买

        为了防止一个用户重复秒杀多次,客户端可以生成一个能标识唯一用户的字符串,在秒杀前随着用户信息一起发送给后端,例如Token,在秒杀之前,判断该Token是否已经秒杀过了即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值