下面给你一份:
企业级 秒杀系统(Redis + Java)
核心目标:
高并发
防超卖
防重复下单
高性能
这是:
企业中经典面试 + 实战项目
一、秒杀核心问题
秒杀最怕:
1、超卖
库存:
100
结果卖:
1000
2、重复下单
一个人疯狂抢。
3、数据库崩溃
10万人同时:
update stock = stock -1
数据库直接炸。
二、企业真实方案
真正企业:
Redis + Lua脚本
保证:
原子性
三、秒杀流程(企业核心)
用户请求
↓
Redis判断库存
↓
Redis判断是否重复下单
↓
扣减库存
↓
记录用户
↓
发送MQ异步创建订单
四、为什么 Redis 适合秒杀
因为:
Redis:
单线程 + 内存
极快。
五、项目结构
controller
service
redis
mq
order
六、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.27.2</version>
</dependency>
七、Redis配置
spring:
data:
redis:
host: localhost
port: 6379
八、秒杀 Controller
@RestController
@RequestMapping("/seckill")
@RequiredArgsConstructor
public class SeckillController {
private final SeckillService seckillService;
@PostMapping("/{voucherId}")
public String seckill(
@PathVariable Long voucherId
) {
Long userId = 1L;
return seckillService.seckill(voucherId, userId);
}
}
九、秒杀核心 Service(重点)
这是:
企业核心代码
@Service
@RequiredArgsConstructor
public class SeckillService {
private final StringRedisTemplate redisTemplate;
/**
* 秒杀
*/
public String seckill(
Long voucherId,
Long userId
) {
// 库存key
String stockKey =
"seckill:stock:" + voucherId;
// 用户key
String orderKey =
"seckill:order:" + voucherId;
// Lua脚本
String script = """
-- 1.判断库存
local stock =
tonumber(redis.call('get', KEYS[1]))
if stock <= 0 then
return 1
end
-- 2.判断是否重复下单
if redis.call(
'sismember',
KEYS[2],
ARGV[1]
) == 1 then
return 2
end
-- 3.扣减库存
redis.call(
'decr',
KEYS[1]
)
-- 4.保存用户
redis.call(
'sadd',
KEYS[2],
ARGV[1]
)
return 0
""";
// 执行 Lua
Long result = redisTemplate.execute(
new DefaultRedisScript<>(
script,
Long.class
),
List.of(stockKey, orderKey),
userId.toString()
);
// 结果判断
if (result == 1) {
return "库存不足";
}
if (result == 2) {
return "不能重复下单";
}
// =========================
// 企业里这里会:
// 发MQ创建订单
// =========================
return "秒杀成功";
}
}
十、为什么企业用 Lua
因为:
Redis Lua脚本:
是原子执行。
十一、如果不用 Lua
例如:
if(stock > 0){
stock--;
}
高并发下:
一定超卖
十二、Lua 原子性(核心)
Lua脚本:
执行期间
不会被其他线程打断
所以:
判断库存
判断重复
扣库存
保存用户
全部原子完成
十三、Redis 数据结构设计(企业重点)
库存
seckill:stock:1
value:
100
已下单用户
seckill:order:1
使用:
Set
存:
1
2
3
十四、为什么用 Set
因为:
天然去重
非常适合:
一人一单
十五、企业真实架构(重点)
真正企业:
不会:
直接写数据库
而是:
Redis负责抗高并发
MQ异步下单
例如:
Redis秒杀成功
↓
发送MQ
↓
订单系统消费
↓
写数据库
十六、为什么必须 MQ
因为:
数据库:
扛不住秒杀流量
十七、企业真实秒杀架构
Nginx
↓
Gateway
↓
Redis Lua秒杀
↓
Kafka/RabbitMQ
↓
订单服务
↓
MySQL
十八、企业优化(非常重要)
真正企业:
还会:
1、本地缓存
2、Redis集群
3、限流
例如:
令牌桶
4、黑名单
5、防刷
6、验证码
十九、为什么秒杀是经典项目
因为:
它包含:
Redis
Lua
MQ
高并发
分布式
缓存
限流
几乎:
后端核心技术全覆盖
二十、真正企业面试重点
面试官真正问:
为什么用 Lua
为什么不会超卖
Redis 为什么单线程还能快
为什么要 MQ
如何保证订单一致性
如何防止重复下单
如何抗10万QPS
这些才是: