大厂Java面试实战:Spring Boot微服务、Redis缓存、Kafka消息队列与Spring AI RAG
故事背景
面试地点:某互联网大厂(电商 + 内容社区 + AIGC 智能客服一体化业务)。
角色:
- 面试官(M):严肃、节奏快、喜欢追问原理与线上落地。
- 候选人小Y(Y):气氛担当的"水货程序员",简单题能答,难题开始"凭感觉"。
规则:一共 3轮 ,每轮 3-5个问题,问题围绕同一业务链路逐步加深。
第一轮:电商下单链路(Java/JVM + Spring Boot + 数据库与连接池)
Q1:你负责的电商"创建订单"接口,Spring MVC里从请求到落库,大致流程是什么?
M:别背概念,说清楚线程模型、参数绑定、事务、异常怎么回。
Y :呃......就是 Controller 接到请求,调用 Service,然后 DAO/MyBatis 写数据库。事务就 @Transactional 一加,异常就......统一返回一个 JSON。
M :还行,至少没把 DAO 写在 Controller 里。那你说说线程是谁在用?
Y:线程是......Tomcat给的?
M:对。继续。
Q2:订单库用 MyBatis + HikariCP。为什么大厂更常用 HikariCP,不太爱 C3P0?
Y:HikariCP快!据说是"光"一样快。
M:回答像广告词。你说说"快"体现在哪?
Y:嗯......它比较轻量,锁少?
M:勉强算点到点上。
Q3:你怎么排查线上"接口偶发慢",怀疑是 JVM 停顿或GC导致?
Y:我会先看日志......然后看看是不是SQL慢。
M :我问的是 JVM停顿。你给我一个可落地的排查链路。
Y:那我......加大内存?
M:(沉默两秒)你继续说。
Y :看 jstat?然后 jmap?
M:至少工具名说对了。
Q4:你们库表变更怎么做?Flyway/Liquibase 用过吗?
Y :用过 Flyway,写 SQL 脚本编号,比如 V1__init.sql。
M:不错。那多人协作冲突怎么办?
Y:就......沟通一下,别冲突。
M:行,第一轮到这。
第二轮:高并发与异步解耦(Redis缓存 + Kafka + 分布式追踪与监控)
Q1:内容社区"爆款商品"被大量访问,商品详情接口如何做缓存?用 Spring Cache + Redis 怎么设计 key?
Y :用 @Cacheable,key 就 productId。
M:太粗了。商品详情和"地区/用户等级/活动价"有关怎么办?
Y:那......key 里拼上地区?
M:对,继续。
Q2:缓存击穿、穿透、雪崩你分别怎么处理?
Y:
- 击穿:加锁
- 穿透:布隆过滤器
- 雪崩:随机过期时间
M:不错,这题答得像个正常人。那加锁你用什么?
Y :Redis setnx?
M:可以。
Q3:下单成功后要异步做"发券、发消息、更新推荐画像",为什么要上 Kafka?如何保证至少一次投递?
Y:Kafka吞吐高。至少一次......就是消费者消费失败就重试?
M:那重复消费呢?
Y:那就......不要重复?
M:你这回答很"哲学"。
Q4:线上出现"用户投诉下单后没收到券",你怎么用 Prometheus + Grafana + Jaeger/Zipkin 排查?
Y:Grafana 看看曲线,然后 Jaeger 看看链路。
M:你能说具体点吗?
Y:就......看错误率、延迟,然后找到某个 span 慢。
M:还行,但细节不够。
第三轮:AIGC智能客服(Spring AI + RAG + 向量库 + Agent工具调用)
业务设定:电商平台上线"智能客服",用户问:
"我这单为什么没发货?能不能退款?顺便推荐一个类似商品。"
客服需要:
- 查订单(权限校验)
- 读平台规则文档(退款/发货时效)
- 调用工具(订单服务、物流服务)
- 支持多轮对话记忆
Q1:你会如何用 Spring AI 做一个"RAG企业文档问答"?流程拆一下。
Y:就是把文档丢给模型,然后模型回答。
M:太天真。RAG 的 "R" 是什么?
Y:Retrieval?检索。
M:对。那检索用什么?
Y:用......向量库?
M:继续。
Q2:向量化(Embedding)怎么做?Milvus/Chroma/Redis Vector 你怎么选?
Y:Embedding 就是把文字变成向量。选哪个看公司喜欢哪个。
M:如果你这么回答,基本就凉了。你至少要从"规模、延迟、运维成本"说。
Y:那我选 Redis,因为我们本来就有 Redis。
M:能落地,但别忘了向量检索能力和召回质量。
Q3:智能客服最怕"AI幻觉"。你怎么降低幻觉?
Y:让它别胡说?
M:你当模型是你儿子吗?给我工程手段。
Y:加提示词?
M:提示词只是开始。
Q4:如果要做 Agent:模型根据用户问题自动调用"订单查询、物流查询、退款规则查询"工具,怎么设计"工具执行框架"和"会话内存"?
Y:用 Spring AI 的工具调用。会话内存就存 Redis。
M:可以,但你得解释清楚"何时调用工具、参数怎么约束、怎么审计"。
Y:审计......打日志?
M:......
面试收尾
M :整体来看,你基础题还行,工程化和原理深挖偏弱,尤其是消息幂等、可观测性闭环、以及 AI 这块的落地细节。今天先到这,回去等通知。
Y:好的好的,我回去就把自己"从水货升级成正品"。
文末答案详解(按业务场景+技术点,小白可学习)
说明:下方是每个问题更"标准的大厂回答",包含场景、要点与可执行做法。
第一轮答案:下单链路(Spring MVC + MyBatis/JPA + HikariCP + JVM)
A1:Spring MVC 下单接口从请求到落库流程(线程/绑定/事务/异常)
业务场景:用户点击"提交订单",请求进入订单服务。
典型链路:
- HTTP线程模型 :
- Tomcat/Jetty 使用线程池(如
http-nio)为每个请求分配工作线程。 - 线程贯穿 Controller → Service → DAO 直到响应返回(同步MVC场景)。
- Tomcat/Jetty 使用线程池(如
- DispatcherServlet :
- 通过 HandlerMapping 找到对应 Controller 方法。
- 参数解析与绑定(JSON→对象):常见是 Jackson(
MappingJackson2HttpMessageConverter)。
- 校验与鉴权 :
@Valid+ Hibernate Validator 做参数校验。- Spring Security Filter Chain 做认证鉴权(如 JWT/OAuth2)。
- 事务 :
- Service 层使用
@Transactional(基于 AOP 代理)。 - 关键:默认对 RuntimeException 回滚;受检异常需要配置
rollbackFor。
- Service 层使用
- 持久化 :
- MyBatis:执行SQL,映射ResultSet。
- JPA/Hibernate:实体状态转换、脏检查、flush。
- 统一异常处理 :
@ControllerAdvice+@ExceptionHandler将异常映射为统一错误码/错误信息。
A2:HikariCP vs C3P0(为什么大厂更爱HikariCP)
核心点:
- 性能与稳定性:HikariCP 以更少的锁和更低的开销提供更高吞吐与更低延迟。
- 配置简洁:常用参数少,默认值更合理。
- 监控友好:可暴露连接池指标(配合 Micrometer → Prometheus)。
关键配置建议(示例):
maximumPoolSize:按数据库承载能力与QPS评估connectionTimeout:避免线程长时间阻塞leakDetectionThreshold:辅助定位连接泄漏
A3:排查"偶发慢"是否JVM停顿/GC导致(可落地链路)
业务现象:少量请求RT飙升(例如从50ms到3s),但SQL并不慢。
排查步骤:
- 看现象是否全局抖动 :
- Grafana 看 P99 延迟是否同时抬升。
- 检查 GC 日志 (最有效):
- 开启 GC log(JDK11+用
-Xlog:gc*)。 - 观察 Full GC/Young GC 次数与停顿时间。
- 开启 GC log(JDK11+用
- jstat 快速确认 :
jstat -gcutil <pid> 1s 10看GC频率、老年代占用。
- jcmd/jmap/jfr 深入分析 :
jcmd <pid> GC.heap_info/GC.class_histogramjmap -dump:format=b,file=heap.hprof <pid>配合 MAT 分析内存泄漏- JFR(Java Flight Recorder)定位停顿原因(锁竞争/IO/GC)。
- 常见原因 :
- 内存泄漏导致频繁 Full GC
- 大对象分配、晋升失败
- 线程池耗尽/锁竞争造成"假慢"
A4:Flyway/Liquibase 管理表结构变更与冲突
推荐做法:
- 每次变更以增量脚本提交(不可修改已发布版本脚本)。
- 冲突处理:
- 通过脚本版本号/时间戳排序
- Code Review 把控"同一张表多分支修改"的合并
- CI阶段执行迁移:测试库先跑 Flyway,失败即阻断。
第二轮答案:高并发(Redis缓存 + Kafka + 可观测性)
A1:商品详情缓存设计(Spring Cache + Redis key设计)
业务点 :商品详情可能随 地区、用户等级、活动 变化。
Key建议:
- 基础:
product:detail:{productId} - 多维:
product:detail:{productId}:{region}:{userLevel}:{activityId}
注意:
- 维度过多会导致 key 爆炸,需要权衡:
- 把"个性化"拆成独立子缓存
- 或缓存"基础详情",价格与活动走实时/短缓存
A2:缓存击穿/穿透/雪崩
- 击穿(热点key过期) :
- 互斥锁:Redis
SET key value NX PX - 双层缓存:逻辑过期 + 异步刷新
- 互斥锁:Redis
- 穿透(查不存在) :
- 布隆过滤器(Bloom Filter)
- 缓存空对象(短TTL)
- 雪崩(大量key同一时间过期) :
- TTL加随机抖动
- 多级缓存(本地 Caffeine + Redis)
- 限流/熔断保护
A3:为什么用Kafka?如何做到"至少一次"与"幂等"
业务场景:下单后异步:发券、发站内信、更新画像。
Kafka价值:
- 削峰填谷、解耦、可回放(按偏移量重放)、高吞吐。
**至少一次(At-least-once)**关键:
- 消费端:处理成功后再提交offset(手动提交或事务性消费)。
- 失败重试:可本地重试 + 死信队列(DLQ)/重试topic。
重复消费(必须回答清楚):
- 通过幂等 保证:
- 唯一业务键(如
orderId+eventType) - 消费表/去重表(数据库唯一索引)
- Redis set去重(注意过期与内存)
- 唯一业务键(如
- 例:发券服务写
coupon_send_log,以order_id建唯一索引;重复消息插入失败即视为已处理。
A4:Prometheus+Grafana+Jaeger/Zipkin 排查"没收到券"
排查闭环:
- 指标层(Prometheus) :
coupon_send_success_total、coupon_send_fail_total- Kafka consumer lag
- 接口P99、错误率
- 日志层(ELK) :
- 以
traceId/orderId搜索跨服务日志
- 以
- 链路追踪(Jaeger/Zipkin) :
- 看下单请求是否产生"发券事件"span
- 看消息生产是否成功(producer ack)
- 看消费端 span 是否存在、是否报错、耗时是否异常
- 结论定位 :
- 生产失败?(Kafka不可用/超时)
- 消费积压?(lag高)
- 消费报错?(依赖服务/DB异常)
- 幂等挡住了?(重复订单/重复事件)
第三轮答案:AIGC智能客服(Spring AI + RAG + Agent)
A1:Spring AI 实现RAG企业文档问答(完整流程)
目标:回答必须基于企业规则文档,减少幻觉。
流程:
- 文档加载:PDF/HTML/数据库(Spring AI DocumentReader)。
- 切分(Chunking):按段落/标题切块,控制chunk大小与重叠。
- 向量化(Embedding):调用 Embedding 模型(OpenAI/Ollama等)将chunk转向量。
- 入库(Vector Store):Milvus/Chroma/Redis 向量索引保存向量+元数据。
- 检索(Retrieval):用户问题 → 向量化 → 相似度召回 topK chunks。
- 提示填充(Prompt Stuffing):把召回的内容作为"证据"塞进提示词。
- 生成回答(LLM):要求引用依据、无法确定就说不知道。
A2:Milvus/Chroma/Redis Vector 如何选型(规模/延迟/运维)
- Redis Vector :
- 优点:公司已有Redis,运维成本低,延迟低,适合中小规模与快速落地。
- 风险:向量能力、过滤与复杂检索能力相对受限(取决于版本与模块)。
- Milvus :
- 优点:面向大规模向量检索,能力完整(索引类型、扩展性强)。
- 成本:独立集群与运维复杂度更高。
- Chroma :
- 优点:上手快,适合原型或中小规模。
- 成本:生产化与高可用能力需评估。
选型口诀:小而快 → Redis/Chroma;大而强 → Milvus。
A3:降低AI幻觉(工程手段)
关键组合拳:
- RAG + 引用约束:回答必须基于检索到的证据;无证据则拒答。
- 更强的系统提示 :
- 明确"只依据上下文""不确定就说不知道"。
- 结构化输出 :
- JSON Schema/函数调用(tool calling)约束格式,减少自由发挥。
- 检索质量提升 :
- chunk切分合理、topK、重排序(rerank)、元数据过滤(按业务线/版本)。
- 在线评测与兜底 :
- 置信度阈值:低置信度转人工
- 敏感场景(退款/医疗/金融)增加规则引擎校验
A4:Agent工具调用框架 + 会话内存(订单/物流/规则查询)
目标 :模型不是"编答案",而是先查数据再回答。
设计要点:
- 工具定义标准化 :
- 每个工具定义:名称、用途、入参Schema、出参Schema、权限要求。
- 例如:
getOrderStatus(orderId)、getLogistics(traceNo)。
- 何时调用工具 :
- 通过 function/tool calling 让模型在需要事实数据时发起调用。
- 参数约束与安全 :
- 对
orderId等参数做校验 - 强制鉴权:只能查当前用户的订单(Spring Security)
- 防止提示注入:工具调用前后做内容过滤与策略校验
- 对
- 会话内存(Chat Memory) :
- 存用户画像、上文问题、已确认的订单号等
- 可用 Redis 存短期会话,设置TTL;长期用数据库
- 审计与可观测性 :
- 每次工具调用记录:用户、入参、结果摘要、耗时、traceId
- Prometheus统计工具成功率/失败率/延迟
你该如何把小Y"升级成正品"(学习路线)
- 把 Kafka幂等/重试/死信 写成一套模板
- 把 Prometheus指标 + traceId贯通日志 在demo里跑通
- 用 Spring AI 做一个最小可用RAG:文档→向量库→检索→回答→拒答策略
(完)