秒杀系统

简介: 秒杀能够以极小的经费撬动巨大的流量,虽然会带来一定的口碑损失,但因为极具性价比,所以经常被运营同学使用。本文介绍如何设计一款能够支撑60W QPS的秒杀系统,希望能够帮助到大家。

简介

秒杀能够以极小的经费撬动巨大的流量,虽然会带来一定的口碑损失,但因为极具性价比,所以经常被运营同学使用。本文介绍如何设计一款能够支撑60W QPS的秒杀系统,希望能够帮助到大家。

这套系统有着漫长的演变历史,从最初利用Nginx、PHP,到后来使用GO,团队慢慢的将系统做的更加稳定。唯一不好的地方是,当年我写的后台还在使用(写前端代码能力有限),运营配置体验上有些瑕疵,后期需要优化一版。

目前14台8+32的机器,可以支撑60W QPS,理论上还能支持的更高,不过单ELB的上限是60W,即使流量再高,在ELB层也会溢出了。

一般大家听到秒杀系统,最可能想到的是高并发,但高并发只是其中的一部分,需要其他的组件一起配合,才算是一个完整的秒杀系统。

本文从这几个方面来讲述该系统

  • 后台
  • 高并发系统设计

    • 获取活动信息
    • 秒杀
    • 统计

不过在讲述之前,我们先看一下应用场景,让大家对秒杀有一个直观的了解。

在活动页面上会有抢购模块,会展示抢购的时间、商品图片、商品名称、秒杀价、商品价等信息。活动开始之前按钮为Coming soon。

当活动时间到了,按钮会变为Buy now,瞬间服务器压力飙升。点击Buy now时,如果秒杀成功,会跳转到购物车页,这时候只需要按照正常流程支付即可。如果不成功,按钮会变为Out of stock。当然,如果不点击Buy now按钮,该按钮文案不会变更,除非重新刷新页面。

秒杀活动完成后,会在页面上展示秒杀成功用户的id。之所以添加这个功能,是因为很多用户投诉这是假秒杀,作为商家,做活动也不容易。

后台

通过对场景的描述,可以分析出后台需要配置的内容。https://www.processon.com/view/link/5fb0a1e75653bb657c335c60

  1. 每场活动配置:需要配置每场秒杀活动的开始时间和结束时间,以及参加秒杀的商品信息。还有一些特殊需求,如只有用户分享后才能参与秒杀等。

  1. 对于活动配置,需要有编辑、推送、校验、测试功能

    • 校验功能:主要用于查看推送出去的数据是否和配置的数据一致,主要用来检查系统正确性、运营操作正确性
    • 测试功能:主要用于白名单测试,使测试人员可以在活动页面真正的演练秒杀过程,同时又不影响正常用户。因为一次秒杀活动可能有多个场次(如每天一场秒杀,每场秒杀两个商品,持续7天),为了让测试同学方便配置,只需要设定好第一场的时间,根据每场活动时间间隔,其他场次的秒杀会自动配置好,商品数量只需设置一次,所有场次商品数量都为该值。

  1. 监控后台,必然需要监控线上情况,但是对于测试情况也需要进行监控,主要为了便利测试人员查看。监控一般关注于:中奖用户、秒杀卖出数量是否和配置数量一致、参与用户数、QPS峰值

    最重要的当然是中奖用户数量、秒杀卖出数量与活动配置数量是否一致,如果不一致,那肯定是出问题了,后面面临修数据、补数据。

  2. 黑名单管理:有些地区的用户,十分喜欢用脚本刷,对于这些用户,一部分通过程序自动抓取,一部分分析得出后,使用该管理平台,手动添加。

秒杀系统的后台给大家讲完了,下面我们进入大家感兴趣的高并发处理环节。

高并发系统设计

获取秒杀活动信息

获取秒杀活动信息,相对比较简单,核心是通过goroutine,设置计时器,每过一段时间从Redis拉取数据,同步到本地缓存,这样能大大减小Redis的压力。

