news 2026/8/12 10:33:12

【高并发秒杀架构】(4)电商秒杀架构升级方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【高并发秒杀架构】(4)电商秒杀架构升级方案

本文为「电商秒杀架构」系列第四篇,结合其他电商公司的经验,针对电商项目当前的秒杀系统,从架构梳理、痛点分析出发,系统梳理三类常见的架构升级方案:Redis 垂直拆分方案、库存预分配方案、动态库存分配方案。


一、秒杀系统当前的架构梳理

先回顾一下当前秒杀系统的整体架构:


二、当前架构的痛点分析

从系统扩容的角度来分析当前架构,Redis 最容易成为性能瓶颈。因为秒杀应用可以基于 Nginx 反向代理进行水平扩展,RocketMQ 也可以通过集群配置进行水平扩展,而 Redis 则相对扩展比较困难。

而对于 Redis,为了保证缓存数据的读写性能,当前架构中优先保证的是从 Redis 与秒杀应用部署在同一个服务器上,这样可以最大限度提升缓存的读写性能。但是,这也让 Redis 成为后续系统扩容的瓶颈。所以,秒杀系统后续如果要进一步提升性能,最需要调整的是其中 Redis 部分。

为此,我们先将当前秒杀系统中 Redis 部分的核心架构整理出来,以便后续进行重点分析:

你可能第一眼就会看到,这样单点的 Redis 服务,显然是不符合高并发应用的集群化要求的。但是,你要注意,其实 Nginx 节点是可以和应用一起扩展的——后续可以部署多个 Nginx 节点,然后同样给每个 Nginx 节点配置一个 Redis 从节点,这样就可以进行整体扩容。像这样:

所以,当前架构的核心痛点,其实并不在于单点 Redis 的性能问题,而是单点 Redis 的数据压力会比较大

当前我们电商项目中,秒杀的商品还不太多,数据比较少。但是如果后续秒杀商品多起来,单点 Redis 的数据压力就会比较大,这会极大地影响 Redis 的性能。


三、常见改进方案

3.1 Redis 垂直拆分方案(集群化)

既然单点的 Redis 数据量不够,那么最简单的想法就是将单机 Redis 升级成为集群,通过集群机制扩充 Redis 的数据量:

升级成为 Redis 集群后,Redis 的数据量问题得到了解决。但是要注意,在秒杀场景下,我们也不是简单升级完 Redis 集群就可以了。采用集群部署 Redis 后,因为大部分的 Redis 客户端都是通过连接池实现的,此时 Redis 的连接数就会逐渐成为瓶颈。一般的办法是通过中间件来减少连接数,例如使用TwemProxy于 Redis 之间建立单链接交互,并通过 Twemproxy 实现分片逻辑,这样我们就可以水平扩展出更多的 Twemproxy 来增加连接数:

此时遇到的问题就是 Twemproxy 实例众多,应用维护、配置困难,需要在这之上做负载均衡。比如,通过LVS/HaProxy实现 VIP(虚拟 IP),就可以做到节点切换对应用透明、故障自动转移;还可以通过实现内网 DNS 来做其负载均衡:

通过 Redis 的集群化部署,多个 SKU 的数据,最终会分散到各个 Redis 节点当中,我们就可以解决 Redis 数据量太大的问题。并且,基于 Redis 集群的方式,Redis 服务的可用性也得到了提高——我们可以通过再加入哨兵机制等方式,保证少量 Redis 节点挂了后,整个 Redis 集群不会出现问题。

3.2 库存预分配方案

通过 Redis 的集群化部署,我们就可以解决 Redis 数据量太大的问题。但是,与之前架构不同的是,我们只能使用一致性算法实现 Redis 集群,而这样就无法保证每个 Nginx 只读取本地的 Redis,这样其实会对 Redis 的读写性能产生一定的影响:

所以,在很多互联网企业中,不会直接使用 Redis 的集群架构,而是搭建多个 Redis 节点,并通过库存预分配的方式,自行控制 Redis 中的数据分布。

