大厂电商 Java 面试实录:从 Spring Cloud 到 Kafka、Redis,再到 AI RAG 实战

场景:某互联网大厂电商事业部,招聘 Java 后端工程师。面试官很严肃,候选人小Y则是个有点搞笑、略带水的程序员。

业务背景:大促场景下的电商下单、库存、支付风控 + 智能客服(AI RAG)。


第一幕:基础电商下单链路(Spring Boot + MyBatis + Redis + Kafka)

面试官(M): 小Y,我们先从最基础的电商下单场景开始。假设我们有一个标准电商网站,用户在商品详情页点击“立即购买”,后端大概会经历哪些核心步骤?你用你熟悉的技术栈,从浏览器到后端,再到数据库,简单说一下调用链。

小Y(Y): 这个…大概就是用户点一下,然后到我们后端的那个 Controller,然后 Service,再到 DAO,最后落到数据库…中间可能还要校验一下库存啥的。呃,用 Spring Boot 写个接口,用 MyBatis 查一下库就行了。

M: 嗯,整体方向还可以,但细节有点“空气感”。如果我们技术栈是:Spring Boot + Spring MVC + MyBatis + Redis + Kafka,你补充一下:

  1. 网关层会怎么设计?
  2. 订单服务怎么做防重复下单?
  3. Redis 在这个链路里放在哪儿?

Y: 网关的话…可以用 Nginx,再配合 Spring Cloud Gateway 吧,做个统一入口,反正就是转发请求。防重复下单的话,可以…用个 token?Redis 就用来存点缓存,比如商品信息啥的,顺便放一放那个 token ?

M: 有点思路。那如果要做“下单异步化处理”,比如发送消息给库存服务、营销服务,你会选什么消息队列?在 Spring 里怎么用?

Y: 这个我肯定选 Kafka,大厂都用 Kafka。Spring 里面…用 Spring Kafka,@KafkaListener 监听一下,然后发消息就用那个模板类,KafkaTemplate。大概就几行代码吧。

M: 行,那你先记着这些关键词:

  • API 网关:Spring Cloud Gateway / Nginx
  • 下单防重:幂等(token、去重表、Redis set)
  • Redis:缓存商品、用户会话、防重 token
  • Kafka:订单事件异步通知库存、营销

我们后面会详细展开。


第二幕:秒杀与高并发库存(Redis + Lua + 分布式锁 + 限流)

M: 现在业务升级了,我们有一个“秒杀活动”:

  • 10 点整开放
  • 单个商品 1000 件
  • 高峰期每秒 5 万请求涌入

你如果还是 Spring Boot + Redis + MyBatis,你会怎么避免“超卖”?

Y: 秒杀…这个压力很大的。我记得可以把库存放 Redis 里面,这样就不用直接打数据库了。然后每次减库存就 decr 一下,减到 0 就不卖了。然后…再异步写数据库?

M: 可以。那如果在极端并发下,同时多个服务实例都在减 Redis,如果只是简单 decr,有没有问题?需要考虑什么?

Y: 呃,Redis 单线程嘛,应该问题不大?顶多就是快一点慢一点,不太会乱吧…

M: Redis 单线程只保证单条命令执行的原子性,但你整个下单流程不止一条命令。

你考虑下这个流程:

  1. 校验库存 > 0
  2. 校验用户是否已经抢过(一个人限购 1 件)
  3. 扣减库存
  4. 写入用户已抢购记录

如果这些操作不是一个原子操作会怎么样?你会怎么设计?

Y: 嗯…那可能会有这种情况:库存够,但是两个人同时看到了,然后都减成功了,就超卖。解决的话…是不是可以用 Redis 的 Lua 脚本,把几步写到一个脚本里面,让它一次执行完,这样就是原子操作了?

M: 对,这个思路对了。那假如你的活动不止一个商品,还有上百个秒杀商品,甚至多机房部署,你只靠 Redis Lua 够不够?要不要再加限流和熔断?

Y: 多机房……这个有点复杂。要不要再上个那个…呃,那个…分布式锁?比如用 Redisson?限流的话,可以用网关那边搞个限流组件,或者用 Sentinel、Resilience4j 之类的吧。

M: 好,分布式锁、限流、熔断这些词你先记下。

我们业务上通常会这么做(先不展开细节):

  • 网关/接口级限流:挡掉一大部分流量
  • Redis 预减库存 + Lua:防止超卖
  • 分布式锁(Redisson / 基于 Redis 或 Zookeeper):避免重复处理同一活动配置
  • 异步消息(Kafka):真正的订单创建、数据库落库

