大厂电商秒杀场景 Java 面试实战:从 Spring Boot、Redis、Kafka 到简单 RAG 智能客服
场景:某互联网大厂电商事业部,招聘 Java 开发工程师。业务方向:电商秒杀 + 简单 AI 智能客服。 角色:
- 面试官:L 老师(严肃认真,偏业务 + 架构)
- 候选人:小Y(略水,基础还行,复杂问题开始嘴硬、含糊其辞)
全文分两部分:
- 面试对话(3 轮,每轮 3~5 个问题),先看故事进入场景
- 面试题详细解析,带业务场景 + 技术要点,适合小白系统学习
一、面试对话实战
第一轮:接口设计 & 基础服务(Spring Boot + REST + MySQL)
背景:
公司准备搞一个「618 秒杀」活动,主打一个爆款手机,期望高并发、强参与感、低成本 。你要负责秒杀下单服务。
Q1:自我介绍 & 你做过什么电商/订单相关项目?
面试官:
先简单介绍下你自己,重点说说你做过的电商、订单或高并发相关项目?
小Y:
我之前在一家"本地生活 + 商城"的公司,主要做 Java 后端,用 Spring Boot 写了一些下单、支付回调接口,还搞过一点点活动秒杀,虽然流量不算特别大,但总体还挺稳定的。数据库用的是 MySQL,加了 Redis 做缓存,然后用 Jenkins 做自动部署,大概是这样的。
面试官:
嗯,至少是做过业务的,我们往秒杀场景具体聊聊。
Q2:设计一个秒杀下单接口,整体 API 怎么设计?
面试官:
假设我们要做一个手机秒杀,请你设计一个「发起秒杀下单」的接口,简单说下:
- URL 怎么设计?
- 入参与出参大致长什么样?
- 你用什么框架、怎样组织 Controller / Service / Repository?
小Y:
嗯......我会用 Spring Boot + Spring MVC 来写这个接口,大概这样:
- URL:
POST /api/seckill/orders - 请求体会传
userId、productId、seckillPrice、addressId之类的 - 返回就一个统一的
Result,有code、msg,成功时还带一个orderId
代码组织上我会这样:
SeckillOrderController:负责接请求和返回SeckillOrderService:做校验和下单逻辑SeckillOrderRepository或用MyBatis Mapper:负责数据库持久化
还会设计一个统一的异常处理,比如 @ControllerAdvice 处理业务异常,保持接口风格统一。
面试官:
基本的接口设计没问题,后面我们会看你怎么把它做成一个扛得住高并发的秒杀接口。
Q3:数据库表怎么设计?如何避免最基本的超卖?
面试官:
秒杀的商品库存怎么设计?订单表、库存表里要哪些关键字段?你会用什么最朴素的方式避免超卖?
小Y:
数据库会有几张表:
product_sku表:记录商品 SKU、原价、库存、状态等等seckill_activity表:记录活动的时间范围、秒杀价格、限购数量seckill_order表:记录秒杀订单,字段有order_id、user_id、sku_id、seckill_price、status等
避免超卖的话,最简单的方式是在数据库层面加行级锁,比如:
sql
UPDATE product_sku
SET stock = stock - 1
WHERE sku_id = ? AND stock > 0;
然后看返回行数是否为 1,如果是 0 就认为卖完了。这样能避免并发扣成负数。
面试官:
这个是最基础的"数据库乐观锁方案",对理解很重要。后面我们会讨论更高并发时怎么做削峰和限流。
Q4:你会用哪些日志和监控手段保证这个接口上线后可观测?
面试官:
这个秒杀下单接口上线之后,出了问题你得第一时间知道。你在项目里一般怎么做日志和监控?
小Y:
日志方面,我一般会用:
SLF4J + Logback作为日志门面和实现- 打
info日志记录主要流程,error记录异常,还会加一个 TraceId 做链路跟踪
监控方面:
- 可以用
Micrometer+Prometheus上报接口 QPS、成功率;再用Grafana做看板 - 比较简单的时候也会直接接公司的 ELK,把日志打到
Elasticsearch,再用Kibana搜索
面试官:
有基础的观测意识,这点不错。后面我们会把链路拉长,看你在微服务、MQ、缓存这些点上怎么监控。
Q5:你会怎么做最基本的接口测试?
面试官:
你写完这个秒杀接口之后,不考虑特别极端的场景,最起码的测试怎么做?
小Y:
- 单元测试用
JUnit 5 + Mockito做 Service 层的逻辑测试 - 接口层会用 Postman 或者用
Spring MockMvc写集成测试 - 会准备一些正常和异常的用例,比如:库存足够、库存不足、活动未开始、重复下单之类的
面试官:
OK,第一轮先到这儿,整体思路还比较正常,我们进到秒杀真正难的地方。
第二轮:高并发秒杀架构(Redis + Kafka + 分布式锁 + 限流)
背景:
这次活动被推到首页 Banner,预计峰值 10 万 QPS ,你刚刚那套「直接打 MySQL」显然会炸。需要你设计一套高并发秒杀架构。
Q6:如何用 Redis 做库存预减和防超卖?
面试官:
用户量上来之后,你不可能让所有请求都打到数据库。你打算怎么利用 Redis 在前面"兜一下",做到削峰、防超卖?
小Y:
我会在秒杀开始前把库存同步到 Redis,比如用一个 Key:seckill:stock:skuId。
秒杀下单时:
- 先在 Redis 做预减库存 :
- 用
DECR或INCRBY之类的操作 - 如果扣完后库存小于 0,就说明没货了,再把数量加回去或直接返回"秒杀结束"
- 用
- 只有预减成功的请求才会进入后面的异步下单流程
这样大部分请求都挡在 Redis,不会直接打穿数据库。
面试官:
预减库存的思路是对的,但还没完全说清楚怎么保证一致性,我们后面结合 MQ 再聊。
Q7:大量请求同时打来,你怎么削峰填谷?
面试官:
即使你的 Redis 扛得住,下游的订单服务、支付服务、数据库很可能扛不住。你除了 Redis,还有什么手段来"削峰填谷"?
小Y:
我会引入 MQ,比如 Kafka 或者 RabbitMQ:
- 前端接口只负责做:限流 + 校验 + Redis 预减库存,然后扔一条「下单消息」到 Kafka
- 后端有一个下单消费服务,从 Kafka 按照自己的消费能力慢慢拉消息,去落库、减真实库存、创建订单
- 如果消费失败,可以放到重试队列或死信队列
这样前端接口只要把消息投递成功,就快速返回"排队中",真正的订单创建由后端异步完成,实现削峰填谷。
面试官:
这是秒杀架构的标配方案之一。后面我们会问你如何保证消息不丢、去重以及幂等。
Q8:如何防止用户重复秒杀同一件商品?(幂等 & 防重)
面试官:
秒杀活动往往要求每个用户限购 1 件。你会在什么地方做"防重复下单"?怎么保证幂等?
小Y:
我会在 Redis 做一个去重标记,比如:
- Key:
seckill:order:skuId:userId - 在用户第一次下单的时候用
SETNX设置这个 Key,设置成功说明是第一次 - 如果
SETNX返回失败,就认为用户已经秒杀过,直接返回"已参与"
在消费端创建订单时也会校验一下数据库里面是否已经有该用户的秒杀订单,防止出现重复。
面试官:
思路算可以,实际上会结合 Redis 原子操作和数据库里唯一索引一起做双保险。
Q9:使用分布式锁防止超卖,你会怎么做?
面试官:
在某些关键逻辑里,比如扣减秒杀库存,你会用到分布式锁。你能说一下用 Redis 分布式锁的基本方法吗?
小Y:
一般会用 Redis 的 SETNX 来实现分布式锁:
- 尝试
SET lockKey requestId EX 5 NX,加过期时间 - 如果返回 OK,说明获得锁
- 处理完业务后,再检查 Value = requestId 时才删除锁,避免误删别人加的锁
或者直接用 Redisson 这种客户端,它封装了可重入锁、公平锁等实现,使用更简单。
面试官:
细节还可以再严谨一点,比如考虑锁过期、业务执行时间过长等问题,但对你这个级别来说,可以接受。
Q10:限流你会怎么做?在网关层还是服务层?
面试官:
秒杀开始瞬间流量可能会很夸张,你会用什么限流策略?是在 Nginx / 网关做,还是在应用里做?
小Y:
我会多层做限流:
- Nginx / API Gateway 层 :
- 用漏桶或令牌桶算法做全局 QPS 限制,保护后端集群
- 应用层 :
- 使用像
Resilience4j或网关自带的限流组件,对单个接口、单个 IP 做更精细限流
- 使用像
- 对同一用户会加一些行为风控,比如单位时间内请求次数超过阈值就暂时封禁,防止刷接口
面试官:
有全局限流的意识就行。实际生产上还会结合风控和验证码等多种手段。
第三轮:监控与压测、微服务拆分 & 简单 AI 智能客服(Spring Cloud + RAG)
背景:
秒杀系统准备上线,需要你补上压测 + 监控 + 故障演练 。另外公司想做一个简单的智能客服,能回答"订单什么时候发货""秒杀规则是什么"之类的问题,你需要给到技术方案。
Q11:你会如何做压测?验证系统能扛住多少 QPS?
面试官:
活动前肯定要压测,你会用什么工具、怎么设计压测场景?
小Y:
我会用 JMeter 或者 Gatling 做压测:
- 先用 JMeter 录制或手动写压测脚本,对秒杀下单接口进行压测
- 模拟多种场景:正常流量、短时间内高峰流量、慢慢升压
- 观察接口 RT、错误率、吞吐量,结合 Prometheus / Grafana 看 CPU、内存、Redis、Kafka、数据库的指标
面试官:
大思路 OK,不过你还没提到对依赖服务的压测隔离,这块可以再补补。
Q12:微服务拆分时,秒杀系统大概怎么拆?
面试官:
秒杀系统要跟购物车、商品中心、用户中心、支付系统等配合。站在 Spring Cloud 的视角,你会做哪些服务拆分?
小Y:
大概会拆这些服务:
- 秒杀活动服务:负责创建和管理秒杀活动
- 秒杀下单服务:负责处理秒杀请求,跟 Redis、MQ 打交道
- 订单服务:统一处理普通订单和秒杀订单的创建、状态变更
- 库存服务:维护库存中心,接收扣减请求
- 用户服务:负责用户信息、等级、黑名单之类
服务间通过 Spring Cloud 或 OpenFeign 调用,注册中心可以用 Nacos 或 Eureka,做服务发现和负载均衡。
面试官:
拆得还行,后面再考虑实际团队规模、数据一致性,会更复杂一些。
Q13:你怎么追踪一次秒杀请求从网关到订单落库的完整链路?
面试官:
一次秒杀请求,要经过网关、秒杀服务、MQ、订单服务、库存服务,如果中间出问题,你怎么快速知道问题在哪一步?
小Y:
会做 分布式链路追踪:
- 在网关生成一个全局
traceId,通过 HTTP Header 和 MQ 消息头传递给下游 - 各个服务接到请求后,用同一个
traceId打日志 - 使用像
SkyWalking、Zipkin或Jaeger这样的链路追踪系统,结合Micrometer上报指标
这样一条请求在 UI 上会显示一条调用链,出问题时直接可以看到是哪个服务耗时过高或报错。
面试官:
有链路追踪意识是好事,工业级大厂基本都这么干。
Q14:公司想搞一个简单智能客服,回答订单/秒杀相关问题,你会怎么设计?
面试官:
假设我们打算用大模型做一个简单智能客服:
- 用户问:"我这个秒杀订单什么时候发货?"
- 或者问:"秒杀规则是什么?" 你会怎样设计后端系统?可以简单说说 Spring Boot 配合向量数据库、RAG 的方案。
小Y:(开始有点慌)
嗯......AI 这块我了解得不是特别深,不过大概的思路是这样:
- 把我们订单的 FAQ、秒杀规则、物流 SLA 这些文档整理好
- 用一个 Embedding 模型把这些文档向量化,存到像 Milvus、Redis 这种向量数据库里
- 用户提问时,把问题也做向量化,在向量库里做语义检索,找到最相关的几段文档
- 再把这些文档片段和用户问题一起丢给大模型,让它生成回答
具体落地的话可以用......像 Spring AI 这种框架,封装一下向量检索和大模型调用。架构上就是一个独立的"智能客服服务",跟订单服务通过接口交互。
面试官:
方向是对的,但你说得很泛:
- 向量化怎么做更新?
- 会话记忆怎么处理?
- 如何控制大模型的幻觉? 这些你都没说到,我们回头在答案解析里帮你补全。
小Y:嘿嘿......这个,我回去再系统学一下。
Q15:如果大模型"瞎编"了一个错误的秒杀规则,怎么降低这种风险?
面试官:
最后一个问题:大模型有"幻觉"问题,如果它胡说八道一个并不存在的秒杀规则,对业务会造成严重影响,你会怎么设计来降低这个风险?
小Y:(开始严重含糊)
这个......我觉得可以......多训练一下模型?然后......让它多看点我们真实的规则文档?
嗯......然后可能,可以加一些关键词匹配,发现不太对的就拦一下?
面试官:
好的,我大概知道你在 AI 这块的掌握程度了。
今天先聊到这里吧,整体基础还可以,复杂场景下的细节掌握得还不够扎实,尤其是 AI + 业务这块。我们会综合评估一下,你先回去等通知。
(小Y:心想------又是"等通知",这通知大概是不会来了......)
二、面试题详细解析(小白向)
下面按照刚才的 3 轮提问,逐题给出详细解析,帮助你把电商秒杀 + 简单 RAG 智能客服这条技术链路打通。
第一轮解析:接口 & 数据库设计 + 日志监控 + 基础测试
1. 秒杀下单接口设计(Spring Boot + REST)
核心点:
- 使用 Spring Boot + Spring MVC 暴露 REST 接口
- URL 风格:资源化,简洁明了,如
POST /api/seckill/orders - 统一响应结构 + 全局异常处理
示例:
java
@RestController
@RequestMapping("/api/seckill")
public class SeckillOrderController {
private final SeckillOrderService seckillOrderService;
public SeckillOrderController(SeckillOrderService service) {
this.seckillOrderService = service;
}
@PostMapping("/orders")
public ApiResponse<Long> createOrder(@RequestBody SeckillOrderRequest request) {
Long orderId = seckillOrderService.createOrder(request);
return ApiResponse.success(orderId);
}
}
ApiResponse封装code、message、data@ControllerAdvice+ 自定义异常,统一返回错误码
适用技术栈:Spring Boot、Spring MVC、Jackson。
2. 数据库表设计 & 基础防超卖(乐观锁)
基本表结构:
-
product_skuidproduct_idsku_nameorigin_pricestockstatus
-
seckill_activityidsku_idseckill_pricestart_time/end_timelimit_per_user
-
seckill_orderid(雪花算法等)user_idsku_idseckill_pricestatus
防超卖(最简单方案):
依赖数据库更新的行级约束:
sql
UPDATE product_sku
SET stock = stock - 1
WHERE id = ? AND stock > 0;
- 返回影响行数=1:扣减成功,可以创建订单
- 返回 0:库存不足或不存在
这个方式在并发不高时有效,缺点是所有请求都打 MySQL,扛不住高并发。
3. 日志和监控:Logback + ELK + Prometheus + Grafana
推荐做法:
-
日志:
- 使用 SLF4J + Logback 或 Log4j2
- 打印关键字段:
traceId、userId、skuId、orderId等 - 使用 JSON 日志格式便于 ELK 分析
-
日志收集 & 搜索:
- Filebeat/Logstash 收集 -> Elasticsearch -> Kibana (ELK Stack)
-
指标监控:
Micrometer采集:QPS、RT、错误率、Redis 命中率、Kafka Lag 等- 时序数据库:Prometheus
- 可视化:Grafana 仪表盘
4. 基础自测:JUnit5 + Mockito + MockMvc
- Service 层:
- 用 JUnit5 + Mockito mock 掉 Repository
- 覆盖核心逻辑:库存校验、活动时间校验、幂等校验
- Controller 层:
- 用 MockMvc 做接口自动化测试
- 校验 HTTP 状态码、JSON 返回结构
扩展工具:AssertJ 做更清晰的断言、Testcontainers 做集成测试。
第二轮解析:高并发秒杀架构(Redis + Kafka + 限流 + 分布式锁)
5. Redis 预减库存 + 防超卖
基本流程:
- 活动预热:
- 将库存从 MySQL 同步到 Redis:
seckill:stock:{skuId} = realStock
- 将库存从 MySQL 同步到 Redis:
- 用户请求进来:
- 使用 Redis 原子操作预减库存:
lua
-- 伪代码(也可以用 Lua 脚本)
local stock = redis.call('DECRBY', stockKey, 1)
if stock < 0 then
redis.call('INCRBY', stockKey, 1)
return 0
else
return 1
end
- 预减成功:进入 MQ 异步下单流程
- 预减失败:秒杀结束 or 库存不足
优势:
- 绝大部分请求都被 Redis 接住
- 避免高并发直接冲击数据库
注意:
- Redis 数据与 DB 一致性问题,需要结合后面 MQ 逻辑和超卖回补机制一起设计
6. Kafka/RabbitMQ 削峰填谷
典型架构:
seckill-api-service:- 负责:参数校验 + 限流 + Redis 库存预减 + 发送 MQ 消息
seckill-consumer-service:- 从 Kafka 消费消息,调用订单服务写数据库
order-service:- 处理订单持久化和状态流转
消息流程:
- 前端:请求秒杀接口
- API 服务:
- Redis 预减成功
- 发送消息:
seckill-order-create到 Kafka - 返回"排队中/下单成功(异步)"
- 消费者服务:
- 拉取消息 -> 校验 -> 落库 -> 更新真实库存
要点:
- 要保证消息至少投递一次 :
- 生产端开启事务或可靠消息
- 消费端做幂等处理(比如订单表加唯一索引、用 Redis 记录消息消费状态)
7. 防重复下单(幂等与去重)
多层防重方案:
- Redis 防重:
text
Key: seckill:order:{skuId}:{userId}
Value: 1
操作: SETNX + TTL
-
数据库防重:
seckill_order表增加联合唯一索引:unique(user_id, sku_id, activity_id)
-
消费端幂等:
- 拿到消息时,先检查是否已有订单,如果有则直接 ack,不再创建
8. Redis 分布式锁的基本实现
方案一:手写 SETNX 锁:
text
SET lockKey requestId EX 5 NX
// 执行业务
// 删除前先判断 value == requestId
问题:
- 业务执行时间可能 > 过期时间
- 锁自动过期,可能被其他请求抢走,容易误删
方案二:Redisson:
- 提供
RLock、RReadWriteLock、RSemaphore等封装 - 支持自动续期(看门狗机制),降低锁丢失风险
秒杀里尽量少用大颗粒锁,优先用:
- 原子操作(
INCR/DECR) - 唯一索引
- CAS 等方式
9. 限流(网关 + 应用层)
常见策略:
- 网关层(Nginx / Spring Cloud Gateway):
- IP 限流:防止部分 IP 恶意刷
- 全局 QPS 限流:保护后端实例
- 应用层:
- 使用
Resilience4j进行接口级限流、隔离、熔断 - 结合用户维度的限流(单用户 QPS 限制)
- 使用
搭配安全与风控:
- 验证码、人机校验
- 黑名单/灰名单(存 Redis、使用 Spring Security / Shiro)
- 行为分析 + 简单风控策略
第三轮解析:压测 & 监控 & 微服务 & 简单 RAG 智能客服
10. 压测:JMeter + Prometheus + Grafana
压测目标:
- 证明系统在某个 QPS 下,RT 可接受、错误率可控
基本步骤:
- 设计压测脚本:
- 用 JMeter 录制或手动配置 HTTP 请求
- 参数化 userId、skuId
- 加上合理的思考时间
- 场景:
- 升压:从 1k QPS 慢慢上升到 10k QPS
- 峰值:长时间保持高压
- 观察指标:
- 应用层:QPS、RT、错误率
- 系统层:CPU、内存、GC、线程数
- 依赖组件:Redis 命中率、Kafka Lag、MySQL TPS
- 瓶颈分析:
- 通过压测 + 链路追踪定位慢点
工具拓展:Gatling(更适合代码化场景)、Locust 等。
11. 微服务拆分(Spring Cloud、OpenFeign)
典型拆分方案:
gateway-service:统一入口,鉴权、限流user-service:用户信息、黑名单、等级product-service:商品和库存基础数据seckill-service:活动管理、秒杀资格校验、Redis 操作、MQ 投递order-service:订单创建和状态管理payment-service:支付对接customer-service:客服/工单系统(后面接 AI)
技术选型:
- 注册中心:Eureka / Nacos / Consul
- HTTP 调用:OpenFeign / RestTemplate / WebClient
- 配置中心:Spring Cloud Config / Nacos Config
- 熔断 & 限流:Resilience4j
要点:
- 领域划分清晰
- 尽量避免强耦合,避免跨服务事务,使用最终一致性方案(消息 + 状态机)
12. 分布式链路追踪(Zipkin / Jaeger / SkyWalking)
流程:
- 网关生成
traceId,放在 HTTP Header(如X-Trace-Id) - 下游服务读取并透传
- 使用 APM/Tracing 组件采集链路信息
- 在 UI 中查看调用拓扑和某条请求的详细链路
常用组合:
- Spring Boot + Sleuth(或 Micrometer Tracing)+ Zipkin
- 或 SkyWalking Agent 无侵入埋点
搭配日志:
- 在日志中打印
traceId,方便从链路跳到日志详情
13. 简单 RAG 智能客服:从文档到问答
RAG(Retrieval-Augmented Generation)核心思路:
大模型不直接"硬想",而是先从知识库里检索相关文档,再基于检索结果生成回答。
(1)文档准备与向量化
- 文档类型:
- 秒杀活动规则文档
- 订单流程 FAQ
- 发货时效(按城市/仓库)
- 文档切分:
- 按段落、按 200~500 个字切片,避免太长
- 向量化:
- 使用 Embedding 模型(如 OpenAI、Ollama、本地模型)将每个文档片段转换成向量
- 存入向量数据库(Milvus、Chroma、Redis Vector、Elasticsearch KNN)
(2)在线问答流程
- 用户提问:"我的秒杀订单什么时候发货?"
- 步骤: -(可选)结合订单系统实时查询该订单的当前状态
- 把用户问题做向量化,去向量数据库做语义检索,取 TopK 的相关文档片段
- 构建 Prompt:把用户问题 + 检索出的文档片段拼接
- 调用大模型(LLM)生成回答
在 Spring Boot 中可以使用:
Spring AI框架封装 LLM 调用、向量化和检索- 或者自封装 HTTP 客户端调用模型服务(Google A2A、OpenAI 等)
(3)会话记忆 & 工具调用
- 会话记忆:
- 用 Redis 或其他存储保留最近几轮对话
- 在 Prompt 中加入"对话历史摘要",实现多轮对话
- 工具调用:
- LLM 通过"工具调用协议"(类似 MCP、工具执行框架)调用后端工具
- 例如:查询订单详情、查看物流进度
场景:
- 用户问:"帮我查下今天的秒杀订单有没有发货?"
- LLM:先调用"订单查询工具" -> 拿到状态 -> 再用自然语言解释结果
14. 如何减少大模型幻觉(错误回答)对业务的影响?
这一题小Y回答得很含糊,我们在这里补全:
常见手段:
- 严格基于检索结果回答 :
- Prompt 中明确约束:"只能根据给出的文档回答,不要编造,没有答案就说不知道"
- 答案置信度与引用 :
- 要求模型在回答中引用来源文档的关键字段
- 前端同时展示"参考规则/文档链接",用户可自行验证
- 业务规则前置校验 :
- 对核心字段(价格、活动时间、限购规则)不要让模型自由生成
- 从业务系统(活动中心)获取结构化数据,让模型只做"自然语言解释"
- 敏感问题兜底 :
- 对涉及赔付、条款解释等敏感问题,采用模板化+规则回答
- 或直接转人工客服
这就形成一个Agentic RAG 的雏形:
- Agent 根据问题决定:
- 是走 RAG 文档问答
- 还是调用业务工具
- 还是直接转人工
总结
这篇文章通过一个大厂面试故事,把一个"电商秒杀 + 简单 AI 智能客服"的技术栈串起来了:
- 第一轮:接口设计、数据库防超卖、日志监控、自测
- 第二轮:Redis 预减库存、MQ 削峰填谷、幂等与分布式锁、限流
- 第三轮:压测与观测、微服务拆分、链路追踪、RAG 智能客服与幻觉控制
你可以把这些问题当成自己的自测清单,逐个补齐实践。哪怕暂时回答得像小Y一样含糊,只要愿意系统补课,下次面试就有机会从"水货"进化成"真材实料"。