跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

设计支持万人并发抢购的秒杀系统架构方案

设计支持万人并发抢购的秒杀系统架构方案。核心架构采用分层过滤与异步削峰,通过 Nginx 限流、Redis 原子操作及消息队列缓冲请求。针对超卖问题,提供 Redis 预扣库存、数据库乐观锁及 Lua 脚本方案。性能优化涉及多级缓存预热与读写分离。高可用保障包含限流降级、熔断机制及弹性扩展策略。此外还涵盖安全防刷、监控告警及数据一致性对账措施,确保系统在高压下稳定运行。

监控大屏发布于 2026/2/9更新于 2026/7/217.5K 浏览
设计支持万人并发抢购的秒杀系统架构方案

一、系统架构设计

1. 分层架构
客户端层 → 接入层 → 业务服务层 → 数据层
↓ ↓ ↓ ↓
限流 缓存 队列 数据库
2. 具体组件
  • 客户端:静态资源 CDN、倒计时校准、防重复提交
  • 接入层:Nginx+Lua/OpenResty,做第一层限流和缓存
  • 业务层:
    • 秒杀服务集群(无状态)
    • 消息队列(Kafka/RocketMQ)
    • 缓存集群(Redis Cluster)
  • 数据层:
    • 主从数据库(读写分离)
    • 分库分表(按商品/时间)

二、核心问题解决方案

1. 超卖问题
解决方案一:Redis 原子操作
# 使用 Redis 的 DECR 原子操作扣减库存
def deduct_stock(product_id, user_id):
    stock_key = f"stock:{product_id}"
    # Lua 脚本保证原子性
    lua_script = """
    local stock = tonumber(redis.call('GET', KEYS[1]))
    if stock and stock > 0 then
        redis.call('DECR', KEYS[1])
        return 1
    end
    return 0
    """
    result = redis.eval(lua_script, 1, stock_key)
    return result == 1
解决方案二:数据库乐观锁
UPDATE products SET stock = stock - 1, version = version + 1 WHERE id = ? AND stock > 0 AND version = ?
解决方案三:预扣库存
// 先预扣 Redis 库存,再异步同步到 DB
public boolean preDeductStock(String productId, int count) {
    String key = "seckill:stock:" + productId;
    Long remaining = redisTemplate.opsForValue().decrement(key, count);
    if (remaining >= 0) {
        // 发送 MQ 消息异步扣减数据库
        sendStockDeductMessage(productId, count);
        return true;
    } else {
        // 库存不足,回滚
        redisTemplate.opsForValue().increment(key, count);
        return false;
    }
}
2. 高并发请求处理
2.1 流量削峰
// 使用消息队列缓冲请求
@Component
public class SeckillService {
    @Autowired
    private RocketMQTemplate mqTemplate;

    public SeckillResult seckill(SeckillRequest request) {
        // 1. 校验用户和商品状态
        if (!validate(request)) {
            return SeckillResult.fail("校验失败");
        }
        // 2. 生成唯一请求 ID
        String requestId = generateRequestId(request);
        // 3. 请求入队,立即返回
        mqTemplate.sendOneWay("seckill-topic", MessageBuilder.withPayload(request).build());
        // 4. 返回排队中状态,前端轮询结果
        return SeckillResult.processing(requestId);
    }
}
2.2 分层过滤

所有请求 → 合法性校验 → 库存校验 → 频率控制 → 实际下单 ↓ ↓ ↓ ↓ ↓ 100 万 50 万 10 万 5 万 1 万

