秒杀系统,就是在一个很短的时间内面对巨大的请求流量。
秒杀场景的特点
同一时间同时进行抢购,网站瞬时访问流量激增。
访问请求数量远远大于库存数量,但是只有少部分用户能够秒杀成功。
秒杀业务流程比较简单,一般就是下订单减库存
设计思路
1.数据预处理。系统启动时将商品信息存到缓存中,并用唯一id进行标识,将后续逻辑精简为维护用户与ID的关系。在秒杀之前,比如上午十点开始秒杀,很多用户可能在九点五十左右就开始访问自己心仪的秒杀商品,这样就会出现在秒杀之前用很多的并发量,所以在秒杀之前的半个小时之前,可以将参加秒杀的商品信息事先缓存到redis等缓存系统中,这样可以大大的提高系统的吞吐量。
2.限流,黑名单。有的用户为了抢到商品可能利用第三插件,去频繁的访问接口,这样给接口会带来很大的压力,为了避免这种刻意的刷单问题,可以在后台对同一个用户的访问频率做限制,比如可以设置一个用户一分钟不能访问超过60次,10秒内不能超过20次等不同时段不同访问频率策略,这个可以通过redis等缓存框架做到,用户每次访问接口,可以先判断该值有没有达到预设的访问频率限制的值,如果达到了,就告诉用户,你的访问太过频繁,请多长时间后再试,或者要求用户输入验证码。这样就可以从一定程度上避免刷单问题,或者把请求次数太过频繁的放入黑名单。
3.分库分表。服务的可扩展,可以水平添加机器将用户请求分担到不同的机器上去。数据库可扩展,支持分库分表,对于用户的请求,映射到不同的数据库,减少单台数据库的压力。
4.削峰。对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。利用MQ把瞬间的高流量变成一段时间平稳的流量。
5.异步处理。有些秒杀系统可能还有后续的业务逻辑,比如下单之后增加积分,增加积分可以放在MQ异步去操作。将“实时扣库存”的行为上移到内存 Cache 中操作,内存 Cache 操作成功直接给 Server 返回成功,然后异步落 DB 持久化。
这个方案的优点是用内存操作替代磁盘操作,提高了并发性能。
但是缺点也很明显,在内存操作成功但 DB 持久化失败,或者内存 Cache 故障的情况下,DB 持久化会丢数据
6.读写分离。大部分时候数据库可能也是读多写少,没必要所有请求都集中在一个库上,可以搞个主从架构,主库写入,从库读取,搞一个读写分离。读流量太多的时候,还可以加更多的从库。
7.乐观锁替代悲观锁。商品“秒杀”系统中,乐观锁的具体应用方法,是在 DB 的“库存”记录中维护一个版本号。在更新“库存”的操作进行前,先去 DB 获取当前版本号。在更新库存的事务提交时,检查该版本号是否已被其他事务修改。如果版本没被修改,则提交事务,且版本号加 1;如果版本号已经被其他事务修改,则回滚事务,并给上层报错。
大概一些设计思路就是围绕上面几点去展开