第三幕:支付与风控(分布式事务 + 消息一致性 + 分布式 ID)

M: 用户下单后要走支付。假设我们有:

  • 订单服务(Order Service)
  • 支付服务(Payment Service)
  • 风控服务(Risk Service)

用的是 Spring Cloud、OpenFeign、Kafka,你会如何保证“订单状态”和“支付状态”的一致性?比如:用户支付成功了,但订单状态却一直是“待支付”,你打算怎么办?

Y: 这个…要不我们上个分布式事务?用那个 XA 啥的…或者 Seata?这样几个服务就绑在一起,要么都成功,要么都失败。

M: 实际上在高并发电商里,很少直接用强一致性的分布式事务,因为会性能很差。我们更常用“最终一致性”,你听过“本地消息表”、“事务消息”这种方案吗?

Y: 好像看过,说是本地先写个消息表,然后再发 MQ,那如果失败了就可以重试。细节我有点记不清了…

M: 那暂时就先到这。你要记:

  • 强一致:分布式事务(XA、二阶段提交)
  • 最终一致:本地消息表、可靠消息 + 重试、Outbox Pattern
  • 分布式 ID:雪花算法(Snowflake)、号段模式(Segment)、Leaf 服务

这些在支付和风控场景都非常常见。


第四幕:AI 智能客服与 RAG(Spring AI + 向量数据库 + 检索增强生成)

M: 我们现在接入了 AI 智能客服,支持“订单问题咨询”和“退货换货说明”,技术栈是:

  • Spring Boot
  • Spring AI
  • 向量数据库(比如 Milvus / Chroma / Redis 向量索引)
  • RAG(检索增强生成)

先说下业务场景:

  1. 用户在 App 里输入:“我想退货,但是快递点说要我填一个单号,这个怎么弄?”
  2. 我们希望机器人能结合企业内部的“退货规则文档”和“用户当前订单状态”来回答。

你说说,RAG 模式下,这个流程大概会怎么走?

Y: RAG…就是检索增强生成嘛,我看过。大概流程是:

  1. 把那些退货规则的文档先切成小块,存到向量数据库里;
  2. 用户提问的时候,先做 Embedding,把问题变成向量,然后去向量库里召回相似的文档;
  3. 把召回的内容和用户问题一起给大模型,让它回答;
  4. Spring AI 里面有那种模板配置,写点 prompt 之类的。

大概就这样。

M: 方向不错。那你考虑下“企业内部订单系统”的数据,比如:订单是否已经发货、是否在 7 天无理由退货期内,这些是实时数据,不适合直接放向量库。你会怎么在一个请求里既用 RAG,又查实时业务数据?

Y: 这个…那就两个步骤吧:

  • 一边做 RAG,从文档里找规则;
  • 一边我再查一下订单数据库,比如用 JPA / MyBatis 查订单状态;
  • 最后把文档内容 + 订单状态拼在一起,给大模型,让它一起考虑。

至于具体怎么写,我没太写过,可能要看 Spring AI 的 demo。

M: 行,你理解到“文档知识 + 实时数据融合”就可以了。

再问一个:RAG 里很容易出现“幻觉”(Hallucination),你会怎么降低幻觉,让回答更可信?

Y: 幻觉…就是瞎编嘛。那就给模型多一点上下文?比如多喂点资料?或者在提示词里面告诉它“你不知道就说不知道”?

M: 这是一个方向,另外常见还有:

  • 检索时设置信心阈值,召回结果不靠谱就直接说“知识库里没找到”;
  • 回答里附上引用的文档片段或链接;
  • 对生成的答案做规则校验,比如金额、日期不合规就打回重试。

第五幕:监控与链路追踪(Prometheus + Grafana + Zipkin / Jaeger)

M: 多个服务 + MQ + AI 调用后,系统变得很复杂。我们要做监控与链路追踪。

技术栈:

  • 指标监控:Micrometer + Prometheus + Grafana
  • 日志:SLF4J + Logback + ELK
  • 链路追踪:Spring Cloud Sleuth + Zipkin / Jaeger

在“用户提交订单 -> 支付 -> 风控 -> 通知智能客服发送消息”这一串链路里,如果用户反馈“下单很慢”,你怎么排查是哪个环节慢?