目前该接口,在8+32的机器上,qps能支持到3~4W左右,其实仍然有一定的提升空间。

  1. 可以将部分不变的数据放到CDN,库存、当前场次等动态变化的信息提供新接口,这样可以进一步减少后端冗余的逻辑和返回数据量,不过对前端要求会提高。
  2. 即使是在当前的逻辑中,有部分场次的活动,因为并不参与展现,所以可以不参与计算,同时也无需返回,一定程度上也能提高性能。

秒杀接口

秒杀接口为最核心的接口,需要保证指定数量的秒杀商品不超卖,也不少卖。这个接口决定了秒杀系统的最终准确性。本来这个接口也做了流程图,不过一是里面有些内容涉及到隐私,另一方面如果给出流程图,可能大家的设计就都一样,少了很多其他的可能性。所以这里只阐述核心点:

  1. 使用两级限流措施,第一级为随机限流,第二级为令牌桶,限流的比例根据预估流量和商品数量来限制,尽量确保1s内所有商品售卖完成。例如,10个商品,60W请求,如果随机限流设置为千分之二,意味1s只有1200个请求能真正走到逻辑层,逻辑层压力会小很多。而令牌桶能够防止逻辑层过载。
  2. 黑客是需要重点考虑的对象

    • 如果提前请求则标记为黑客,进行记录
    • 如果1s内同一个用户多个请求到达逻辑层,标记为黑客,进行记
  3. 对于走到逻辑层的请求,需要做众多判断,确保系统准确性

    • 该用户或者IP不在黑客列表里
    • 该用户本次活动中没有秒杀成功过
    • 同一个用户不能获得两次秒杀成功的机会
    • 是否仍然有足够的库存
    • 帮用户按照秒杀价添加到购物车

本系统使用Redis来管理库存,虽然使用两级限流后,Redis负载不大,但是仍然有出错的可能性。

在库存管理上,通过一切检查后,如果符合规定,会先扣减库存。这样保证了不会超卖。

有一种情况,如先扣减库存,添加购物车失败,但是归还库存失败,这样会导致少卖。对于这种情况,目前做法为记录日志,活动结束后,如果数据不对,根据日志进行补发。

对于这种情况的优化,我能想到的办法有错误重试、错误写入队列后异步处理、分析日志自动处理错误。这几种方案,在某些极端情况下,仍然会失效,如果大家有更好的方案可以提供一下。

不过因为日志的存在,让我们有了保底的方案,而且如果在如此小流量下,Redis都无法稳定的话,可能问题就不仅仅是这一个服务了。

统计

对于秒杀成功用户的统计,比较容易完成,秒杀成功后写入Redis即可。

但是对于秒杀流量的统计,就无法使用这种方案了,毕竟60W的流量,Redis可能也撑不住。

这里介绍一个比较巧的方案。

  1. 每次请求秒杀接口时,使用golang的原子操作,将统计变量statNow的值加1
  2. 起goroutine,设置定时任务,计算当前统计总数与上次统计总数的差值,写到Redis中

ticker := time.NewTicker(time.Millisecond * 100)

go func() {
    for range ticker.C {
        orig := atomic.LoadUint64(&statOrig)
        now := atomic.LoadUint64(&statNow)
        num := int64(now - orig)
        if num > 0 {
            //将增加的数值incr到Redis中
        }
        atomic.SwapUint64(&statOrig, statNow)
    }
}()

## 总结

Golang是门好语言,帮我们解决了众多问题。单机使用Nginx,并发2W左右,不使用Nginx,直接用go,并发4W,在语言层面上直接解决了高并发问题。

使用两级限流策略,保证服务器压力可控。

灵活运用Go提供的功能,Goroutine、定时器、本地存储、原子操作、读写锁等。

合理使用Redis,保证服务的准确性与稳定性。

虽然还有少许的待完善点,但并不影响使用。

如果后续压力继续增加,一个可行方案是CDN边缘计算。当然,如果有钱,不必这么扣扣索索的,堆机器也是可以的。

## 最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的[个人博客](https://shidawuhen.github.io/)

