【Java 开发日记】设计一个支持万人同时抢购商品的秒杀系统?

【Java 开发日记】设计一个支持万人同时抢购商品的秒杀系统?

目录

一、系统架构设计

1. 分层架构

2. 具体组件

二、核心问题解决方案

1. 超卖问题

解决方案一:Redis原子操作

解决方案二:数据库乐观锁

解决方案三:预扣库存

2. 高并发请求处理

2.1 流量削峰

2.2 分层过滤

3. 系统性能优化

3.1 缓存策略

3.2 读多写少优化

4. 详细实现方案

4.1 秒杀流程

4.2 库存同步方案

三、高可用保障

1. 限流降级策略

2. 熔断降级

四、监控与告警

1. 关键监控指标

2. 监控实现

五、部署与扩展

1. 弹性扩展策略

2. 压测方案

六、安全考虑

总结要点

面试回答


一、系统架构设计

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

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

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

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

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

Read more

4步创作革命!WAN2.2极速视频AI重新定义AIGC视频生产流程

4步创作革命!WAN2.2极速视频AI重新定义AIGC视频生产流程 【免费下载链接】WAN2.2-14B-Rapid-AllInOne 项目地址: https://ai.gitcode.com/hf_mirrors/Phr00t/WAN2.2-14B-Rapid-AllInOne 价值定位:打破专业壁垒的视频创作新范式 在AIGC视频生成领域,创作者长期面临"三高困境":技术门槛高、硬件要求高、时间成本高。传统工作流往往需要串联文本理解、图像生成、视频插值等多个模型,仅模型加载就需消耗数分钟,且80%以上的失败案例源于模型组合不当。WAN2.2-14B-Rapid-AllInOne(简称WAN2.2极速视频AI)以"一体化模型架构"直击行业痛点,将原本需要10+步骤的创作流程压缩至4个核心环节,在8GB显存设备上实现每分钟视频内容的高效生成。 这款由Phr00t团队开发的开源模型,通过"MEGA Merge"

By Ne0inhk

Dify v1.12.0深度适配DeepSeek-V3:支持LoRA微调注入、流式响应对齐、上下文长度动态扩展,附GitHub私有仓库验证清单

第一章:Dify v1.12.0与DeepSeek-V3集成概述 Dify v1.12.0 是一个面向 AI 应用开发的低代码平台,支持快速构建、调试和部署基于大语言模型的应用。该版本显著增强了对第三方大模型的兼容性,尤其在与国产高性能模型 DeepSeek-V3 的集成上实现了深度优化。通过标准化接口对接与上下文管理机制升级,开发者可无缝将 DeepSeek-V3 接入 Dify 的应用工作流中,实现高效推理与对话能力。 核心特性 * 支持通过 API Key 直接连接 DeepSeek-V3 模型服务 * 内置 Prompt 编排引擎,适配 DeepSeek-V3 的输入格式要求 * 提供实时日志追踪与 token 消耗统计功能 * 兼容 streaming 输出模式,提升用户交互体验 配置步骤 1. 登录 Dify 管理后台,

By Ne0inhk
【AI大模型前沿】通义万相Wan2.2:阿里270亿参数巨兽开源,消费级显卡就能跑,免费平替Sora上线

【AI大模型前沿】通义万相Wan2.2:阿里270亿参数巨兽开源,消费级显卡就能跑,免费平替Sora上线

系列篇章💥 No.文章1【AI大模型前沿】深度剖析瑞智病理大模型 RuiPath:如何革新癌症病理诊断技术2【AI大模型前沿】清华大学 CLAMP-3:多模态技术引领音乐检索新潮流3【AI大模型前沿】浙大携手阿里推出HealthGPT:医学视觉语言大模型助力智能医疗新突破4【AI大模型前沿】阿里 QwQ-32B:320 亿参数推理大模型,性能比肩 DeepSeek-R1,免费开源5【AI大模型前沿】TRELLIS:微软、清华、中科大联合推出的高质量3D生成模型6【AI大模型前沿】Migician:清华、北大、华科联手打造的多图像定位大模型,一键解决安防监控与自动驾驶难题7【AI大模型前沿】DeepSeek-V3-0324:AI 模型的全面升级与技术突破8【AI大模型前沿】BioMedGPT-R1:清华联合水木分子打造的多模态生物医药大模型,开启智能研发新纪元9【AI大模型前沿】DiffRhythm:西北工业大学打造的10秒铸就完整歌曲的AI歌曲生成模型10【AI大模型前沿】R1-Omni:阿里开源全模态情感识别与强化学习的创新结合11【AI大模型前沿】Qwen2.5-Omni:

By Ne0inhk

CompreFace:企业级开源人脸识别系统的技术突破与实践应用

CompreFace:企业级开源人脸识别系统的技术突破与实践应用 【免费下载链接】CompreFaceLeading free and open-source face recognition system 项目地址: https://gitcode.com/gh_mirrors/co/CompreFace 在当前数字化转型浪潮中,企业级人脸识别技术正面临着部署成本高昂、技术门槛过高、数据隐私安全等多重挑战。传统的商业人脸识别解决方案往往需要巨额投入,同时缺乏透明度和定制灵活性。CompreFace作为领先的免费开源人脸识别系统,通过其完整的技术架构和丰富的功能模块,为企业用户提供了全新的解决方案。 技术痛点与行业挑战 企业部署人脸识别系统时普遍遭遇以下困境: * 高昂的许可费用 - 商业解决方案动辄数万元的年度授权费用 * 技术依赖风险 - 闭源系统的算法黑盒化导致技术不可控 * 数据安全隐患 - 云端服务存在数据泄露风险 * 定制化困难 - 标准产品难以满足特定业务需求 CompreFace的技术架构优势 CompreFace采用微服务架构设计,将人脸识别

By Ne0inhk