Y: 这个要看日志,看看哪个服务耗时高。可以在每个接口打点日志,然后 ELK 搜一下。不过这个太慢了,如果有那个链路追踪系统,就可以看 trace id ,看哪个 span 时间长。

M: 对,那 trace 是怎么串起来的?比如:

  • 网关 -> 订单服务 -> 支付服务 -> Kafka -> 风控服务 -> 消息推送服务

你怎么保证这些跨服务调用都在同一个 trace 里?

Y: 好像 Spring Cloud Sleuth 会自动在 HTTP header 里加 traceId、spanId,然后 Feign 调用会自动把这些带过去。Kafka 那种消息队列也可以带一些 header,让消费者那边继续这个 trace。不过我没具体配过…

M: 思路对。你要知道关键点:

  • 通过 traceId 将一次用户请求的所有服务调用串起来
  • 指标监控看整体 QPS、RT,链路追踪看单次请求在各服务上的分布
  • 日志要统一格式,方便在 ELK 里按 traceId 检索

第六幕:面试收尾

M: 好,今天时间差不多了。你整体上对 Spring Boot、Redis、Kafka、Spring Cloud、RAG 等概念都有一些了解,但在很多细节的工程实现上还比较模糊,需要你回去多做实战。

我们后续会综合评估你的表现,回去等通知吧。

Y: 好的好的!那我回去先把 Lua、RAG、链路追踪再补一补,下次我争取能说得更清楚一点!


面试题详解:业务场景 + 技术点拆解

下面把刚才面试官问到的核心问题系统讲一遍,适合小白学习,也方便你面试前系统复盘。


一、基础下单链路:从浏览器到数据库

1. 调用链的典型结构

Spring Boot + Spring MVC + MyBatis + Redis + Kafka 为例,一个用户点击“立即购买”的链路通常是:

  1. 浏览器 / App 发起 HTTP 请求到 API 网关(Nginx / Spring Cloud Gateway)
  2. 网关做:
    • 认证鉴权(JWT / OAuth2 / Spring Security)
    • 限流(如基于 IP、用户 ID、接口维度)
    • 路由到对应的微服务(订单服务)
  3. 订单服务(Spring Boot):
    • Controller:接收请求参数,做基础校验
    • Service
      • 调用商品服务获取商品信息 / 价格(可通过 OpenFeign)
      • 校验库存(可调用库存服务,或查 Redis 预库存)
      • 做业务校验(地址、优惠券、风控初筛等)
    • DAO(Mapper):通过 MyBatis / JPA 操作数据库,插入一条订单记录
    • 缓存处理:用 Redis 缓存一些读多写少的数据
  4. 发 MQ 消息(Kafka):
    • 发送“订单创建事件”:
      • 通知库存服务锁库存
      • 通知营销系统记录一次成交

2. 防重复下单(幂等)

常见方案:

  1. 接口幂等 token
    • 下单前从服务端获取一个 orderToken(放在 Redis 或数据库)
    • 下单请求必须带上 orderToken
    • 服务端使用 Redis 的 SETNX(或 Lua 脚本)保证 token 只用一次
  2. 业务幂等键
    • 对同一用户 + 同一购物车 + 同一时间窗口生成一个“幂等 key”
    • 写入数据库或 Redis,检查是否已处理
  3. 数据库唯一约束
    • 如订单表里对 idempotent_key 建唯一索引

实际项目里一般是多个手段组合使用。

3. Redis 的角色

在下单链路中,Redis 常见用途:

  • 缓存商品信息(价格、库存快照)
  • 缓存用户会话(Session)、登录状态
  • 存储限流计数器
  • 存储幂等 token、验证码等

使用连接池(比如 HikariCP 用于数据库,Redis 客户端本身也有连接池配置)保证性能。

4. Kafka 的角色

Kafka 在电商订单场景中常见用途:

  • 订单事件:订单创建、订单支付成功/失败、订单取消
  • 库存同步:通过 Kafka 事件驱动库存服务更新
  • 营销埋点:用户行为数据上报大数据平台(Flink / Spark)

在 Spring 中通常用:

// 发送
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

public void sendOrderCreatedEvent(Order order) {
    kafkaTemplate.send("order-created-topic", order.getId().toString(), toJson(order));
}

// 接收
@KafkaListener(topics = "order-created-topic", groupId = "inventory-service")
public void onOrderCreated(String message) {
    Order order = parseJson(message);
    // 更新库存
}

二、秒杀和高并发库存控制

1. 问题:超卖、宕机、数据库被打爆

秒杀的特点:

  • 瞬时高并发(5 万 QPS 甚至更高)
  • 库存极少(比如 1000 件)
  • 用户体验敏感,对延迟非常敏感

如果用“直接写数据库”:

  • 数据库承受不了这么高的写压力
  • 并发下可能会出现超卖(事务隔离不当)

2. Redis 预减库存 + Lua 原子操作

典型做法:

  1. 活动开始前,把库存预加载到 Redis:
SET seckill:sku:123:stock 1000
  1. 用户请求秒杀时:
  • 使用 Lua 脚本 在 Redis 内部原子执行:
    • 检查库存是否 > 0
    • 检查用户是否已经抢过
    • 扣减库存
    • 记录用户已抢购

示例 Lua 逻辑(伪代码):

local stockKey = KEYS[1]
local userKey = KEYS[2]
local userId  = ARGV[1]

-- 是否已经抢购
if redis.call("SISMEMBER", userKey, userId) == 1 then
    return 0  -- 已抢过
end

local stock = tonumber(redis.call("GET", stockKey))
if stock <= 0 then
    return -1  -- 无库存
else
    redis.call("DECR", stockKey)
    redis.call("SADD", userKey, userId)
    return 1  -- 成功
end

这样整个操作在 Redis 内部是原子进行的,不会出现中间状态。

  1. 真正的订单创建、数据库写入通过 MQ 异步处理。

3. 网关限流、熔断与降级

在秒杀场景中,不是所有请求都值得进入服务内部:

  • API 网关(例如 Spring Cloud Gateway)上做限流:
    • 按 IP / 用户 ID 每秒 N 次
    • 固定窗口、滑动窗口、令牌桶等算法
  • 使用限流熔断组件:
    • Sentinel、Resilience4j
    • 当下游服务响应慢时,触发熔断,返回“稍后重试”

4. 分布式锁的使用场景

并不是所有东西都要上分布式锁,但在以下场景有用:

  • 修改某个秒杀活动配置(避免多管理员同时修改导致冲突)
  • 定时任务抢占执行权(例如只允许一个实例执行)

可用 Redisson 来实现基于 Redis 的分布式锁。


三、支付与风控:最终一致性与分布式 ID

1. 为什么不随便上分布式事务?

XA / 二阶段提交(2PC)的问题:

  • 性能差,延迟高
  • 单点风险大(协调者)
  • 在高并发电商场景不太适用

2. 最终一致性常见方案

  1. 本地消息表 / Outbox Pattern

    • 在订单服务本地事务中:
      • 写订单表
      • 写消息表(记录要发送的事件)
    • 事务提交后,单独的后台任务扫描“未发送成功”的消息表,发送到 Kafka / MQ
    • 发送成功后更新消息状态
  2. 事务消息(MQ 支持)

    • 如 RocketMQ 的事务消息
    • 半消息 + 本地事务回查,保证消息不会丢失或乱发
  3. 幂等消费

    • 消费端(支付服务、风控服务)根据消息 ID 做幂等,避免重复消费导致重复扣费等

3. 分布式 ID 生成

订单号、支付号一般需要:

  • 全局唯一
  • 趋势递增(便于数据库索引)
  • 高可用

常见方案:

  • 雪花算法(Snowflake):64 位长整型,包含时间戳 + 机房 ID + 机器 ID + 自增序列
  • 号段模式(Segment):从数据库一次取一段 ID 到内存,提升生成效率
  • 专门 ID 服务(如 Meituan Leaf)

四、AI 智能客服与 RAG(检索增强生成)

1. 业务目标

  • 用户自然语言提问:订单状态、退货规则、物流问题
  • AI 机器人结合:
    • 企业文档知识(退货政策、客服话术)
    • 实时业务数据(用户当前订单最新状态)

2. RAG 的核心流程

RAG(Retrieval-Augmented Generation)的管线一般为:

  1. 文档加载
    • 把企业内部文档(PDF、Word、网页)通过工具(如 LangChain loader)加载
  2. 文本切分
    • 以段落 / 语义为单位切块,比如每 512~1024 字
  3. 向量化(Embedding)
    • 使用 Embedding 模型(OpenAI、Ollama 等)将每个文本块变成向量
    • 向量存入向量数据库(Milvus / Chroma / Redis Vector)
  4. 查询阶段
    • 用户提问 -> 生成向量
    • 在向量库中做相似度搜索(语义检索)
    • 取出最相关的若干文档块
  5. 生成阶段
    • 将检索到的文档 + 用户问题一起发送给大模型
    • Prompt 示例:

      你是电商平台客服,请仅根据下面提供的“退货规则文档”和“订单状态数据”回答用户问题。如无法从文档中得到答案,请明确告诉用户无法确定。

