百万QPS游戏限时秒杀系统架构设计

一、架构设计核心思想

秒杀系统的核心矛盾是瞬时高并发请求系统有限处理能力的不匹配,因此设计围绕三大核心思路展开:

  1. 拦截:在请求到达核心业务逻辑前,通过多层过滤筛选掉无效、恶意或超量请求,减少下游压力;
  2. 缓冲:通过缓存、队列等组件 “削峰填谷”,将瞬时峰值请求转化为平稳的后台处理流量;
  3. 异步:拆分核心链路与非核心链路,核心链路(如扣库存)同步快速响应,非核心链路(如创建订单、通知)异步延迟处理,提升前端响应速度。

二、整体架构图

plaintext

用户层 → CDN → 网关层 → 业务层 → 缓存层 → 消息队列 → 数据层
                  ↓          ↓          ↓          ↓
                限流        防作弊      库存预加载    异步处理
                  ↓          ↓          ↓          ↓
               降级策略    频率控制    原子扣库存    最终一致性

详细架构拆解(从请求入口到数据落地)

如下图:

三、各层级设计细节

1. 网关层:请求入口的 “第一重拦截”

核心目标:负载均衡 + 限流 + 初步过滤,避免无效请求进入业务层。

  • Nginx 反向代理
    • 部署多台 Nginx 组成集群(配合 Keepalived 实现高可用),将百万 QPS 请求均匀分发到后端业务服务器;
    • 配置proxy_connect_timeout等参数缩短无效连接超时时间,减少资源占用;
    • 静态资源(如活动页面、按钮图标)直接通过 Nginx 返回,无需穿透到业务层。
  • 网关限流(Sentinel/Nginx 限流模块)
    • 基于 “令牌桶算法” 或 “漏桶算法”,设置网关总 QPS 阈值(如 120 万,预留 20% 缓冲),超过阈值的请求直接返回503 Service Unavailable
    • 按 “用户 IP + 游戏 ID” 维度设置细粒度限流(如单 IP 每秒最多 10 次请求),防止单机恶意刷量。

2. 业务层:核心逻辑的 “第二重过滤”

核心目标:防作弊 + 业务校验 + 降级控制,确保只有合法请求进入缓存层。

  • 防作弊策略
    • 频率限制:通过 Sentinel 对 “用户 ID” 设置限流(如单用户活动期间最多 3 次抢购请求),避免单用户反复提交;
    • 合法性校验:校验用户是否已登录、是否满足游戏内参与条件(如等级≥10 级)、请求参数是否篡改(如签名验证),非法请求直接拦截。
  • 降级机制
    • 触发条件:当网关限流触发率≥80%、Redis 响应延迟≥500ms 或业务服务器 CPU 利用率≥90% 时,自动触发降级;
    • 降级方案:
      • 排队模式:返回 “当前拥挤,请排队等待”,通过前端轮询 + Redis 队列记录用户排队顺序,待系统压力下降后依次处理;
      • 抽签模式:用户提交请求后仅记录 “参与资格”,活动结束后通过随机算法抽取中奖用户,再异步处理订单,彻底规避瞬时峰值。

3. 缓存层:库存操作的 “核心战场”

核心目标:原子扣库存 + 快速响应,避免百万请求直接打穿数据库(数据库单库 QPS 通常仅 1 万 - 5 万,无法承载峰值)。

  • 库存预加载
    • 活动开始前 1 小时,通过定时任务将秒杀商品库存(如 10 万份游戏道具)从数据库同步到 Redis,存储结构为key=seckill:game:1001(游戏ID):goods:2001(商品ID), value=100000
    • 为防止 Redis 单点故障,采用 “主从 + 哨兵” 架构(1 主 3 从),主库负责写操作(扣库存),从库负责读操作(查询库存),主库故障时哨兵自动切换从库为主库。
  • 原子扣库存
    • 采用 Redis 的Lua脚本实现原子操作(避免 “超卖” 问题),脚本逻辑如下:

      lua

      -- 1. 检查库存是否充足
      local stock = redis.call('GET', KEYS[1])
      if tonumber(stock) <= 0 then
          return 0 -- 库存不足,返回失败
      end
      -- 2. 扣减库存(DECR原子操作)
      redis.call('DECR', KEYS[1])
      -- 3. 记录用户抢购记录(防止重复抢购)
      redis.call('SADD', KEYS[2], ARGV[1]) -- KEYS[2]为用户集合key,ARGV[1]为用户ID
      return 1 -- 扣库存成功
      
    • 关键:通过SADD记录用户抢购记录,后续请求可通过SISMEMBER快速判断用户是否已抢购,避免重复扣库存。

