秒杀兑换商品的完整链路是怎样的?

1 个回答

  • 西蒙
    热爱漫无边际,生活自有分寸。
    ## 作用 秒杀兑换商品的核心链路采用“先拦后放、层层过滤”的思路,在高并发场景下保护系统、控制兑换成本,并防止库存超发和同一用户重复领取。 完整链路通常分为以下几层: 1. **前端层** - 点击抢购后按钮置灰,防止重复提交。 - 对同一设备或账号做本地限流。 - 提前加载活动时间、库存数量、活动规则等配置,减少开始时的请求压力。 2. **CDN/边缘节点层** - 秒杀页面、图片、规则等静态资源提前缓存在 CDN。 - 用户浏览页面、查看倒计时等请求尽量不回源。 - 只有真正的抢购请求才进入后端系统。 3. **Nginx 接入层** - 按 IP 做限流,超过阈值直接返回“服务繁忙”。 - 拦截爬虫、秒杀器等异常 IP。 - 当后端负载过高时,直接拒绝新请求,保护核心服务。 4. **网关/应用层** - 按活动维度限流,例如根据库存量控制每秒进入核心流程的请求数。 - 做用户风控,识别小号、频繁抢购、异常行为等。 - 先查询 Redis 库存,库存为 0 时直接返回已抢空。 5. **MQ 队列层** - 瞬时抢购请求先进入 MQ,起到削峰填谷作用。 - 消费者按照数据库和业务系统能承受的速度处理。 - 队列已满或排队超时,则返回繁忙或失败。 6. **核心业务层(Redis + MySQL)** - 活动开始前把库存预热到 Redis。 - 抢购时通过 Redis 原子扣减库存,防止超发。 - 使用“活动/商品 ID + 用户 ID”作为唯一标识,防止重复领取。 - 扣减成功后异步写入 MySQL,保存兑换记录和最终库存。 - 定时进行 Redis 与 MySQL 的库存对账,发现不一致及时修复。 ## 原理 ### 1. 为什么要层层拦截 秒杀的特点是请求量远大于商品量,例如少量商品面对大量并发请求。如果所有请求都直接访问数据库,会导致数据库压力过大甚至系统不可用。 因此系统会在前端、CDN、Nginx、网关、MQ、核心业务层逐步过滤请求,只让少量有效请求进入最终兑换逻辑。 ### 2. 如何防止超发 - 活动开始前将库存写入 Redis。 - 用户抢购时使用 Redis 的原子扣减操作,例如 `DECR`。 - 原子操作在 Redis 中单线程执行,多个并发请求不会同时把库存扣成负数。 - 当库存扣减到 0 后,后续请求直接失败。 - Redis 扣减成功后,再由消费者写入 MySQL,最终通过对账保证数据一致。 ### 3. 如何防止重复兑换 - 使用“活动 ID/商品 ID + 用户 ID”构造唯一 key。 - 用户抢购成功后,在 Redis 中标记该用户已经领取。 - 同一用户再次请求时,直接返回“已领取”或“已抢过”。 - MQ 消费阶段也可再次校验唯一标识,避免消息重复投递造成重复发券。 - MySQL 中可对用户和活动建立唯一约束,作为数据库层面的兜底。 ### 4. MQ 的作用 MQ 主要用于削峰填谷: - 高峰请求先写入队列。 - 后端按稳定速度消费。 - 避免数据库在秒杀瞬间被打垮。 - 队列满或超时的请求快速失败,从而平衡用户体验和系统稳定性。 ### 5. 用户看到“服务繁忙”的原因 “服务繁忙”不一定代表系统崩溃,也可能是主动限流: - 请求超过 IP、账号或活动维度的限流阈值。 - 当前队列已满或排队超时。 - 命中风控规则。 - Redis 库存已为空。 - 后端负载过高,接入层主动拒绝请求。 整体上,秒杀兑换链路就是通过静态化缓存、多层限流、风控校验、Redis 原子扣库存、MQ 异步削峰、MySQL 落库和对账,来实现高并发下的可用、可控和数据正确。
    发布于 2026-10-28 03:39 •IP属地 西藏
    举报
    评论
    收藏