在 Spring 生态中,可以利用 Spring AI 来简化这一流程:

  • 配置 LLM(OpenAI / 其他供应商)
  • 配置向量存储(Redis、Milvus 等)
  • 配置 RAG Chain/Workflow

3. 实时业务数据融合

RAG 只适合相对稳定的“知识”。对于订单状态这种实时数据,应当:

  1. 在后端服务中:
    • 先根据用户 ID / 订单号,用 MyBatis / JPA 从数据库查询实时订单状态
    • 结果结构化,如 JSON:
{
  "orderId": "202403240001",
  "status": "DELIVERING",
  "canRefund": true,
  "remainRefundDays": 3
}
  1. 在向量检索完成后,将“文档知识 + 实时订单状态”一起作为上下文传入模型:

文档片段:...

订单状态:{"status": "DELIVERING", "canRefund": true, ...}

这样 AI 回答的不只是“规则”,还知道这个用户“此刻能不能退货”。

4. 减少 AI 幻觉的手段

  1. 设置检索阈值
    • 如果检索到的文档相似度低于阈值,直接告诉用户“知识库中没有找到明确答案”。
  2. Prompt 约束
    • 明确要求模型“不知道就说不知道”。
  3. 结果可解释
    • 在回答中附带引用的规则条款,或者展示来源文档标题
  4. 规则校验
    • 对模型输出进行二次校验(金额是否在合理范围、时间是否符合规则),不通过则重新生成或人工兜底。

五、监控与链路追踪:如何查“哪里慢了”

1. 指标(Metrics)

采用 Micrometer + Prometheus + Grafana:

  • 在代码中对关键接口打指标:
    • QPS(请求次数)
    • RT(响应时间)
    • 错误率
  • Prometheus 定时拉取指标
  • Grafana 用图表展示:
    • 订单创建接口平均耗时
    • Kafka 消费延时

这个层面主要是“宏观观测”。

2. 日志(Logging)

  • 使用 SLF4J + Logback 统一日志接口
  • 输出结构化日志(JSON),包含:
    • traceId、spanId
    • userId
    • 请求路径、参数摘要
  • 日志送入 ELK:
    • Elasticsearch 存储
    • Kibana 可视化检索

3. 链路追踪(Tracing)

使用 Spring Cloud Sleuth + Zipkin / Jaeger:

  • 网关收到请求时生成 traceId
  • Sleuth 自动在 HTTP header 中透传 traceId
  • Feign 调用、RestTemplate 调用、Kafka 消息都会自动携带这个 trace 信息(需要正确配置)
  • 每个服务会打出自己的 span:
    • 订单服务 createOrder
    • 支付服务 callThirdPartyPay
    • 风控服务 checkRisk

在 Zipkin / Jaeger UI 中,可以看到一条完整的时序图:

  • 哪个 span 耗时最长 → 初步定位问题服务
  • 是外部接口慢还是内部 DB 慢 → 结合日志进一步排查

六、小结:从电商到 AI,一条完整学习路径

  1. 基础 Java & Web
    • Java SE 8/11/17,集合、多线程、JVM 基础
    • Spring Boot + Spring MVC 写 REST 接口
  2. 数据访问与缓存
    • MyBatis / JPA / Spring Data
    • Redis 缓存、分布式锁
  3. 消息与微服务
    • Kafka / RabbitMQ + Spring Cloud(Gateway、OpenFeign)
    • 服务注册发现(Eureka / Consul)、熔断限流(Resilience4j)
  4. 高并发场景
    • 秒杀、库存、幂等、分布式 ID
  5. 监控运维
    • Prometheus + Grafana + ELK + Zipkin / Jaeger
  6. AI 与 RAG
    • Spring AI、向量数据库、语义检索
    • 企业文档问答、智能客服、Agentic RAG

把这些知识结合具体业务场景去理解和实践,你在大厂 Java 面试里就不会像小Y那样“说得云里雾里”,而是可以清晰讲出“场景-方案-优缺点-落地细节”。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