Spring Boot + Kafka + Redis + MyBatis + Kubernetes + RAG:互联网大厂Java面试三轮连环问(含答案详解)
《Spring Boot + Kafka + Redis + MyBatis + Kubernetes + RAG:互联网大厂Java面试三轮连环问(含答案详解)》
角色设定
- 面试官(M):语气严肃、追问到位。
- 小Y(Y):自称“全栈架构师”,简单题能答,复杂题开始“凭感觉”。
业务背景(贯穿三轮)
你要面试的岗位负责一个内容社区与UGC平台:
- 用户发帖/发视频(UGC),需要上传、转码、审核、推荐。
- 平台引入 AIGC:用户可用 AI 生成文案/封面;平台也用 AI 做内容审核与问答客服。
- 系统为微服务架构:内容服务、审核服务、推荐服务、搜索服务、用户服务等。
第一轮:从“能跑起来”到“跑得稳”(Java/JVM + Spring Boot + Web)
Q1:你用 Spring Boot 做内容发布接口 /posts,如何设计参数校验、异常处理与统一返回?
M: 说说你会怎么做,别光说“加个注解”。
Y: 这个简单!我一般就 @RestController 然后 @Valid,不行就 try-catch 一把梭……统一返回我就 new Result()。
M: @Valid 和全局异常处理能说具体点吗?
Y: 嗯……大概就是 @ControllerAdvice,然后把异常转成 JSON……
M: 还行。下一题。
Q2:Spring MVC 与 Spring WebFlux 的差异?什么场景下你会选 WebFlux?
M: 你们视频上传、转码回调、审核回调很多,怎么选?
Y: WebFlux 就是更快,因为是响应式嘛……适合高并发。
M: “更快”不严谨。你说下线程模型?背压?
Y: 线程模型……嗯……反正不是一个请求一个线程。背压就是……别把人压死?
M: ……
Q3:JVM 内存结构、GC 选择与线上 OOM 排查思路(Java 8/11/17)
M: 内容服务发布高峰期 OOM,怎么定位?你在 Java 8 和 17 的选择上有什么差异?
Y: JVM 内存就是堆、栈、方法区。OOM 就加内存……或者重启。GC 我一般用默认的。
M: 你至少要说出:堆 dump、MAT、GC 日志、以及常见 OOM 类型。
Y: 对对对,可以 dump 一下……然后用个工具看看。
M: 好,进入第二轮。
第二轮:从“单体CRUD”到“微服务链路”(DB/ORM + MQ + Cache + Resilience)
Q1:内容发布如何做到“写库 + 发审核消息”一致?(MyBatis/JPA + Kafka/RabbitMQ + 事务)
M: 你写入帖子表成功了,但 Kafka 消息没发出去,审核服务收不到怎么办?
Y: 这个我懂!加事务!数据库事务和 Kafka 事务一起提交。
M: 你确定你们 Kafka 和数据库能一个事务?
Y: 嗯……应该可以吧?要不就 try-catch 重试。
M: ……
Q2:Redis 在内容社区里怎么用?缓存穿透、击穿、雪崩怎么处理?(Redis + Caffeine + Spring Cache)
M: 帖子详情 /posts/{id},热点帖子访问量暴涨,你怎么做缓存?
Y: Redis 缓存一下就行,key 用 post:id。穿透就……加个布隆过滤器?击穿就加锁,雪崩就随机过期时间。
M: 这题答得不错。那你会用 Caffeine 吗?
Y: 会!就是本地缓存,更快。我一般 Redis + Caffeine 双写。
M: 双写一致性怎么保证?
Y: 这个……靠缘分。
Q3:微服务治理:OpenFeign + Resilience4j + 熔断限流
M: 审核服务慢了,内容发布接口被拖死,你怎么做超时、重试、熔断、隔离?
Y: Feign 配个超时,再重试几次。熔断就让它别调了。
M: 你讲下 Resilience4j 的 Bulkhead、CircuitBreaker、RateLimiter 在你业务里的组合?
Y: Bulkhead……是船舱隔离?我觉得都差不多,配置下就行。
M: ……继续。
Q4:数据库连接池与迁移:HikariCP + Flyway/Liquibase
M: 你们高峰期数据库连接暴涨,怎么设置 HikariCP?表结构迭代怎么控制?
Y: 连接池就调大点。迁移就……手工执行 SQL?
M: 好,第三轮。
第三轮:从“能用”到“可观测 + AI 落地”(K8s/监控/链路追踪 + RAG/Agent)
Q1:Kubernetes 部署内容服务:滚动发布、就绪探针、资源限制怎么配?
M: 新版本发布后错误率升高,如何快速回滚?
Y: K8s 我会用,直接 kubectl apply。回滚就再 apply 回去。
M: 探针、HPA、requests/limits 的意义?
Y: 探针就是探活;HPA 就自动扩容;limits 就限制一下别太浪。
M: 勉强过。
Q2:可观测:Micrometer + Prometheus/Grafana + ELK + Jaeger/Zipkin
M: 线上接口慢,你怎么在 10 分钟内定位是 DB 慢、下游慢还是 GC 抖动?
Y: 我会看日志,ELK 搜一下。然后……再看看 Grafana。
M: 链路追踪怎么串起来?traceId 怎么传?
Y: 这个我记得 Spring Cloud 会自动带……
M: ……
Q3:AI:用 Spring AI 做“企业文档问答客服”(RAG + 向量库 Milvus/Chroma/Redis)
M: 你们社区要做客服机器人:回答“帖子被下架原因”“申诉流程”。怎么用 RAG 降低幻觉?
Y: 这个我最近在看!RAG 就是把文档丢给模型。向量库就……存向量。幻觉就提示它别瞎说。
M: 你能说出:文档加载、切分、Embedding、语义检索、提示填充、引用来源、以及会话记忆怎么做吗?
Y: 嗯……大概就是先向量化,再搜,再拼 prompt。会话记忆……就是把聊天记录存起来。
M: 好,最后一个问题。
Q4:Agent(智能代理)+ 工具调用:让客服机器人能“查订单/查申诉状态”
M: 用户问“我昨天申诉的帖子审核到哪一步了?”机器人需要调用内部接口。你如何设计工具执行框架、防止越权与提示注入?
Y: Agent 就是让模型自己决定调哪个接口。越权的话……加鉴权。提示注入就……别让它注入?
M: 行。今天先到这。
面试收尾
M: 你基础还行,但在一致性、可观测、以及 AI 工程化落地上需要更系统的方法。我们后续会综合评估,你先回去等通知,有结果 HR 会联系你。
题目答案详解(按三轮顺序,含业务场景与技术点)
目标:让小白也能把“为什么这么做、怎么落地、常见坑”学下来。
第一轮答案详解
1)Spring Boot 接口:校验、异常、统一返回
业务场景:内容发布 /posts 入参包含 title、content、mediaUrls、categoryId,需要校验长度/非空/格式;错误要统一给前端。
推荐做法:
- DTO + Bean Validation:
@NotBlank @Size @Pattern,控制器参数@Valid或@Validated。 - 全局异常:
@RestControllerAdvice+@ExceptionHandler处理:MethodArgumentNotValidException(Body 校验失败)ConstraintViolationException(Query/Path 校验失败)- 业务异常(自定义
BizException)
- 统一返回结构:
code/message/data/traceId。 - 日志:在异常处理器里记录必要上下文,避免吞异常。
关键点:不要在 controller 里 try-catch 到处写;用全局异常更可维护。
2)Spring MVC vs WebFlux:什么时候用 WebFlux
业务场景:
- 视频上传后会有转码回调、审核回调;同时还要调用对象存储、审核服务等外部 IO。
差异核心:
- Spring MVC:Servlet 模型,典型“一个请求一个线程”,适合传统同步阻塞 IO(JDBC)。
- Spring WebFlux:基于 Reactor 的响应式,事件循环/少量线程处理大量连接,适合高并发 + 大量非阻塞 IO(如 WebClient、R2DBC、响应式 Redis)。
- 背压(Backpressure):下游处理不过来时,上游能减速,避免内存堆积(响应式流规范的一部分)。
选型建议:
- 如果核心链路强依赖阻塞 JDBC(MyBatis/JPA),盲上 WebFlux 可能得不偿失。
- WebFlux 更适合网关、聚合层、长连接(SSE/WebSocket)、大量外部 HTTP 调用。
3)JVM/GC 与 OOM 排查
业务场景:内容发布高峰 OOM,可能来自:
- 大对象(图片/视频元数据)驻留
- 缓存误用(本地缓存无限增长)
- 线程池任务堆积
定位步骤:
- 先确认 OOM 类型:
Java heap space / Metaspace / unable to create new native thread。 - 开启关键参数:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=...- GC 日志(Java 11+ 用
-Xlog:gc*)
- 用 MAT/VisualVM 分析 dump:看 dominator tree、泄漏嫌疑。
- 看 GC 日志判断:频繁 Full GC?晋升失败?
Java 8 vs 17:
- Java 8 默认 Parallel/(常见配置 CMS);Java 17 常用 G1/ZGC 等更现代的收集器选择(以具体版本与需求定)。
第二轮答案详解
1)写库 + 发 MQ 一致性:Outbox/事务消息/最终一致
业务场景:发布帖子后必须触发“审核任务”。若 DB 成功但 MQ 失败,会漏审。
常见正确方案(二选一/组合):
- Outbox Pattern(强烈推荐):
- 本地事务:写
posts+ 写outbox_event(待发送事件表) - 异步投递器轮询 outbox 表,发送 Kafka
- 发送成功后标记已发送
- 优点:不依赖分布式事务;可重试;可审计
- 本地事务:写
- Kafka 事务:只能保证 Kafka 内部事务一致,不等于与数据库跨资源一致。
- 最终一致:消费者幂等(用业务唯一键去重),配合重试与死信队列。
关键点:
- 不要幻想“数据库事务 + MQ 事务”天然原子。
- 必须考虑幂等(审核消息重复投递)和补偿(漏发补发)。
2)Redis 缓存与三大问题
业务场景:帖子详情热点访问。
- 缓存穿透(查不存在的 id):
- 布隆过滤器(RedisBloom/自建)
- 缓存空值(短 TTL)
- 缓存击穿(热点 key 过期瞬间大量打 DB):
- 互斥锁/单飞(Redis 分布式锁或本地锁)
- 逻辑过期(后台刷新)
- 缓存雪崩(大量 key 同时过期):
- TTL 随机化
- 分批预热
Redis + Caffeine 两级缓存:
- Caffeine:极低延迟,适合单机热点。
- Redis:跨实例共享。
一致性建议:
- 以 DB 为准:更新 DB 后删缓存(cache-aside),而不是双写。
- 删缓存失败要重试;可用 MQ 异步删。
3)Feign + Resilience4j:超时、重试、熔断、隔离
业务场景:审核服务慢导致发布接口线程耗尽。
组合建议:
- Timeout:严格控制(例如 200~500ms,按业务)
- Retry:只对幂等请求重试;设置最大次数 + 指数退避
- CircuitBreaker:失败率/慢调用比例触发熔断,快速失败保护系统
- Bulkhead(舱壁隔离):限制并发/线程池隔离,防止下游拖垮上游
- RateLimiter:保护自身或下游(例如审核服务限流)
关键点:
- “重试”会放大流量,熔断打开时应禁止重试。
- 对外部依赖要做隔离,否则会发生级联故障。
4)HikariCP 与数据库迁移
连接池要点:
- HikariCP 常用参数:
maximumPoolSize:别盲目调大,受 DB max_connections 与 SQL 耗时影响minimumIdle:维持一定空闲connectionTimeout:拿不到连接的等待时间,避免线程挂死
- 性能排查:慢 SQL、索引、事务范围、连接泄漏(leakDetectionThreshold)。
表结构迁移:
- 用 Flyway/Liquibase 管版本化 SQL:
- 每次上线带 migration 脚本
- CI/CD 执行,避免“手工 SQL 漏执行”
第三轮答案详解
1)K8s:滚动发布、探针、回滚
业务场景:内容服务灰度发布。
- RollingUpdate:逐步替换 Pod。
- Probes:
- readinessProbe:就绪才接流量(避免冷启动接请求)
- livenessProbe:死了重启
- 资源:requests/limits 防止抢占;配合 HPA 按 CPU/自定义指标扩缩。
- 回滚:
kubectl rollout undo deployment/...或 Helm rollback。
2)可观测体系:指标 + 日志 + 链路
10 分钟定位慢的套路:
- 指标(Metrics):Micrometer 暴露 QPS、延迟、线程池、JVM GC;Prometheus 抓取;Grafana 看趋势。
- 日志(Logs):Logback/Log4j2 + JSON 格式;ELK 检索错误堆栈与关键字段。
- 链路(Tracing):Jaeger/Zipkin 还原一次请求各 span 耗时;
- traceId/spanId 通过 HTTP header 传播(如 W3C traceparent)
关键点:只有日志不够;链路能告诉你“慢在谁”。
3)Spring AI 落地 RAG:降低幻觉
业务场景:客服回答下架原因/申诉流程,必须可追溯。
RAG 流程:
- 文档加载(PDF/网页/内部知识库)
- 文档切分(chunk)+ 去噪
- Embedding 向量化(OpenAI/Ollama 等)
- 写入向量库(Milvus/Chroma/Redis Vector)
- 查询时:语义检索 topK + 过滤(权限/时间/标签)
- 提示填充:把检索到的片段作为“上下文”喂给模型
- 输出时:要求引用来源(chunk id/文档链接)
降低幻觉:
- 只允许基于检索内容回答;无依据就输出“不确定/请人工”。
- 输出附带引用;设置温度参数;对敏感问题走规则兜底。
4)Agent + 工具调用:可控地“让模型调接口”
业务场景:机器人查“申诉状态”,需要调用内部 appeal-service。
设计要点:
- 工具标准化:定义 tool schema(入参、出参、超时、错误码)。
- 鉴权:工具调用必须带用户身份(JWT/OAuth2),后端二次鉴权。
- 防提示注入:
- 工具参数做白名单校验
- 不让模型直接拼 SQL/URL
- 对外部内容(用户输入/文档)进行隔离与清洗
- 审计与回放:记录每次 tool 调用的输入输出与 traceId。
文章小结
这场面试用“内容社区 + UGC + AIGC 审核/客服”的真实链路,把 Java 基础、微服务一致性、缓存与消息、可观测、K8s 以及 Spring AI 的 RAG/Agent 工程化串起来:基础题能背不够,关键在于能讲清业务风险与落地方案。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)