例如,自行搭建多级 Redis 缓存:第一级 Redis 管理总的秒杀库存。在秒杀活动开始时,增加一个库存预分配的程序,将总库存分配到多个二级 Redis 中。然后,在每个二级 Redis 上,就可以搭建一个对应的 Nginx 加 APP 的秒杀应用,每个应用就只访问对应的二级 Redis。而二级的 Redis 就可以还原成我们当前秒杀系统中的单点架构,从而保证每个 Nginx 加 APP 的秒杀应用可以只访问本地的 Redis。

通常建议都配置成1+1的组合,这样可以尽量保证每个 Nginx 和秒杀应用都操作本地的 Redis,也就不用再另外维护秒杀应用与二级 Redis 的对应关系:

这样调整后,给整个秒杀架构带来了非常明显的优点:

  • 通过预分配库存的方式,可以让每个应用都有一套独立的库存数据,各个应用之间处理库存时互不干扰,从而大大降低并发量,以应对高并发,应用也就可以横向扩展。
  • 由于各个应用扣减库存的速度不一致,这也可以一定程度上防止羊毛党。
  • 具体扩展多少个应用和预分配多少套库存数据,要看两个纬度:一个是并发量,一个是活动的库存数据。不同热度的秒杀活动可以配备不同的资源;在当前项目中,只要在前端引导用户进入不同的静态页面即可。
  • 可以一定程度上解决热点商品的问题:由于每个二级 Redis 里可以分配多个 SKU 的活动信息,因此每个二级 Redis 对应的秒杀应用,也可以承载多个商品的秒杀活动。这样,即使出现某一个特别火热的热点商品,也可以通过部署多个秒杀应用的方式,增加热点商品的承载能力。

但是,这个架构也有它自己的不足之处:

  • 前端秒杀页合理导航的问题:在我们的秒杀系统中,是通过往 OpenResty 中发布的静态页面作为秒杀的入口的。如果想要多个服务平均地承载同一个商品的秒杀服务,就需要在前端进行合理的导航,将不同的用户导入到不同的 OpenResty 对应的秒杀页面。而这时,前端的导航很难与预分配的库存进行沟通——某一个二级 Redis 服务分配的库存很多,但是前端导航很少,这就造成了商品的浪费。
  • 服务出现问题时,库存数据很难回收:为了尽量让秒杀应用只读取本地的 Redis 数据,二级 Redis 大概率还是会采用单点的方式进行部署。此时,由于每个二级 Redis 中的库存数据并不完整,如果二级 Redis 在活动中途出现崩溃,那么基于这个 Redis 的库存数据就无法回滚,会影响到整体的库存管理。虽然对于秒杀应用,单节点的 Redis 可用性不是首要的,但在纯粹单节点情况下,至少活动数据可以通过日志管理,即使出了问题也可以通过日志快速恢复,后续可以进行返场等活动进行补救;而采用预分配之后,库存的管理是分散的,中途出现问题,库存的管理就会变得很复杂,就无法恢复到整个集群全部正常时的场景。
  • 服务之间无法沟通造成的业务尴尬:比如每个二级 Redis 上都分配全量的 SKU 信息(只有这样才比较好实现),但是只有二级 Redis 1 和二级 Redis 3 上承载了 SKU 1 的秒杀活动,当这两个 Redis 上的库存扣减完成后,就无法再继续扣减了,而实际上二级 Redis 2 上还有很多 SKU 1 的库存,就无法正常售卖。
  • 无法跨服务凑单:如果秒杀活动一次可以抢购多个商品,出现了某一个服务上的库存不够一个订单时,也无法与其他服务进行沟通进行合理的凑单。比如每个二级 Redis 中还剩下 1 个库存,但是某一个订单需要抢购 2 个商品,总的库存是足够的,却无法完成这个订单。

3.3 动态库存分配方案

之前库存预分配方案的核心问题在于:库存只是在活动开始时进行分配,而不能在活动扣减过程中进行灵活调整。所以,要解决这个问题,就需要独立出一个库存预分配的服务,在扣减过程中,灵活调整各个服务的库存:

