架构实战案例解析
王庆友
前 1 号店首席架构师
18817 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 23 讲
架构实战案例解析
15
15
1.0x
00:00/00:00
登录|注册

17 | 高性能架构案例:如何设计一个秒杀系统?

你好,我是王庆友。
在上一讲中,我和你详细介绍了打造一个高性能系统的应对策略和架构手段。那么今天,我就以 1 号店的秒杀系统为例,来具体说明如何实现一个高性能的系统。

背景和问题

先说下背景。在 2014 年的时候,1 号店作为网上超市类电商,经常在线上举行各种大促活动。比如进口牛奶促销活动,每次促销的牛奶有几十万盒,促销价格非常优惠,一般这样的促销活动会在某个整点的时间进行开卖(如上午 10 点)。对于这种质高价优并且是刚需的商品,会有大量的用户来抢购,俗话说“手快有,手慢无”,往往短短几分钟内,所有牛奶就能售卖完毕。
这本质上是一种秒杀活动,但商品数量非常大,一瞬间会有大量的用户流量涌入,流量可以高达平时的几十倍。而且和少量商品的秒杀不同,这些都是有效流量,最终会生成订单。
而在正常情况下,系统因为资源有限,只能处理 10% 的流量,无法处理剩下的 90% 流量,瞬间高并发的流量涌入,很大程度上会引起后台系统超时报错,导致用户下单不成功。这样一来,用户就会反复刷新页面,多次尝试下单,不但用户的体验不好,而且系统的压力会更大。
最终的结果就是,系统往往由于过载,整体处理能力下降,甚至瘫痪,导致所有用户都无法购买。就像下图表示的一样,在秒杀场景下,系统会面临这样的困境:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文以1号店的秒杀系统为例,详细介绍了设计高性能秒杀系统的关键策略。在传统系统中,瞬间高并发的流量会导致系统超时报错,用户体验不佳,系统处理能力下降,甚至瘫痪。为了解决这一问题,文章提出了利用异步处理的思路来应对秒杀活动,通过排队系统实现前端瞬时大流量的快速处理,同时保证后台订单生成的匀速处理,从而保证了系统处理订单的能力,也保证了用户良好的体验。排队系统使用Redis作为队列技术选型,为每个秒杀商品提供单独的队列,通过合理的调度和队列长度设置,保证了用户能够买到商品。文章还介绍了建立活动库存的优化策略,以及对于不同场景的适用性讨论。通过这些策略,读者可以深入了解如何保障系统的高性能,并在实践中参考这里的做法。整体架构设计合理,既保证了系统的高性能,又保证了用户体验。文章内容详实,对于设计高性能秒杀系统的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《架构实战案例解析》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(26)

  • 最新
  • 精选
  • 小祺
    20W用户下单成功,后面的用户提示下单失败,预下单成功的用户全部放弃支付,导致活动结束了但是商品没卖出去,怎么解决?

    作者回复: 后台下单时,会有异常订单自动审核,比如黄牛下的单,恶意订单等,这部分库存会回到前台可用队列中,只要是正常订单,不会出现大面积不支付的情况

    2020-03-31
    2
    14
  • zeor
    老师您好,当正常下单时采用同步方式,但流量也很大,如果按您说的,库存只有一个库,但库已经达到了瓶颈,有什么方式在同步情况下解决这个瓶颈?

    作者回复: 可以用redis放库存数据,利用redis的锁保证互斥访问。这样相当于把redis作为前置数据库。 应用直接改redis数据,通过发消息,再异步改db的数据。

    2020-03-30
    3
    9
  • 独孤九剑
    请问老师,如何处理“商品详情页”在秒杀时间段的过载问题呢?

    作者回复: 一般来说,减轻后端处理有两种方式,可以在服务端做页面级缓存,比如squid缓存,在访问tomcat前即返回详情页内容。也可以在前端通过ajax获取必须的信息,比如库存/价格。 在秒杀场景下,具体看业务上要求是什么。

    2021-05-16
    3
    3
  • 蓝天
    排队数据存在redis中是不也需要开启持久化呢

    作者回复: 很好的思考,要持久化的,这是关键的业务数据。

    2020-03-31
    2
    2
  • J.Smile
    如果有些前置知识会比较好,比如流量洪峰到来的时候对于秒杀这种类型的活动,首先要把流量接下来,起码不能在网关入口处就被拒绝了,这个时候能用到的技术有哪些,比如nginx或者其他的方式。接下来,流量怎么分发到后端的应用服务器,负载均衡或者是直接操作redis,这里也有一些技术点。 老师整体上讲的比较言简意赅,不过我还是想关注下一些技术点,哪怕一笔带过略微提一下,也可以受益匪浅哈!感谢!

    作者回复: 对于接入系统来说,这点流量照常接,没有变化,所以文章里就没提

    2020-03-30
    2
  • 大龄程序员在线治掉发
    用户在排队中,如果要通知用户秒杀成功或失败,这个时候是不是应该使用websocket的方式推送?

    作者回复: websocket也可以,不过实现比较复杂一点。直接定时轮询就可以,前提是服务端处理很快,本案例查缓存,几个ms就能返回。

    2021-05-30
    1
  • 图灵机
    redis list 没有设置初始长度的操作吧,那么这个初始长度值是另存到一个key中吗,这样的话每次新增订单需要先查一次初始长度和list llen吧?还有lindex是时间复杂度O(n)的操作吧,假如都是十万量级的list长度,redis是用链表去存,这样的话遍历也用不到局部性原理,实际应用中需要考虑这种问题吗?还有一个问题就是处理完成的订单订单号会从队列里弹出吗,这样的话和商品数量1:1的队列长度再有新的订单号进来不就超过实际商品量了吗?如果处理订单是维护一个游标移动的话是不是就符合这个问题了

    作者回复: 理解本质就好,不用纠结细节哈。

    2020-08-05
    4
    1
  • 乖,摸摸头
    根据排队号获取消息在队列中的位置,是怎么实现的?redis list 并没找到这样的接口。如果是通过 LINDEX 来获取,感觉比 遍历还慢。 为啥还要弄个请求队列,不直接去读商品秒杀队列,商品队列读取不到了就返回失败

    作者回复: 应该是LINDEX接口,用起来性能还可以。 请求队列包含下单所有信息,商品,用户,收货地址等,是一个预定单的概念,不知你说的商品秒杀队列具体是什么概念。

    2020-06-15
    1
  • 旅途
    老师,后台服务消费队列的线程数这个是压测得来的吗,这个是使用的程序内部的线程是吧

    作者回复: 这个主要是评估后面下单服务的处理能力,把下单能力充分发挥就可以。每个消费者是一个线程

    2020-05-28
    1
  • 小洛
    首先感谢老师您的分享 有两个问题请教下老师: 1、一个秒杀商品一个单独redis队列,如果秒杀商品几十万,就算按照1:1的比例 那么理论上瞬间也有10万的请求打到redis上,单个redis 支撑10W, 这里是不是还有一些限流的策略? 2、老师能加餐分享下库存的方案吗

    作者回复: 10万请求入队,是分1-2分钟,处理得过来,要限流的话,直接在接入层就限流。

    2020-04-05
    1
收起评论
显示
设置
留言
26
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部