【如何保证订单支付与库存扣减的一致性】五年经验Java开发者业务场景面试题集【如何避免热点Key失效】【微服务接口幂等性】

本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)

在这里插入图片描述

学习教程(传送门)

1、掌握 JAVA入门到进阶知识(持续写作中……
2、学会Oracle数据库用法(创作中……
3、手把手教你vbs脚本制作(完善中……
4、牛逼哄哄的 IDEA编程利器(编写中……
5、吐血整理的 面试技巧(更新中……

一、秒杀系统设计:如何支撑10万QPS的双11抢购?

题目描述

假设你是某电商平台的Java架构师,需要在双11期间设计一个秒杀系统,支撑10万+ QPS,同时满足:
不超卖(库存1000件,最多卖出1000单)

高可用(系统不能崩溃)

低延迟(用户点击后1秒内响应结果)

请描述完整设计方案。

考察点

分布式系统设计、高并发流量削峰、缓存与数据库一致性、防刷限流、事务控制。

参考答案
流量分层拦截(核心防刷)

前端限流:按钮置灰(未开始)、倒计时(防止重复提交)、验证码(滑动验证/短信验证,降低机器请求)。

网关层拦截:使用Nginx做IP限流(如limit_req_zone限制单IP每秒10次),过滤异常UA(如无Referer、爬虫特征)。

服务层校验:用户登录态校验(JWT令牌)、黑名单过滤(历史恶意用户)、参数校验(商品ID是否合法)。
缓存预热与库存扣减

库存预加载:活动开始前,将数据库库存同步到Redis(set stock:1001 1000),避免直接操作数据库。

Redis原子扣减:用户下单时,通过Lua脚本原子扣减库存(避免并发问题):

if redis.call('get', KEYS[1]) > 0 then
  redis.call('decr', KEYS[1])
  return 1  -- 扣减成功

else
return 0 – 库存不足
end

防超卖兜底:即使Redis扣减成功,数据库层面仍需用「乐观锁」二次校验(版本号或库存字段):

UPDATE goods SET stock = stock - 1, version = version + 1 

WHERE id = #{goodsId} AND version = #{oldVersion} AND stock > 0

异步下单与消息队列削峰

请求异步化:秒杀请求先进入RocketMQ/Kafka队列(削峰填谷),后端消费者按稳定速率(如2000单/秒)处理。

订单生成:消费者从队列拉取请求,校验用户、库存(再次查Redis),通过后生成订单(写入MySQL),并发送短信通知。
高可用保障

集群部署:网关、服务、Redis均集群化(如Redis Cluster),避免单点故障。

熔断降级:Sentinel监控核心服务(如下单接口),若错误率超50%则熔断,返回「稍后再试」。

数据库保护:主库写压力大时,启用从库读(库存查询走从库),但扣减必须主库(避免主从延迟导致超卖)。
关键优化点

库存分段:将1000件库存拆成10个段(每段100件),用户抢购时随机分配段ID,减少热点Key竞争(Redis的stock:1001:0~stock:1001:9)。

本地缓存:网关层用Caffeine缓存少量库存(如每个商品缓存10个),过滤无效请求(用户拿到缓存库存为0时直接拒绝)。

二、分布式事务:如何保证订单支付与库存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值