**往期文章回顾:**

**技术**

1. [秒杀系统](https://mp.weixin.qq.com/s/JAC8M_4D2wPoRKhWTbv_CA)
2. [分布式系统与一致性协议](https://mp.weixin.qq.com/s/pbGLGcQqocuVTmhDfxmHqQ)
3. [微服务之服务框架和注册中心](https://mp.weixin.qq.com/s/sw5JVKtvYx1Jgsf5KSPXmg)
4. [Beego框架使用](https://mp.weixin.qq.com/s/xLmVs2kf_2KoXJw2kZkxzw)
5. [浅谈微服务](https://mp.weixin.qq.com/s/zOIkb2CQcjA9-TemGA9pYg)
6. [TCP性能优化](https://mp.weixin.qq.com/s/SwYcLLKhvv2lCjgew3sv9A)
7. [限流实现1](https://mp.weixin.qq.com/s/hG6QrPPTHjqEaUVQhjDdBg)
8. [Redis实现分布式锁](https://mp.weixin.qq.com/s/3i0fVLgAYc_QkvBvTW2JCQ)
9. [Golang源码BUG追查](https://mp.weixin.qq.com/s/pfV1guaUwUlkiZx6xdXzxg)
10. [事务原子性、一致性、持久性的实现原理](https://mp.weixin.qq.com/s/yQM9vzhFxgCrzkx3EjfIPQ)
11. [CDN请求过程详解](https://mp.weixin.qq.com/s/HFfs0sJjY8cwpDYaIa5ZjQ)
12. [常用缓存技巧](https://mp.weixin.qq.com/s/xElsNUjxiT0MYZuVJct6Gw)
13. [如何高效对接第三方支付](https://mp.weixin.qq.com/s/NM34aevx3DBT1czcoFMJWw)
14. [Gin框架简洁版](https://mp.weixin.qq.com/s/X9pyPZU63j5FF4SDT4sHew)
15. [InnoDB锁与事务简析](https://mp.weixin.qq.com/s/K8s_1cYRK5mkY_b4_XOeng)
16. [算法总结](https://mp.weixin.qq.com/s/pg94QcxIttHUBlGnHBW4zQ)

**读书笔记**

1. [敏捷革命](https://mp.weixin.qq.com/s/8k5UI9zC5Fap1NzKBE6YCQ)
2. [如何锻炼自己的记忆力](https://mp.weixin.qq.com/s/q05zTz49--tJmnYCboLOQw)
3. [简单的逻辑学-读后感](https://mp.weixin.qq.com/s/Xh-yhWpQjMYeVFKhXOw3zA)
4. [热风-读后感](https://mp.weixin.qq.com/s/kYvJA6pZPh5OQ_8xG620-A)
5. [论语-读后感](https://mp.weixin.qq.com/s/ufPVVxgawx3KuoTuZjMRUQ)
6. [孙子兵法-读后感](https://mp.weixin.qq.com/s/qiKAFo-bNV5efpWrmQbadg)

**思考**

1. [对项目管理的一些看法](https://mp.weixin.qq.com/s/TAx5oKNpfN7nDUi7bIT1wg)
2. [对产品经理的一些思考](https://mp.weixin.qq.com/s/gDGcnQw_0oRFbDnfE6uoOQ)
3. [关于程序员职业发展的思考](https://mp.weixin.qq.com/s/QR2_3j1rbfiXoZGlSqpSRw)
4. [关于代码review的思考](https://mp.weixin.qq.com/s/M0ExjoIGHVA6bI9g8ZLAog)
5. [Markdown编辑器推荐-typora](https://mp.weixin.qq.com/s/TeYMjeJOmKm2cbZychLcOw)
相关文章
|
存储 人工智能 架构师
ChatGPT 与软件架构 (2) - 基于 Obsidian 和 GPT 实现解决方案架构自动化
ChatGPT 与软件架构 (2) - 基于 Obsidian 和 GPT 实现解决方案架构自动化
448 0
|
人工智能 运维 安全
阿里云函数计算 AgentRun 全新发布,构筑智能体时代的基础设施
阿里云推出以函数计算为核心的AgentRun平台,通过创新体系解决开发、部署、运维难题,提供全面支持,已在多个真实业务场景验证,是AI原生时代重要基础设施。
|
安全 Linux 应用服务中间件
从零开始启动、配置、保护你的云服务器并搭建一个简单的网站
本文详细介绍了如何准备原料、搭建基础环境、进行安全防护、建设网站、管理证书以及开启BBR优化网络性能。主要内容包括获取健康云服务器、配置SSH登录、创建非root用户、启用密钥认证、安装Nginx、申请TLS证书、配置HTTPS自动跳转及优化网络性能等步骤。通过本文,读者可以掌握从零开始搭建个人网站的全过程。
470 2
从零开始启动、配置、保护你的云服务器并搭建一个简单的网站
|
6月前
|
存储 运维 安全
OSS安全合规实战:金融行业敏感数据加密+KMS自动轮转策略(满足等保2.0三级要求)
金融行业OSS面临等保2.0、行业监管及数据泄露三重合规挑战,存在存储加密不足、密钥轮转滞后、访问控制不当等问题。本文提出分层加密架构,结合服务端KMS与客户端加密,设计自动密钥轮转机制,实现高性能与合规兼顾,并提供故障排查与成本优化方案,助力金融机构安全落地OSS应用。
323 1
|
10月前
|
机器学习/深度学习 资源调度 数据可视化
YOLOv11改进策略【损失函数篇】| 将激活函数替换为带有注意力机制的激活函数 ARelu
YOLOv11改进策略【损失函数篇】| 将激活函数替换为带有注意力机制的激活函数 ARelu
448 6
YOLOv11改进策略【损失函数篇】| 将激活函数替换为带有注意力机制的激活函数 ARelu
|
11月前
|
人工智能 机器人
LeCun 的世界模型初步实现!基于预训练视觉特征,看一眼任务就能零样本规划
纽约大学Gaoyue Zhou等人提出DINO World Model(DINO-WM),利用预训练视觉特征构建世界模型,实现零样本规划。该方法具备离线训练、测试时行为优化和任务无关性三大特性,通过预测未来补丁特征学习离线行为轨迹。实验表明,DINO-WM在迷宫导航、桌面推动等任务中表现出强大的泛化能力,无需依赖专家演示或奖励建模。论文地址:https://arxiv.org/pdf/2411.04983v1。
333 21
|
存储 安全 开发工具
基于ESP32的便携式游戏机
基于ESP32的便携式游戏机
358 2
|
SQL BI 数据库
如何在 SQL Server 中使用 `CONCAT_WS`
【8月更文挑战第10天】
481 3
如何在 SQL Server 中使用 `CONCAT_WS`
|
监控 数据可视化 API
探索低代码/无代码平台的崛起及其对开发者的影响
【10月更文挑战第14天】低代码/无代码平台通过可视化工具和预构建模块,使非技术用户也能构建应用,改变了软件开发格局。这不仅降低了开发成本,提高了效率,还促使开发者角色向顾问和策略师转变,加速了创新,扩大了市场。文章探讨了其核心优势及对开发者的影响。
|
机器学习/深度学习 数据可视化 测试技术
统计学入门:时间序列分析基础知识详解
本文探讨了时间序列分析的核心概念,包括自协方差、自相关和平稳性。通过Python实现和图形化展示了这些概念,以增进理解。时间序列涉及观察随时间变化的数据,如心率或温度。自协方差和自相关衡量数据点之间的关系,滞后表示时间间隔。弱平稳性意味着均值、方差和协方差不随时间变化。文章介绍了自回归(AR)、移动平均(MA)、ARMA和ARIMA模型,用于描述不同类型的序列行为。统计检验如ADF和Durbin-Watson用于检测平稳性和残差自相关。ARIMA模型特别适用于非平稳数据,通过差分实现平稳化。文章还提供了代码示例和可视化来辅助学习。
573 4