大厂Java面试实录:Spring Boot/WebFlux、JVM调优、Redis/Kafka、Spring Cloud、Prometheus/ELK 与 RAG/Agent 追问
场景:某互联网大厂「内容社区 + UGC + AIGC 创作」业务,一次 Java 后端面试。
角色:
- 面试官(严肃):追问细、喜欢从业务到技术逐层加压。
- 小Y(搞笑水货程序员):简单题能答,复杂题开始"玄学编程"。
第一轮(基础能力):从UGC发帖接口开始
Q1(业务引入):UGC发帖接口你怎么设计?
面试官:我们是内容社区,用户发帖带文字+图片,可能还要触发审核、打标签、推送。你会怎么拆接口?
小Y :就一个 POST /posts 呗......参数 content、images,然后我 postService.save() 一把梭。
面试官:那审核、打标签、推送都在一个事务里?
小Y :嗯......要不我加个 @Transactional?这样肯定稳。
面试官:至少你知道事务能兜底,但这会把一个"写库操作"绑上很多"异步链路"。我们先往下。
Q2(Spring MVC基础):你会怎么做参数校验与统一异常?
面试官:发帖接口怎么做参数校验,怎么让前端拿到统一错误码?
小Y :@Valid + @RequestBody,然后写个 @ControllerAdvice 统一返回就行。
面试官:可以。那你会怎么区分"业务异常"和"系统异常"?
小Y :业务异常我就 throw new RuntimeException("业务不对")......系统异常也是 RuntimeException......反正都能被 Advice 抓住。
面试官:方向对了,但异常分层要更规范。继续。
Q3(JVM基础):线上接口偶发超时,你第一时间看什么?
面试官 :/posts 偶发超时,RT 从 50ms 飙到 5s。你先看 JVM 哪些指标?
小Y :先看 CPU......再看内存......然后 jstack 一下?
面试官:还行。那 GC 你会重点看什么?
小Y:看......是不是 Full GC 了。Full GC 就很慢。
面试官:对,至少抓住了重点。
Q4(数据库与连接池):写库慢,你怀疑连接池,你会怎么定位?
面试官:写库慢,你怎么判断是 SQL 慢还是连接池拿连接慢?
小Y:我看一下日志......SQL 打印出来......如果慢就加索引。
面试官:连接池呢?HikariCP 你会看哪些配置/指标?
小Y :呃......maximumPoolSize?我一般设 200,越大越好。
面试官:200 不一定更好,但你至少知道从池大小入手。
第二轮(进阶链路):从同步发帖到异步审核与消息队列
Q1(拆分与一致性):审核、打标签、推送你会怎么做异步?
面试官:发帖成功后要触发: 1)内容安全审核 2)NLP 打标签 3)给粉丝推送 你怎么拆?
小Y :我在 save() 后面开三个线程 new Thread() 跑就行。
面试官:线上你敢这么干?如果进程重启线程就没了。
小Y:那......我用线程池!
面试官:线程池也不解决可靠性。那你会用什么?
小Y:用 Kafka/RabbitMQ 发消息!
面试官:这就对了。那你怎么保证"发帖入库"和"发消息"一致?
小Y:加个大事务,把 Kafka 也一起事务?
面试官:......Kafka 事务不是这么用的。继续往下问。
Q2(Kafka/RabbitMQ):你怎么设计消息幂等与重复消费处理?
面试官:审核消息可能重复投递,消费者如何做到幂等?
小Y:我在消费的时候先查数据库,如果处理过就不处理。
面试官:用什么字段标识"处理过"?
小Y :就......加个 status,0 未处理 1 已处理。
面试官:基本思路可以。但高并发下会有竞态,你怎么避免?
小Y :加锁!synchronized!
面试官:......跨 JVM 你打算 synchronized 谁?
小Y:那我用 Redis 锁!
面试官:好,至少你知道分布式锁这个工具。
Q3(缓存与热点):帖子详情是热点接口,你怎么用 Redis 缓存?
面试官 :GET /posts/{id} QPS 很高,怎么做缓存?
小Y:先查 Redis,没有就查 MySQL,再 set 到 Redis。
面试官:缓存穿透、击穿、雪崩怎么处理?
小Y:穿透就......加布隆过滤器?击穿......加锁?雪崩......加随机过期时间?
面试官:回答得不错,这几个关键词都对。
Q4(微服务治理):审核服务偶发超时,你怎么做降级与重试?
面试官:审核服务是独立微服务,调用用 OpenFeign。偶发超时你怎么处理?
小Y:我把超时设置大一点......比如 30 秒。
面试官:那上游线程都被占满。更好的?
小Y:那就重试!一直重试到成功。
面试官:重试会放大流量雪崩。你知道 Resilience4j 吗?
小Y:知道!就是......断路器那个......我用过,但名字配置总记不住。
面试官:至少方向对:超时、限流、隔离、断路器、重试要组合使用。
第三轮(架构综合):可观测性 + 安全 + AIGC/RAG 追问
Q1(可观测性):一次"发帖→审核→打标签→推送"链路你怎么监控?
面试官:我们要求能定位:哪一段慢、哪一段报错、是否消息堆积。你会怎么做可观测性?
小Y:打日志!Logback!
面试官:只靠日志不够。指标、链路追踪呢?
小Y:Prometheus + Grafana 看指标,Jaeger/Zipkin 看链路。
面试官:Micrometer 用过吗?
小Y:用过......就是加依赖就有指标了那种。
面试官:行,至少知道组件栈。
Q2(安全):用户登录后发帖,怎么做鉴权与权限控制?
面试官:你会怎么做登录态?JWT 还是 Session?
小Y:JWT!因为无状态,最先进。
面试官:那 JWT 如何安全失效?比如用户被封禁后立刻不能发帖。
小Y:呃......JWT 不是不好失效吗......那就让它过期快一点?
面试官:这是典型问题。那 OAuth2/Keycloak 了解吗?
小Y:听过......Keycloak 是个登录的东西。
面试官:好,我们继续 AI。
Q3(AIGC/RAG):我们要做"企业级内容助手",从社区规则和历史帖子里回答问题,你怎么做RAG?
面试官:产品要一个"发帖助手":用户输入一句话,系统从社区规则、历史优质帖子里检索,再生成一段建议文案。你怎么落地?
小Y:用 ChatGPT......把所有文档丢给它,它就会回答。
面试官:文档 10GB 呢?
小Y:那就......分批丢?
面试官:你知道向量化、Embedding、向量数据库吗?
小Y:知道!向量就是......一串数字。数据库用 Milvus/Chroma/Redis 都行。
面试官:检索怎么做?
小Y:语义检索......topK......然后把结果拼进 prompt。
面试官:不错。那怎么降低幻觉?
小Y:让它"不要胡说八道"。
面试官:......我们希望更工程化:引用证据、回答约束、评估与回退。
Q4(Agent与工具调用):如果让AI自动"查违规词库、查用户历史、生成审核结论",你怎么设计工具执行框架?
面试官:你会让模型怎么调用内部服务?如何标准化?
小Y:我让它输出 JSON,然后我解析 JSON 调接口。
面试官:模型输出不稳定怎么办?
小Y:那我......多试几次?温度调低点?
面试官:MCP(模型上下文协议)/工具调用标准化了解吗?
小Y:呃......MCP 我看过文章,感觉挺厉害,但我还没来得及"深入实践"。
面试官:好的。
面试收尾
面试官:今天先到这。整体看你基础还行,关键词也能对上,但在一致性、可靠性、AI工程化落地上需要更系统的实战。你回去等通知,有结果我们 HR 会联系你。
小Y:好的老师!我回去就把 Kafka 事务和 MCP 都"深入一下"。
文末答案详解(按业务链路讲清楚)
目标:让小白能把"内容社区发帖 + 异步链路 + 可观测性 + 安全 + RAG/Agent"串起来。
第一轮答案详解:发帖接口与基础功
1)UGC 发帖接口如何设计(Spring Boot + 分层)
业务目标:用户发帖快速返回;审核/打标签/推送不阻塞用户。
推荐设计:
POST /posts:只做核心写入(帖子基础信息落库、返回 postId)。- 非核心动作走异步事件:
PostCreatedEvent(Kafka/RabbitMQ/Pulsar 皆可)- 消费者分别做审核、标签、推送
技术要点:
- Spring MVC:Controller → Service → Repository/Mapper
- DTO/VO 分离:入参
CreatePostRequest,出参CreatePostResponse(postId) - 上传图片:可先走对象存储(OSS/S3),接口只保存 URL(避免大文件阻塞应用线程)
2)参数校验与统一异常(Jakarta Validation + ControllerAdvice)
做法:
- 入参校验:
@Valid @RequestBody+ 字段上@NotBlank @Size ... - 统一异常:
@RestControllerAdvice@ExceptionHandler(MethodArgumentNotValidException.class)返回统一错误码
异常分层建议:
BizException:可预期业务错误(如"内容为空""用户被封禁")SysException:不可预期系统错误(NPE、下游超时)- 返回结构示例:
{code, message, traceId}
3)线上超时:JVM 与线程维度如何排查
先看现象属于哪类:
- CPU 飙高:可能死循环、序列化/加密过重、热点锁竞争
- RT 偶发飙高:常见是 STW GC、下游抖动、线程池/连接池耗尽
JVM/GC 要看:
- GC 次数与耗时(Young/Old/Full)
- Old 区占用是否持续上升(内存泄漏风险)
- 线程状态(
jstack看 BLOCKED、WAITING、RUNNABLE)
常用工具:
- JDK:
jcmd,jstack,jmap(线上谨慎), GC log - APM:New Relic/自建链路追踪
4)写库慢:区分 SQL 慢 vs 连接池慢(HikariCP)
判断路径:
- 看 SQL 执行时间(MyBatis/JPA 日志、慢查询日志)
- 看连接池等待时间(Hikari 指标:等待队列、active/idle)
HikariCP 关键点:
maximumPoolSize不是越大越好:受 DB 最大连接数、CPU、事务时间影响- 观察:
- 连接获取耗时(pool wait)
- active connections 是否长期满
- 优化:缩短事务、分页、加索引、减少 N+1
第二轮答案详解:异步、消息、缓存、治理
1)为什么要用 MQ 而不是 new Thread
业务目标:可靠触发审核/标签/推送,且可削峰。
MQ 价值:
- 解耦:发帖服务不关心审核细节
- 削峰:Kafka/RabbitMQ 缓冲流量
- 可靠性:消费失败可重试/死信队列
2)"入库 + 发消息"一致性怎么做(Outbox / 事务消息)
推荐:Outbox Pattern(通用、易落地)
- 同一个本地事务内: 1)写
posts表 2)写outbox_event表(事件内容、状态) - 后台 Job/CDC(Debezium)把 outbox 事件投递到 Kafka
- 投递成功再把 outbox 状态置为已发送
好处:避免"库写成功但消息没发出去"或反过来。
3)消息幂等与重复消费
核心:MQ 至少一次投递(at-least-once)很常见,消费者必须幂等。
常用做法:
- 每条消息带唯一键:
eventId/messageId - 消费侧幂等表:
processed_event(event_id, processed_time)- 插入成功才执行业务
- 插入失败(唯一键冲突)说明处理过,直接 ack
竞态避免:
- 使用 DB 唯一约束比
synchronized更可靠 - Redis 锁适合某些场景,但要考虑过期/续期/可重入等复杂度
4)Redis 缓存:穿透/击穿/雪崩
- 穿透 :请求不存在的 postId
- 缓存空值(短 TTL)
- 布隆过滤器(Guava/RedisBloom)
- 击穿 :热点 key 过期瞬间
- 互斥锁/SingleFlight
- 逻辑过期(返回旧值 + 后台刷新)
- 雪崩 :大量 key 同时过期
- TTL 加随机
- 多级缓存(Caffeine + Redis)
- 限流/熔断
Spring 可用:Spring Cache + Caffeine/Redis 实现本地+分布式缓存。
5)微服务治理:OpenFeign + Resilience4j
不要:一味调大超时、无限重试。
推荐组合:
- 超时:合理设置 connect/read timeout
- 重试:只对幂等请求;限制次数;指数退避
- 断路器:错误率/慢调用触发,快速失败保护系统
- 隔离:线程池/信号量隔离,避免拖垮主线程池
- 降级:返回"审核中"状态或进入人工队列
第三轮答案详解:可观测性 + 安全 + RAG/Agent
1)可观测性三件套:Logs/Metrics/Traces
日志(ELK):
- Logback/Log4j2 + JSON 格式
- 统一字段:
traceId、userId、postId
指标(Prometheus + Grafana):
- QPS、RT、错误率
- 线程池队列长度、DB 连接池 active/idle
- Kafka lag(消费滞后)
链路追踪(Jaeger/Zipkin):
- Spring Cloud Sleuth(或 OpenTelemetry)采集 span
- 定位"发帖→发消息→审核→回写状态"哪段慢
Micrometer 负责把应用指标标准化暴露给 Prometheus。
2)JWT/Session 与"立刻失效"问题
JWT 优点 :无状态、易扩展。 难点:签发后在过期前很难强制失效。
工程解法:
- 短 TTL + Refresh Token
- 引入 token 黑名单/版本号:
- Redis 存
userTokenVersion - JWT 中带 version,校验不一致立刻失效
- Redis 存
- 统一认证中心:OAuth2 + Keycloak(适合多端、多系统 SSO)
Spring Security 可实现:
- 鉴权过滤器校验 JWT
- 方法级权限:
@PreAuthorize
3)RAG 落地:向量化 + 语义检索 + Prompt 填充
业务目标:从"社区规则、历史优质帖子、FAQ"中找到证据,再生成建议文案。
典型流程:
- 文档加载(规则/帖子/运营文档)→ 分段(chunking)
- Embedding 向量化(OpenAI/Ollama 等)
- 向量入库(Milvus/Chroma/Redis Vector)
- Query 来了:Embedding(query) → TopK 语义检索
- Prompt 填充:把检索结果作为 context,要求"基于证据回答"
降低幻觉(工程化,不靠"请别胡说"):
- 让模型输出引用片段/来源
- 设定回答约束:无证据则回答"不确定/需要补充信息"
- 加评估:检索命中率、答案一致性
- 关键场景回退:走模板回复或人工
Spring AI 可用来串:Embedding、VectorStore、ChatModel、Retriever。
4)Agent + 工具调用框架:让模型"会用内部系统"
业务例子:自动审核助手需要:
- 查询违规词库服务
- 查询用户历史违规次数
- 调用内容安全模型
- 生成审核结论并落库
关键点:
- 工具(Tool)需要标准化描述:name/description/JSON schema
- 工具执行要可观测:每次调用有 traceId、耗时、入参脱敏
- 输出不稳定要防御:
- 严格 JSON schema 校验
- 重试要有限制,失败要降级(人工队列)
MCP(模型上下文协议)价值:
- 统一"模型 ↔ 工具/资源"的调用协议
- 让扩展能力更标准化(更像插件体系)
你可以带走的"面试回答模板"(一句话版)
- 发帖:核心写入同步,审核/标签/推送异步事件化
- 一致性:Outbox/CDC 保证库与消息一致
- 幂等:eventId + 幂等表唯一约束
- 缓存:穿透/击穿/雪崩三件套
- 治理:超时+重试+断路器+隔离+降级(Resilience4j)
- 可观测:ELK + Prometheus/Grafana + Jaeger/Zipkin(Micrometer/OpenTelemetry)
- 安全:Spring Security + JWT(短 TTL + 版本号/黑名单)或 OAuth2/Keycloak
- RAG:chunk → embedding → vector DB → topK → prompt
- Agent:工具 schema + 执行可观测 + 失败降级,MCP 做标准化