具体机制如下:

  1. 将库存分配服务独立出来,这样便于与其他秒杀应用进行沟通。
  2. 在秒杀活动开始时,进行库存预分配。这时,不一定将所有库存全部分配完成,可以在一级 Redis 中预留一部分库存。
  3. 每个秒杀应用独立扣减库存,当发现库存低于某一个阈值下限时(不要等到库存扣没了才通知),通知库存分配服务,库存分配服务再访问各级 Redis,对库存进行统一重分配。
  4. 重分配时,优先从一级 Redis 中分配库存,这样的速度是比较快的。一级 Redis 中库存扣减完成后,再协调二级 Redis 进行库存动态分配;并且在分配过程中,可以用一级 Redis 作为统一缓存进行协调。比如,发现二级 Redis 2 上的 SKU 1 的库存就没有扣减过,这时就可以直接将二级 Redis 2 上的 SKU 1 库存全部回收,分配给其他二级 Redis。
  5. 当其他二级 Redis 中的库存超过了某一个阈值上限时(由于其他 Redis 上的库存扣减速度不一致,所以不建议一次全部平均分配完,预留一部分库存作为机动库存,可以加快分配的速度),将多出来的库存放回到一级 Redis 中。
  6. 在秒杀活动快要结束或者是库存快要完全售完时(比如所有二级 Redis 中的库存全都低于某一个临界点),可以将剩余库存全部回收,然后一起分配给某一个二级 Redis,这样就可以在遇到大订单时努力进行最后的拼单。

很多互联网企业都采用了这样一套架构。如果做得比较细致的话,库存分配服务还可以用来监控各个秒杀应用的状态——如果发现某个秒杀应用挂了,也可以及时回收其对应的二级 Redis 库存。而更进一步,如果做到了对每个秒杀服务状态的精准把控,那么甚至可以将二级 Redis 进一步改为秒杀应用的本地RocksDB缓存,这样又可以再次提升秒杀应用的并发性能。

总之,独立出这个库存分配服务后,就可以动态调整各个零散的二级 Redis 库存。这样既保证了每个秒杀应用可以只操作本地的 Redis 缓存,最大限度增加应用的吞吐量,又能保证这些独立的秒杀应用可以整体进行协调,像一个整体进行工作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/12 10:27:23

Android Studio安装配置全攻略:从下载到运行,避坑指南与镜像加速

1. 为什么你的Android Studio安装总是不顺?如果你正准备踏入Android开发的大门,或者刚从一个老版本升级,那么“安装Android Studio”这件事,很可能就是你遇到的第一个、也是最磨人的坎。我见过太多新手,兴冲冲地下载好…

作者头像 李华
网站建设 2026/8/12 10:26:00

WinHex十六进制编辑器:从数据底层视角到文件修复实战指南

1. 从“十六进制编辑器”到“数据手术刀”:WinHex的定位与价值如果你在数据恢复、数字取证、甚至是软件逆向的圈子里待过一阵子,大概率会听到一个名字:WinHex。很多新手第一次接触它,看到满屏的十六进制数字和ASCII字符&#xff0…

作者头像 李华
网站建设 2026/8/12 10:25:47

面向对象编程核心思想:从概念到实战的完整指南

1. 从“造车”到“编程”:为什么我们需要面向对象?如果你问一个刚学编程不久的朋友:“面向对象是什么?” 大概率会得到一串标准答案:封装、继承、多态。然后呢?然后可能就没了。这些概念就像汽车说明书上的…

作者头像 李华
网站建设 2026/8/12 10:24:07

数据库面试核心:从锁、索引到分布式架构的深度解析与实战

1. 从面试官视角看数据库面试:他们要考察什么?又到了一年一度的保研季,对于计算机专业的同学来说,数据库这门课几乎是所有面试的“必考题”。但很多同学复习时容易陷入一个误区:抱着厚厚的教材,从第一章“绪…

作者头像 李华
网站建设 2026/8/12 10:23:35

Hive SQL字符串匹配:LIKE、RLIKE与REGEXP核心区别与实战指南

1. 项目概述:从模糊匹配到精准筛选的进化在数据仓库和数据分析的日常工作中,我们每天都要和海量的字符串数据打交道。无论是用户行为日志里的URL路径、商品评论中的关键词,还是设备上报的状态信息,如何高效、准确地进行文本匹配和…

作者头像 李华