3. 系统性能优化
3.1 缓存策略
# 多级缓存配置
缓存层级:
一级:JVM 本地缓存 (Caffeine) - 热点商品
二级:Redis 集群 - 库存信息
三级:数据库 - 最终一致性
3.2 读多写少优化
// 商品信息缓存预热
@Service
public class CacheWarmUpService {
    @PostConstruct
    public void warmUpSeckillProducts() {
        List<Product> hotProducts = loadHotProducts();
        for (Product product : hotProducts) {
            // 库存信息
            redisTemplate.opsForValue().set(
                "stock:" + product.getId(), product.getStock()
            );
            // 商品详情
            redisTemplate.opsForValue().set(
                "product:" + product.getId(), JSON.toJSONString(product)
            );
            // 使用布隆过滤器存储可售商品 ID
            bloomFilter.add(product.getId());
        }
    }
}
4. 详细实现方案
4.1 秒杀流程
class SeckillSystem:
    def process_seckill(self, user_id, product_id):
        # 1. 恶意请求拦截
        if not self.check_risk(user_id):
            return {"code": 403, "msg": "访问过于频繁"}
        # 2. 布隆过滤器快速判断
        if not bloom_filter.contains(product_id):
            return {"code": 404, "msg": "商品不存在"}
        # 3. 内存标记(已售罄的商品直接返回)
        if sold_out_flags.get(product_id):
            return {"code": 400, "msg": "已售罄"}
        # 4. Redis 原子扣减库存
        if not self.deduct_stock_in_redis(product_id):
            sold_out_flags[product_id] = True
            return {"code": 400, "msg": "库存不足"}
        # 5. 生成订单 ID(雪花算法)
        order_id = snowflake.generate()
        # 6. 订单信息入队
        mq.send({
            "order_id": order_id,
            "user_id": user_id,
            "product_id": product_id,
            "time": time.time()
        })
        # 7. 返回排队中
        return {
            "code": 200,
            "msg": "排队中",
            "order_id": order_id,
            "queue_position": get_queue_position(order_id)
        }
4.2 库存同步方案
@Component
@Slf4j
public class StockSyncService {
    // 数据库最终扣减
    @Transactional
    public void syncStockToDB(String productId, int count) {
        try {
            // 数据库扣减(带重试机制)
            boolean success = productDAO.deductStock(productId, count);
            if (success) {
                // 更新 Redis 中的最终库存状态
                redisTemplate.opsForValue().set(
                    "stock_final:" + productId, getDBStock(productId)
                );
                // 删除售罄标记
                soldOutCache.remove(productId);
            }
        } catch (Exception e) {
            log.error("库存同步失败", e);
            // 记录异常,人工介入处理
            alertService.sendAlert(e);
        }
    }

    // 库存对账任务
    @Scheduled(cron = "0 */5 * * * ?")
    public void stockReconciliation() {
        List<Product> products = productDAO.getAllSeckillProducts();
        for (Product product : products) {
            Integer redisStock = getRedisStock(product.getId());
            Integer dbStock = product.getStock();
            if (!Objects.equals(redisStock, dbStock)) {
                log.warn("库存不一致:productId={}, redis={}, db={}", product.getId(), redisStock, dbStock);
                // 自动修复或报警
                fixStockInconsistency(product.getId(), dbStock);
            }
        }
    }
}

三、高可用保障

1. 限流降级策略
# 多维度限流配置
限流规则:
用户维度:每个用户 10 次/分钟
IP 维度:每个 IP 1000 次/分钟
商品维度:每个商品 10000 次/分钟
总 QPS: 系统最大承受 50000 QPS
2. 熔断降级
@RestController
@Slf4j
public class SeckillController {
    @GetMapping("/seckill/{productId}")
    @HystrixCommand(
        fallbackMethod = "seckillFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20")
        }
    )
    public Response seckill(@PathVariable String productId, @RequestParam String userId) {
        return seckillService.process(userId, productId);
    }

    // 降级方法
    public Response seckillFallback(String productId, String userId) {
        return Response.error("系统繁忙,请稍后重试");
    }
}

四、监控与告警

1. 关键监控指标
  • 系统层面:QPS、RT、错误率、CPU/内存使用率
  • 应用层面:库存扣减成功率、消息堆积量
  • 业务层面:抢购成功率、用户排队时长
2. 监控实现
@Component
public class SeckillMonitor {
    private final MeterRegistry meterRegistry;