4. 异步层:非核心逻辑的 “削峰填谷”

核心目标:拆分核心链路与非核心链路,让前端快速响应,后台平稳处理。

  • 消息队列(MQ)选型
    • 选用 RabbitMQ 或 RocketMQ(支持高吞吐 + 事务消息),确保消息不丢失、不重复消费;
    • 配置 “死信队列”,处理失败的消息(如创建订单失败)可重试 3 次,仍失败则进入死信队列人工排查。
  • 异步处理流程
    1. 当 Redis 扣库存成功后,业务层立即向 MQ 发送 “抢购成功” 消息(携带用户 ID、商品 ID、抢购时间);
    2. MQ 消费者集群异步处理 3 类任务:
      • 订单创建:根据消息生成订单数据,存储到订单库;
      • 库存同步:将数据库中对应商品的库存同步扣减(与 Redis 库存最终保持一致);
      • 通知发送:调用短信 / 推送接口,告知用户抢购结果。
    3. 最终一致性保障:通过 “Redis 库存 + 数据库库存” 双校验,活动结束后执行库存对账任务,若存在差异则以 Redis 为准修正数据库。

5. 数据层:最终数据的 “持久化保障”

核心目标:高可用 + 读写分离,支撑异步层的平稳写入。

  • 数据库架构
    • 采用 “主从分离” 架构,主库负责异步写入(创建订单、扣库存),从库负责查询(如用户查询订单);
    • 按 “商品 ID” 分库分表(如 10 个分库,商品 ID%10 路由到对应分库),避免单库写入压力过大;
    • 配置数据库连接池(如 HikariCP),设置合理的连接数(如单库最大 500 连接),避免连接耗尽。
  • 数据一致性
    • 活动结束后,执行 “Redis 库存 vs 数据库库存” 对账任务,若 Redis 库存<数据库库存(可能因 MQ 消息延迟),则修正数据库库存为 Redis 值;
    • 订单数据通过 “定时任务 + 日志回放” 确保不丢失,若 MQ 消费者故障,可通过日志重新消费消息。

四、关键问题解决方案

核心问题解决方案
超卖问题1. Redis 扣库存使用 Lua 脚本保证原子性;2. 数据库库存作为最终校验,活动结束后对账修正
重复抢购1. Redis 用SADD记录用户抢购记录,重复请求直接拦截;2. 订单表设置 “用户 ID + 商品 ID” 唯一索引
系统高可用1. Nginx+Keepalived 高可用;2. Redis 主从 + 哨兵;3. 业务层 / 数据库层集群部署;4. 关键组件故障自动切换
瞬时峰值压力1. 网关 + 业务层多层限流;2. Redis 承载所有库存操作;3. MQ 异步削峰,将瞬时请求转化为平稳流量

五、架构优势总结

  1. 高吞吐:通过 Nginx 负载均衡、Redis 高并发扣库存,支撑百万 QPS 峰值;
  2. 高可用:关键组件(Nginx、Redis、数据库)均为集群架构,无单点故障;
  3. 防超卖 / 防作弊:Lua 原子操作 + 用户频率限制 + 数据一致性校验,避免业务风险;
  4. 用户体验:核心链路(扣库存 + 返回结果)耗时<100ms,异步处理非核心逻辑,前端快速响应。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值