大厂Java面试:Spring Boot + Redis/Kafka + Spring Cloud + JVM + RAG/向量检索(小Y翻车实录)
故事背景
地点:某互联网大厂视频内容社区(UGC + AIGC 辅助创作)事业部。
岗位:Java后端/微服务工程师。
面试官(严肃):
"我们做的是内容社区:视频上传、转码、推荐、评论、弹幕、举报审核,还有 AIGC 智能客服与创作助手。你简历里写了 Spring Boot、Redis、Kafka、K8s、还有 Spring AI + RAG。我们按业务链路聊,三轮。"
候选人小Y(搞笑且有点水):
"好嘞,我最擅长......把复杂问题讲简单(讲不明白)。"
第一轮(基础链路):上传-发布-阅读的核心服务怎么搭?(4题)
Q1:如果我们用 Spring Boot + Spring MVC 做"视频发布服务",你会怎么分层?Controller/Service/DAO 各干啥?
小Y:
"Controller 接请求,Service 写业务,DAO 查数据库。基本就......三板斧。"
面试官:
"嗯,至少没把 DAO 写进 Controller 里。那我们继续。"
Q2:发布视频后会产生一堆事件(转码、审核、推送给粉丝、搜索索引),你会选 Kafka 还是 RabbitMQ?为什么?
小Y:
"我一般都用 Kafka,因为......大厂都用。RabbitMQ 也行吧,主要看领导喜欢哪个。"
面试官(眉头一皱):
"理由太'领导驱动'了。给你个机会,补充下吞吐、顺序、回放这些差异。"
小Y:
"Kafka 吞吐大,能回放;RabbitMQ 更像传统消息队列,功能......更全面?"
面试官:
"勉强及格。下一题。"
Q3:视频详情页是高并发热点,你会怎么用 Redis + Spring Cache 做缓存?如何解决缓存穿透、击穿、雪崩?
小Y:
"我就加个 @Cacheable。穿透就......加布隆过滤器?击穿就加锁,雪崩就加随机过期。差不多。"
面试官:
"回答方向对。你知道布隆过滤器误判怎么处理吗?"
小Y:
"误判......那就当它没判错(开玩笑)。其实可以回源数据库再确认。"
面试官:
"还行,知道兜底回源。"
Q4:你说熟 JVM。线上视频发布服务突然 Full GC 飙升,你会怎么定位?
小Y:
"先重启试试......(小声)再看 GC 日志?jstack?jmap?反正工具都能用上。"
面试官:
"重启不算定位。说一条你最常用的链路:从现象到结论。"
小Y:
"嗯......看 GC 日志确认是 Old GC 还是元空间,配合 heap dump 看大对象;再看是不是缓存没上限导致内存涨。"
面试官:
"这句像工程师了。第一轮到这。"
第二轮(微服务进阶):多服务协作、容灾与可观测(5题)
Q1:我们有"发布服务、用户服务、关注服务、通知服务"。你会用 Spring Cloud + OpenFeign 怎么做服务调用?如何做超时与重试?
小Y:
"OpenFeign 写个接口就能调。超时重试......默认就行?不行就加大超时时间。"
面试官:
"默认值最危险。那如果下游抖动,你无限重试会怎样?"
小Y:
"会......更抖?"
面试官:
"对,会雪崩。继续。"
Q2:你会怎么用 Resilience4j 做熔断、限流、隔离?在"发布后通知粉丝"这个链路里,哪些地方应该降级?
小Y:
"熔断就是断开,限流就是不让进。隔离就是......分开线程池?降级的话通知失败就算了,反正粉丝自己刷也能看到。"
面试官(点头):
"通知是可降级的,核心发布不可降级。思路对。"
Q3:数据库层面:发布服务写 MySQL,评论服务也写 MySQL。你选 MyBatis 还是 JPA/Hibernate?怎么做数据库迁移?
小Y:
"我喜欢 MyBatis,SQL 看得见。迁移用 Flyway 或 Liquibase,都行。"
面试官:
"为什么评论更适合 MyBatis?发布更适合 JPA?给个例子。"
小Y:
"评论查询复杂、排序多;发布可能就是简单 CRUD......所以 JPA 省事?"
面试官:
"可以。继续。"
Q4:在 K8s 上跑服务,如何做灰度发布与回滚?CI/CD 你用过 Jenkins/GitLab CI + Docker + Kubernetes 吗?
小Y:
"我会写 Dockerfile,K8s 就 kubectl apply。灰度就是发一半 pod?回滚就是再 apply 回去。"
面试官:
"......你这叫'手工灰度'。那 readiness/liveness、HPA、滚动更新参数你了解多少?"
小Y:
"readiness 是准备好接流量,liveness 是活着;HPA 自动扩缩。参数我得查一下。"
面试官:
"至少概念是对的。"
Q5:可观测性:你会怎么用 Micrometer + Prometheus + Grafana + ELK + Jaeger/Zipkin 定位一次接口慢?
小Y:
"先看 Grafana 的 QPS、RT;然后看日志;再看链路追踪。慢的话可能是 SQL 慢或者下游慢。"
面试官:
"不错,路径清晰。第二轮结束。"
第三轮(综合实战):AIGC 智能客服 + RAG 企业知识库(4题)
Q1:现在要做"内容社区智能客服",回答用户:账号封禁原因、申诉流程、充值问题。你会怎么做 RAG(检索增强生成)?
小Y:
"把文档喂给大模型,让它自己学会。"
面试官(严肃加倍):
"'喂给模型'不是工程方案。说清楚:向量化、检索、提示拼接、回答生成。"
小Y:
"就是先把文档切块,然后 Embedding,存向量库,比如 Milvus。用户问问题就向量检索拿 topK,再拼到 prompt,让模型回答。"
面试官:
"这才像话。"
Q2:如何降低 AI 幻觉(Hallucination)?如果客服答错"封禁原因",后果很严重。
小Y:
"那就让它别胡说......加一句提示:请勿编造。"
面试官:
"提示是手段之一,但不够。你还有什么?"
小Y:
"可以让它必须引用检索到的文档片段;没有证据就回答不知道;再加人工审核?"
面试官:
"可以,这叫 grounded generation + 拒答策略。"
Q3:如果我们用 Spring AI 接入模型(OpenAI/Ollama)并做工具调用(MCP/Tool calling),你会怎么设计"查封禁记录"的工具?
小Y:
"我就写个接口给它调:/ban/info。模型想查就查。"
面试官:
"权限呢?审计呢?以及模型怎么知道参数格式?"
小Y:
"权限用 Spring Security + JWT;审计打日志进 ELK;参数格式用 JSON schema 描述给模型?"
面试官:
"对,工具描述要标准化,MCP/函数调用都要 schema。"
Q4:聊天会话要有"记忆"(用户前面说过订单号、手机号)。你会怎么做会话内存?如何避免把敏感信息发给模型?
小Y:
"把聊天记录都存 Redis,然后每次全发给模型。"
面试官:
"......那你等着数据合规找你。你怎么改?"
小Y:
"做摘要记忆,只保留必要字段;敏感信息脱敏/加密;权限校验后再决定能不能放进 prompt。必要时本地检索,不把原文发给模型。"
面试官:
"终于像大厂做法了。今天面试到这,你回去等通知。"
参考答案与学习笔记(按业务链路串起来)
下面把面试中的问题,按"内容社区(UGC)+ AIGC 智能客服"的业务主线,给出可落地的参考答案。适合小白按图索骥。
第一轮答案:单体到高并发基础
1)Spring Boot + Spring MVC 分层怎么做?
典型三层:
- Controller(接口层) :
- 参数校验(JSR-303)、鉴权(交给 Spring Security)、DTO 转换
- 不写业务规则、不直接操作数据库
- Service(业务层) :
- 事务边界(
@Transactional) - 组合多个 DAO/Client
- 业务规则:发布状态机、风控校验、幂等
- 事务边界(
- DAO/Repository(数据访问层) :
- MyBatis Mapper 或 JPA Repository
- 只做数据读写,不掺业务
加分点:
- 复杂对象转换用 MapStruct
- 通用校验/异常用
@ControllerAdvice
2)发布事件:Kafka vs RabbitMQ 怎么选?
在"发布视频 → 转码/审核/推送/索引"这种事件驱动链路里:
- Kafka 更适合:
- 高吞吐、水平扩展强
- 可回放(consumer offset 可控),适合重放"发布事件"做补偿
- 分区内有序(按
videoId做 key 保证同一视频事件有序)
- RabbitMQ 更适合:
- 低延迟、路由模型灵活(topic/direct/fanout)
- 对复杂投递语义、死信队列(DLQ)等支持更"开箱即用"
工程建议:
- 事件总线(发布/审核/索引)走 Kafka
- 需要强路由或小规模可靠投递(比如后台运营通知)可用 RabbitMQ
3)Redis 缓存 + 三大问题
以"视频详情页"缓存为例:
- Spring Cache :
@Cacheable(cacheNames="video", key="#videoId")- 热点更新用
@CachePut或手动cache.evict+ 异步预热
缓存穿透(请求不存在的数据):
- 布隆过滤器(Bloom Filter)拦截不存在的
videoId - 或缓存空值(短 TTL)
- 误判处理:Bloom 说"可能存在"就回源 DB 再确认
缓存击穿(热点 key 过期瞬间被打爆):
- 互斥锁:Redis
SETNX/Redisson Lock 控制单线程回源 - 热点永不过期 + 异步刷新(逻辑过期)
缓存雪崩(大量 key 同时过期):
- TTL 随机化
- 分批预热
- 多级缓存(Caffeine 本地 + Redis 分布式)
4)Full GC 飙升定位思路(JVM)
从现象到结论的常用链路:
- 先确认指标:Old Gen 使用率、Full GC 次数/耗时(Prometheus/JMX)
- 开/查 GC 日志(Java 11/17 用
-Xlog:gc*)看:- 是分配速率过高?晋升失败?还是元空间膨胀?
jmap -dump导出 heap dump,用 MAT/YourKit 看:- 最大对象是谁?是否集合无限增长(例如缓存 Map 未设上限)
jstack看线程是否阻塞导致堆积
典型原因:
- 大对象(视频元数据/文本列表)频繁创建
- 缓存无上限
- 日志/trace 拼接过多字符串
第二轮答案:微服务、稳定性、可观测
1)Spring Cloud + OpenFeign:超时/重试怎么配?
原则:超时要短,重试要慎重。
- Feign 设置连接/读取超时
- 重试仅用于幂等请求(GET/查询),写请求避免重试或配合幂等 token
为什么不能无限重试?
- 下游抖动时会放大流量,导致级联故障(雪崩)
2)Resilience4j:熔断/限流/隔离/降级
在"发布后通知粉丝"链路:
- 发布主链路(写库):强一致关键路径,优先保证成功
- 通知粉丝/站内信/Push:可降级
可用策略:
- 熔断(CircuitBreaker):通知服务连续失败直接快速失败
- 限流(RateLimiter):限制瞬时推送风暴
- 隔离(Bulkhead/线程池隔离):通知慢不拖垮发布线程
- 降级(fallback):落库一条"待通知任务"后异步补偿
3)MyBatis vs JPA/Hibernate + 迁移(Flyway/Liquibase)
- 评论/搜索类查询:SQL 复杂、动态条件多、性能敏感 → MyBatis 更直观
- 发布/账号等 CRUD:领域模型清晰、关联少 → JPA 能提高开发效率
数据库迁移:
- Flyway:版本化 SQL(
V1__init.sql)简单直接 - Liquibase:支持 XML/YAML/SQL,适合更复杂变更管理
连接池:优先 HikariCP(现代、性能好)
4)K8s 灰度与回滚(CI/CD)
- 滚动更新 :Deployment 配
maxSurge/maxUnavailable - 灰度 :
- 金丝雀:新版本少量 pod
- 进阶:服务网格/Ingress 按比例分流
- 回滚 :
kubectl rollout undo deployment/... - 健康检查 :
- readiness:决定是否接流量
- liveness:决定是否重启
- 弹性伸缩:HPA 基于 CPU/自定义指标(QPS/延迟)
5)可观测:Micrometer/Prometheus/Grafana + ELK + Jaeger
定位慢接口的"黄金三板斧":
- 指标(Metrics) :
- Grafana 看 P95/P99 延迟、错误率、饱和度
- 日志(Logs) :
- ELK 定位异常堆栈、慢 SQL 日志
- 链路(Tracing) :
- Jaeger/Zipkin 找到耗时最大的 span(DB/下游/序列化)
第三轮答案:AIGC 智能客服(RAG、工具调用、合规)
1)RAG 端到端怎么做?
以"封禁/申诉/充值规则"知识库为例:
- 文档加载:FAQ、工单规范、规则文档(PDF/HTML/数据库)
- 切分(chunking):按段落/标题切块,保留来源元数据
- 向量化(Embedding):OpenAI/Ollama embedding 模型
- 向量库:Milvus/Chroma/Redis Vector
- 检索:相似度 topK + 过滤(按业务线/国家/时间版本)
- 提示填充(prompt stuffing):把检索片段作为"证据"注入 prompt
- 生成:LLM 输出结构化回答(含引用)
2)如何降低幻觉(Hallucination)?
组合拳:
- Grounding:必须基于检索证据回答,输出引用片段/链接
- 拒答策略:检索不到就回答"不确定 + 建议转人工"
- 结构化输出:JSON schema/固定模板,减少自由发挥
- 人审/抽检:高风险问题(封禁/支付)走人工复核
- 监控与回放:记录问答与证据,用于追责与优化
3)Spring AI + MCP/工具调用:如何设计"查封禁记录"工具?
工具接口示例(受控):
getBanInfo(userId):只返回必要字段- schema 描述参数与返回结构(便于模型正确调用)
安全与审计:
- Spring Security + JWT/OAuth2:鉴权
- RBAC:只有客服/用户本人可查
- 审计日志:谁在什么时间查了谁(落 ES/日志系统)
- 数据最小化:返回原因码 + 可展示文案,不返回内部风控细节
4)会话内存与隐私合规怎么做?
- 会话存储:Redis 保存 session state(带 TTL)
- 摘要记忆:把多轮对话压缩成摘要,只保留关键槽位(订单号、问题类型)
- 敏感信息处理 :
- 脱敏(手机号、身份证)
- 加密存储(必要时)
- prompt 注入前做敏感字段过滤
- 分层策略 :
- 不把原始 PII 发给模型
- 能本地查询就本地查,给模型"结果摘要"
结尾
这场面试,小Y 的特点很明显:
- 基础题能答个方向;
- 一到"工程细节 + 风险控制 + 量化指标",就开始"领导喜欢哪个"。
如果你把文末答案真正做成自己的项目实践,下次面试官夸的就不只是"方向对",而是"你来带一个子系统"。