    // 记录关键指标
    public void recordSeckill(String productId, boolean success, long cost) {
        // QPS 监控
        meterRegistry.counter("seckill.requests.total").increment();
        if (success) {
            meterRegistry.counter("seckill.success.total").increment();
        } else {
            meterRegistry.counter("seckill.fail.total").increment();
        }
        // 耗时分布
        meterRegistry.timer("seckill.process.time")
            .record(cost, TimeUnit.MILLISECONDS);
        // 库存变化
        meterRegistry.gauge("seckill.stock." + productId, getCurrentStock(productId));
    }
}

五、部署与扩展

1. 弹性扩展策略
  • 水平扩展:无状态服务可快速扩容
  • 自动伸缩:基于 CPU 使用率或 QPS 自动扩缩容
  • 异地多活:重要业务支持多机房部署
2. 压测方案
压测场景:
场景 1: 库存预热,10 万用户同时抢 1 万商品
场景 2: 持续高压,5 万 QPS 持续 5 分钟
场景 3: 峰值冲击,瞬间 20 万 QPS
压测目标:
成功率:>99.9%
平均 RT: <100ms
错误率:<0.1%

六、安全考虑

  • 防刷机制:
    1. 验证码(峰值时降级)
    2. 设备指纹
    3. 行为分析
  • 数据安全:
    1. 关键数据加密
    2. 操作日志记录
    3. 防篡改校验

总结要点

  1. 架构核心:分层过滤 + 异步处理 + 最终一致
  2. 库存核心:Redis 原子操作 + 消息队列 + 数据库乐观锁
  3. 性能核心:缓存预热 + 流量削峰 + 读写分离
  4. 稳定核心:熔断降级 + 限流隔离 + 快速失败

面试回答

首先,架构设计上要动静分离、分层削峰。我会把系统分为:

  1. 静态资源分离:商品图片、描述页等提前推送到 CDN,请求直接走边缘节点,不给后端压力。
  2. 网关层限流:在入口用 Nginx 或网关(如 Sentinel)做恶意请求拦截和总流量限制,比如对同一 UID 限速,超过阈值直接返回'请求频繁'。
  3. 业务逻辑后置,请求队列化:秒杀的核心——'下单扣库存'这个最重要的逻辑,绝不放在前台实时处理。用户点击'抢购'后,前端直接返回'排队中',请求进入一个消息队列(比如 RabbitMQ、Kafka 或 RocketMQ)。这样一来,海量并发就被平滑成顺序处理的流量,后端服务按照自己的能力从队列里慢慢消费,实现削峰填谷。
  4. 服务独立部署:把秒杀相关的功能(验资格、扣库存)单独做成一个微服务,避免影响商城其他正常功能(如浏览、普通下单)。

其次,针对如何解决超卖、库存扣减和高并发请求这三个核心问题,我的解决方案是:

  • 解决超卖和库存扣减:这是秒杀的核心。我的方案是:
    • 预扣库存:活动开始前,把商品的库存从主库加载到Redis中。Redis 是单线程内存操作,可以保证原子性。
    • 原子化操作:在 Redis 里,使用 DECR 或 LUA 脚本来扣减库存。DECR 命令会直接返回扣减后的值,如果返回值小于 0,就说明库存没了,后续流程直接返回售罄。LUA 脚本可以打包多个操作(检查库存、扣减),确保整个过程原子性,彻底杜绝超卖。
    • 最终同步:后台服务从队列消费,成功扣减 Redis 库存后,生成一个订单 ID(但状态是'未支付'),再异步去更新数据库的库存。这里数据库的库存更多是用于后续对账和长尾查询。
  • 应对高并发请求:
    • 限流:除了网关层的总限流,在秒杀服务本身也要做限流,比如用信号量或令牌桶控制处理线程数,只服务自己能承受的流量,多的直接拒绝,快速失败。
    • 无状态化与扩容:秒杀服务做成无状态的,方便用 K8s 或云服务快速横向扩容,扛过峰值后再缩容,控制成本。
    • 热点数据隔离:对于'爆款'商品,它的库存 Key 在 Redis 里是热点 Key。可以做两件事:一是提前对它进行Key 散列,把压力分散到多个 Redis 节点;二是使用 Redis 集群模式,并开启读写分离。

