秒杀如何设计呢?

一、Redis 扣减成功但 MQ 发送失败的解决方案

1. 核心原则:确保 “扣减库存” 与 “发送消息” 的原子性

Redis 扣减库存与 MQ 发送消息是两个独立操作,若中间失败(如 MQ 宕机),会导致 “库存已扣但订单未生成” 的不一致问题。解决方案如下:

方案 1:本地消息表 + 重试机制(最终一致性)
  • 步骤

    1. Redis 扣减库存:使用 Lua 脚本原子执行 GET库存 → 校验 → 扣减 流程,确保扣减成功。
    2. 写入本地消息表:在业务库中创建 seckill_message 表,记录消息状态(status=0 表示待发送),字段包括 order_iduser_idgoods_idstockcreate_time 等。
      • 此操作需与 Redis 扣减在同一本地事务中(若 Redis 扣减成功但表写入失败,需回滚 Redis 扣减)。
    3. 发送 MQ 消息:若发送成功,更新消息表 status=1;若失败,status 保持 0
    4. 定时任务重试:后台定时扫描 status=0 且超过一定时间(如 30 秒)的消息,重新发送 MQ,重试次数上限(如 3 次),超过后标记为失败(人工介入)。
  • 优势:通过本地事务保证 “扣减库存” 与 “消息记录” 的原子性,重试机制确保消息最终送达。

方案 2:Redis 事务 + 消息队列确认机制
  • 步骤

    1. Redis 扣减 + 消息暂存:使用 Redis 事务,先扣减库存,再将消息内容(订单信息)存入 Redis 临时队列(如 seckill_pending_messages),确保两者同时成功或失败。
    2. 异步发送 MQ:单独的线程消费 seckill_pending_messages,发送消息到 MQ,若收到 MQ 的确认回调(如 RabbitMQ 的confirm机制),则从临时队列删除消息;否则保留,等待重试。
    3. 重试兜底:定时任务扫描临时队列,对超时未发送成功的消息重新发送。
  • 优势:纯内存操作,性能高,适合超高频场景。

二、整体设计的补充优化建议

1. 前端优化
  • 静态资源 CDN:秒杀页面的静态资源(图片、CSS、JS)部署到 CDN,减少源站压力。
  • 按钮防重复点击:通过前端防抖(如 3 秒内禁止重复点击),减少无效请求。
  • 预加载与倒计时:活动开始前预加载商品信息,倒计时结束后再开放请求,避免提前流量冲击。
2. 网关层优化
  • 令牌桶限流:基于用户 ID/IP 的令牌桶算法限流(如每秒允许 10 次请求),比简单 IP 限流更灵活。
  • 黑名单机制:拦截历史恶意请求的 IP / 用户 ID,直接拒绝服务。
  • 协议压缩:启用 HTTP/2 或 gzip 压缩,减少传输数据量,提升响应速度。
3. 缓存层优化
  • 库存预热与过期时间:秒杀前将商品库存写入 Redis(如 seckill:stock:{goodsId}),设置合理过期时间(略长于活动时间),避免缓存雪崩。
  • 分布式锁防超卖:Redis 扣减库存必须用原子操作(如 DECR + 校验结果,或 Lua 脚本),确保并发安全。

    lua

    -- Lua脚本:检查库存并扣减,确保原子性
    local stock = redis.call('get', KEYS[1])
    if stock and tonumber(stock) > 0 then
        return redis.call('decr', KEYS[1])
    end
    return -1  -- 库存不足
    
4. MQ 层优化
  • 消息幂等性:消费端通过 订单ID 或 用户ID+商品ID+时间戳 作为唯一键,结合 Redis / 数据库的幂等表(如 seckill_order_unique),防止重复下单。
  • 死信队列:MQ 中无法消费的消息(如数据库暂时不可用)进入死信队列,后续人工处理,避免消息丢失。
  • 流量削峰:MQ 设置合理的队列长度和消息过期时间,避免消息堆积导致内存溢出。
5. 数据库层优化
  • 分库分表:订单表按用户 ID 哈希分表,库存表按商品 ID 分表,减少单表压力。
  • 库存冻结机制:Redis 扣减库存后,数据库库存可设为 “总库存 = 可售库存 + 冻结库存”,MQ 消费时将冻结库存转为实际扣减,避免超卖。
  • 读写分离:订单查询走从库,写入走主库,减少主库压力。

三、一致性校验与监控

  1. 库存对账

    • 定时任务(如每 5 分钟)对比 Redis 库存与数据库库存,若有差异,以数据库为准修正 Redis(避免 Redis 因网络 / 重启丢失数据)。
    • 秒杀结束后,生成库存差异报表,人工核对异常订单。
  2. 全链路监控

    • 接入 APM 工具(如 SkyWalking),监控 Redis 扣减成功率、MQ 消息延迟、数据库写入耗时等指标,及时预警瓶颈。
    • 日志埋点:记录每个环节的关键日志(如 Redis 扣减、MQ 发送、订单生成),便于问题追溯。

总结

秒杀系统的核心是 “流量分层过滤” 和 “异步化削峰”:前端过滤无效请求,网关拦截恶意流量,缓存承接高频读写,MQ 削峰填谷,数据库保证最终一致性。针对 “Redis 扣减成功但 MQ 发送失败” 的问题,通过本地消息表 + 重试Redis 临时队列 + 确认机制可实现最终一致性,结合全链路监控和对账机制,确保系统稳定可靠。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值