面试官:我们开始吧。你是谢飞机?
谢飞机:是的是的,我就是那个一飞冲天的谢飞机!
面试官(面无表情):……今天我们聊电商秒杀系统,结合 Spring Boot、Kafka 和 Redis,准备好了吗?
🟢 第一轮:基础构建 —— 秒杀系统的骨架
Q1:如果让你设计一个基于 Spring Boot 的秒杀接口,你会怎么初始化项目结构?Maven 还是 Gradle?为什么?
A1 - 谢飞机:这我会!当然用 Maven 啊,公司都用这个,标准统一,插件多,
pom.xml一看就懂。而且我背过 starter 列表:spring-boot-starter-web、starter-data-jpa、starter-redis……面试官:不错,至少没说用 Ant。(微微点头)那你说说,秒杀请求进来,Controller 层该怎么处理才能避免瞬间压垮服务器?
A2 - 谢飞机:嗯……加
@RequestMapping("/seckill"),然后写个方法返回 boolean?不对不对……哦对!要加限流!我记得有
@RateLimiter注解!面试官:那是你梦里的注解。真实世界里呢?
A2 - 谢飞机:啊……是不是可以用
Hystrix或者Resilience4j?我在网上看到过,能熔断!面试官:还行。其实更基础的是使用 WebMvcConfigurer 配合拦截器做前置校验,比如用户登录、活动状态检查。
Q3:库存扣减放在哪里比较合适?Service 还是 Controller?为什么?
A3 - 谢飞机:肯定 Service 呀!这是基本功!Controller 只负责接收参数和返回结果,不能写业务逻辑,不然测试都难写!
面试官:很好,终于有个清晰的回答了。继续保持。
🟡 第二轮:进阶挑战 —— 高并发与数据一致性
Q4:假设商品库存是 100,如何防止超卖?你在数据库层面怎么做?
A4 - 谢飞机:简单!每次扣减前查一下库存,大于 0 就减 1!SQL 写
UPDATE goods SET stock = stock - 1 WHERE id = 1 AND stock > 0,这样就不会负数啦!面试官:那你有没有考虑多个线程同时执行这条 SQL 会怎样?
A4 - 谢飞机:呃……应该没问题吧?MySQL 会自动排队?
面试官:不完全对。你需要明确的事务隔离级别,最好是
REPEATABLE READ,并配合悲观锁SELECT ... FOR UPDATE,或者乐观锁 version 控制。Q5:如果数据库压力太大,能不能先把库存放在 Redis 里?怎么保证 Redis 和 DB 的一致性?
A5 - 谢飞机:可以可以!Redis 很快!我先把库存 load 到 Redis,每次秒杀就
DECR一下,到 0 就不让买了!至于一致性嘛……等秒杀结束再同步回数据库?
面试官:这叫最终一致性。但万一 Redis 挂了怎么办?或者机器重启丢数据?
A5 - 谢飞机:那……那就持久化?RDB+AOF?
面试官:勉强及格。真正高可用要用 Redis Cluster,配合 Lua 脚本原子操作,再加上本地缓存 + 降级策略。
🔴 第三轮:架构视野 —— 异步化与削峰填谷
Q6:10万用户同时点“立即抢购”,你的服务直接被打满怎么办?
A6 - 谢飞机:加服务器!横向扩容!云上一键伸缩!
面试官:成本太高。技术手段呢?
A6 - 谢飞机:嗯……可以用消息队列?把请求发到 Kafka?
面试官:继续。
A7 - 谢飞机:消费者慢慢从 Kafka 读,一个个处理,相当于排队……这样数据库就不崩了!
面试官:对,这就叫“削峰填谷”。那 Kafka 如何保证消息不丢失?Producer 发送失败怎么办?
A7 - 谢飞机:呃……重试?设置
retries=3?面试官:还不够。你要设置
acks=all,ISR 副本同步完成才算成功。还要开启幂等 Producer,防止重复。Q8:如果某个用户提交了两次请求,你怎么防重?
A8 - 谢飞机:前端按钮变灰?
面试官:后端呢?
A8 - 谢飞机:嗯……用 Redis 存个 key,比如
user:123:seckill:goods:456,存在就不能再提交……面试官:不错,这是分布式锁的一种简化版——叫“唯一令牌机制”。还可以结合 Token Bucket 算法做频率控制。
面试官:今天就到这里。
谢飞机:您看我能进二面吗?
面试官:回家等通知吧。
✅ 真实答案详解:电商秒杀系统的技术全景图
💼 业务场景:电商平台大促秒杀
- 用户在指定时间抢购限量商品(如 iPhone 限时 1 折)
- 特点:瞬时高并发、请求集中、资源有限、极易发生超卖或系统雪崩
🧱 技术选型与实现要点
1.项目构建:Spring Boot + Maven
- 使用
spring-boot-starter-parent统一版本管理 - 引入关键依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>
2.接口防护:限流 & 熔断
- 使用Resilience4j实现限流:
RateLimiter rateLimiter = RateLimiter.ofDefaults("seckill"); Supplier<Response> decorated = RateLimiter.decorateSupplier(rateLimiter, this::doSeckill); - 配合 Sentinel 或 Hystrix 做熔断降级,保护下游服务
3.库存扣减:三层防御机制
| 层级 | 方案 | 说明 | |------|------|------| | 前端 | 按钮置灰、倒计时 | 初级防护 | | 缓存 | Redis 原子 DECR + Lua 脚本 | 快速拦截 | | 数据库 | 乐观锁 / 悲观锁 | 最终一致 |
示例 Lua 脚本防止超卖:
if redis.call('get', KEYS[1]) > 0 then return redis.call('decr', KEYS[1]) else return -1 end4.异步削峰:Kafka 解耦请求
- 秒杀成功后发送消息到 Kafka Topic:
seckill-order - 后台消费者异步创建订单、扣减账户、发短信通知
- 解决同步阻塞问题,提升吞吐量
5.防刷与防重:Token 机制
- 用户进入页面时获取唯一 token(JWT 或 UUID)
- 提交秒杀请求必须携带 token
- 后端用 Redis 标记
token_used:{token},防止重复提交
6.监控与可观测性
- 使用Prometheus + Grafana监控 QPS、响应时间、Redis 命中率
- 日志收集通过ELK Stack分析异常请求
- 链路追踪使用Zipkin/Jaeger查看全流程耗时
🏁 总结:大厂看重的能力维度
| 维度 | 考察点 | |------|--------| | 基础编码 | Spring Boot 结构、MVC 分层 | | 并发处理 | Redis 扣库存、锁机制 | | 架构思维 | 消息队列削峰、系统分层 | | 故障应对 | 数据一致性、容错设计 | | 学习能力 | 是否了解 Resilience4j、Kafka ISR |
⚠️ 提醒:不要只背答案,理解“为什么”比“是什么”更重要。
结尾彩蛋:
谢飞机回家路上自言自语: “原来
@RateLimiter真的不存在……怪不得我一直运行报错。”