最后,还有一些关键的细节和兜底策略:

  • 防刷与验证:前端加入计算型验证码或答题,防止机器人;下单前必须校验用户资格(是否登录、地址完善等)。
  • 异步下单与结果轮询:用户提交后,服务端返回一个'排队 ID',前端用这个 ID 轮询后端,查询最终结果(成功、失败或等待)。用户体验上是'排队等待',而不是一直卡住或报错。
  • 数据一致性对账:因为用了 Redis 和消息队列,可能出现极端情况下的数据不一致(比如 Redis 扣成功,但下游服务挂了,订单没生成)。需要有一个定时对账任务,核对 Redis、数据库库存和订单状态,进行修复。
  • 降级与熔断:如果 Redis 或数据库访问慢,要有熔断机制,防止服务被拖垮。比如可以快速降级到'返回售罄'的静态页面。

总结一下,我的设计思路是:前端限流拦截,请求队列削峰;Redis 原子扣减防超卖;服务无状态化应对高并发;再通过异步、对账等手段保证最终一致性和用户体验。

目录

  1. 一、系统架构设计
  2. 1. 分层架构
  3. 2. 具体组件
  4. 二、核心问题解决方案
  5. 1. 超卖问题
  6. 解决方案一:Redis 原子操作
  7. 使用 Redis 的 DECR 原子操作扣减库存
  8. 解决方案二:数据库乐观锁
  9. 解决方案三:预扣库存
  10. 2. 高并发请求处理
  11. 2.1 流量削峰
  12. 2.2 分层过滤
  13. 3. 系统性能优化
  14. 3.1 缓存策略
  15. 多级缓存配置
  16. 3.2 读多写少优化
  17. 4. 详细实现方案
  18. 4.1 秒杀流程
  19. 4.2 库存同步方案
  20. 三、高可用保障
  21. 1. 限流降级策略
  22. 多维度限流配置
  23. 2. 熔断降级
  24. 四、监控与告警
  25. 1. 关键监控指标
  26. 2. 监控实现
  27. 五、部署与扩展
  28. 1. 弹性扩展策略
  29. 2. 压测方案
  30. 六、安全考虑
  31. 总结要点
  32. 面试回答
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 产品经理如何利用 AI Agent 提升工作效率
  • 基于 SpringBoot+Vue 的新能源充电系统架构设计与实现
  • 谷歌 TurboQuant 内存压缩与 RWKV-6 架构优化大模型部署
  • C++上位机利用Snap7实现西门子S7-200与合信M226ES数据交互
  • Python 数据分析与可视化:金融量化基础与双均线策略
  • 智能降重与 AIGC 检测功能解析:适配主流平台的合规解决方案
  • SpringDoc OpenAPI 常用注解详解与实战示例
  • AIGC 产品经理面试高频问题与核心解答
  • synchronized 与 ReentrantLock 的核心区别与选型指南
  • RAG 技术演进:从基础架构到模块化创新
  • LLM 大模型应用落地与优化:评测体系构建指南
  • 学生如何申请及使用 GitHub Copilot 编程助手
  • GitHub Copilot 配置避坑指南与安全策略
  • 当 AI 写作遇上“学术贫富差距”,我们是桥梁还是高墙?
  • AnimeGANv2 WebUI 集成 OAuth 登录与权限控制方案
  • GitHub Copilot 登录失败的常见原因与排查指南
  • HomeAssistant 海尔智能家居集成插件使用指南
  • JavaScript DOM 元素操作:添加、删除、替换与插入详解
  • NPlayer 流媒体接入实战:HLS、FLV 与 WebRTC 详解
  • Copilot的Plan模式到底好在哪?

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online