秒杀系统设计思路

什么是秒杀系统?

秒杀的场景一般都是商家以促销、预热等活动的形式出现,其主要目的是全民营销以及用户的激活和拉新。

业务特点

  1. 高并发(读、写);
  2. 高可用;
  3. 数据最终一致性要求高(不能出现库存超扣的情况);

设计原则

  1. 热点隔离,秒杀的热点数据隔离处理,报障整个系统的高可用;
  2. 读数据,动静分离,静态数据缓存在客户端或者CDN,动态数据缓存在服务端;
  3. 读数据,不需要做强一致性校验,最终一致性即可;
  4. 写数据,分层校验、“削峰填谷”、限流保护;
  5. 写数据,强一致性校验。

具体方案

热点隔离

核心思想,不要让1%的请求影响到另外的99%,隔离出来后也更方便对这1%的请求做针对性优化。设计多层次隔离:

  • 业务隔离。与产品运营提前沟通好活动产品和方案,做好预热准备工作。技术上,把相关产品加入热点隔离范围。

  • 系统隔离。独立部署集群,和普通商品的服务区分处理。

  • 数据层隔离。数据库、缓存的独立部署。

动静分离

核心思想,细化读请求内容,针对性的进行多级缓存处理。

  • 静态数据。像秒杀活动的商品、活动方案、页面样式等等数据,在整个活动周期内基本不会发生变化,都属于静态数据。静态数据处理,在CDN和客户端加上双缓存。CDN缓存解决大量用户的请求问题。客户端缓存保证单个用户的多次请求问题,并降低CDN节点压力以及网络传输耗时。
  • 动态数据。像商品库存、参与人数等变化数据,都属于变化数据。可以在web端缓存,保证最终一致性即可。
    • 缓存中间件。如redis、Tair等缓冲中间件。
    • 本地缓存。虽然缓存中间件可以处理10W+/S的读请求,但是毕竟还是有请求极限,网卡限制等。在本机加上本地缓存,不用去请求缓存组件,减少网络传输提高效率,也可以一定程度上保护缓存组件。

读数据的最终一致性

像读数据的请求,如秒杀库存、参与人数等数据,从业务场景上并不需要绝对的实时数据,允许一定程度的数据延迟。所以可以加上缓存,来应对高并发场景,并定时更新数据即可。更新方式主要两种:

  • 被动更新。设置缓存失效时间,当缓存失效后可以从DB加载数据到缓存中。可能出现缓存并发(也叫缓存击穿)问题。
  • 主动更新。在失效前提前异步加载最新数据到缓存(应对缓存并发问题)。解决缓存并发问题,唯一不足的是可能会出现各个应用节点极其短暂的不一致情况,这个对互联网应用来说是完全可以接收的。推荐采用。

写数据,分层校验

核心思想,尽早返回处理结果。从请求的全链路角度出发,分层校验,减少无效请求,尽早返回结果。
请求漏斗模型

写数据,“削峰填谷”

针对瞬时的大量请求的高并发问题,一般的通用解决思路就是加入队列缓冲,实现“削峰填谷”。

写数据,限流保护

没有什么是不可能的。就算我们做了上面一系列的优化措施,还是有可能扛不住请求的并发。为了保证系统的可用性,还是需要做限流保护。限流后可能会出现雪崩效应(单机到达限流阀值拒绝请求,这部分请求转嫁给其他机子,其他机子也会更容易到达限流阀值,最终导致服务不可用。)。

  • 解决方案:
    • 提前准备横向扩展的服务器。数据提前预估。
    • 设置多级限流阀值。
    • 当到达一定阀值的时候,动态横向扩展服务器,并发送警告通知。

写数据,强一致性校验

  • 数据库层(不推荐)
    • 悲观锁。innodb行锁(共享锁/排他锁)。
    • 乐观锁。version版本号控制。
  • 应用层
    推荐: 在应用层虚拟扣除库存成功后,然后队列处理到DB层。

    redis的watch命令+multi命令,扣除成功后同步到订单子系统。

    watch命令对目标Key进行标记后,当事务提交时,如果监控到目标Key对应的值已经发生了改变,那么也就则意味着版本号发生了改变,因此这一次的事务提交操作就失败。

提高下单成功率

通过redis的watch命令处理,基本上可以满足秒杀场景的写需求。但是当秒杀的商品数量比较多的时候,比如上万的库存量,watch的重新尝试次数会变多,整体上来讲碰撞率会很高,从用户角度来看就是秒杀时系统反应时间过长,体验不好。

分析原因:根本上来说所有请求是对单个商品key进行处理导致的。如果采用分流方式,某部分请求key1,某部分请求key2,通过分流针对不同的key进行watch,降低碰撞概率,提高下单成功率。

把1个商品key拆分为1个父key+多个子key,每个key占用一部分库存,所有子key对应的商品数量和等于父key对应的商品数量。

  • 随机watch子key,当这个子key产生碰撞后,重新随机watch子key。
  • 当子key的事务成功提交后,把父key的商品数量相应扣除。
  • 当子key的商品数量为0时,维护子key列表剔除这个子key。
  • 当父key的商品数量为0或者子key列表为空时,直接返回库存为0的结果。

拆分的数量也不是越多越好,一般10-20个子key,理论上会有10-20倍成功率提升。

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
秒杀模块是一个高并发、高可用性的场景,需要考虑多方面的因素,以下是一个设计秒杀模块的思路: 1. 预热:在秒杀活动开始之前,需要对系统进行预热,将商品信息、活动规则等数据加载到缓存中,以提高系统的响应速度。 2. 并发控制:为了避免系统崩溃或者性能下降,需要对请求进行并发控制。可以采用限流、队列、分布式锁等方式进行控制。 3. 库存控制:秒杀活动中库存是一个重要的考虑因素。需要对库存进行实时的更新和控制,避免超卖或者少卖的情况。 4. 订单处理:在秒杀成功后,需要生成订单,并对订单进行处理。可以采用异步处理的方式,将订单放入队列中进行处理,避免请求过多导致系统阻塞。 5. 缓存优化:为了提高系统的响应速度,可以采用缓存优化的方式,将热点数据缓存到内存或者分布式缓存中,避免每次请求都需要查询数据库的开销。 6. 数据库优化:为了避免数据库成为瓶颈,需要对数据库进行优化,包括索引优化、读写分离、分库分表等方式。 7. 安全防护:由于秒杀活动的高价值,需要考虑安全因素。可以采用验证码、IP黑名单、风控系统等方式进行安全防护。 8. 监控和调优:在秒杀活动中,需要对系统进行实时监控和调优,包括性能监控、日志监控、异常监控等方式,避免出现问题导致系统崩溃。 以上是设计一个秒杀模块的基本思路,具体实现需要根据具体的业务场景进行调整和完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值