互联网大厂Java面试:Spring Boot/Redis/Kafka/K8s 可观测 + RAG(向量检索/Agent)三轮追问实录
互联网大厂 Java 面试实录:Spring Boot + Redis + Kafka + Kubernetes + RAG(向量检索/Agent)三轮追问
场景:某内容社区与UGC平台,近期上线“RAG 智能客服”(企业文档问答 + 工单流转),并要求支持高并发、可观测、可灰度。
人物:
- 面试官(M):严肃、节奏快、喜欢追问“为什么”。
- 小Y(Y):自称“全栈Java”,实际有点水但很会搞笑。
第一轮:Java 基础与 Web 入门(3-5问)
Q1:M:Java 8/11/17 你最常用哪些新特性?在我们“UGC内容审核/客服系统”里会怎么用?
Y:Java 8 就是……Lambda!Stream!写起来像在写 SQL,挺爽的。Java 11/17……我一般用 8,兼容性好。
M:Java 8 用得熟是好事,但别把“只会8”当优点。说说你在代码里怎么落地 Stream 的?
Y:比如把用户列表stream().filter()一下……然后就更优雅了。
M:还行,基础没丢。
Q2:M:Spring MVC 和 Spring WebFlux 有什么区别?我们智能客服“长连接/流式输出”该选哪个?
Y:MVC 是同步阻塞,WebFlux 是……反应式!就很快!
M:快不快不是口号。背后模型是什么?
Y:呃……就是 Reactor,Mono/Flux,那种“流”。
M:回答有点虚,但方向对。我们后面会追。
Q3:M:HikariCP 为什么普遍比 C3P0 受欢迎?你在 Spring Boot 怎么配置连接池参数?
Y:因为……Hikari 轻量、快!配置我一般用spring.datasource.hikari.*。
M:行,能说出关键点。比如连接池满了会怎样?
Y:会……排队?
M:至少知道会阻塞/等待。继续。
Q4:M:如果线上出现“接口偶发超时”,你第一步看什么?日志怎么打?
Y:我先看 ELK!再看日志里有没有 error。日志用 SLF4J,log.info("xxx {}", id)。
M:参数化日志不错,避免字符串拼接。还可以。
第二轮:微服务、缓存、消息队列(业务递进)(3-5问)
业务设定:UGC平台的“智能客服”接入站内私信与工单。用户提问后,系统要:
- 先查缓存命中“常见问题”;
- 未命中则走 RAG:向量检索 + LLM 生成;
- 生成结果与引用片段落库;
- 异步写入 Kafka 做埋点与质检。
Q1:M:你会怎么设计 Redis 缓存结构,避免热点 Key 和缓存穿透?
Y:热点 Key 我就加本地缓存 Caffeine!穿透就……加布隆过滤器?
M:不错,能说到点上。布隆过滤器怎么落地?
Y:就……Guava 有 BloomFilter,放 Redis 也行。
M:思路可以,但细节要补。
Q2:M:Kafka 和 RabbitMQ 怎么选?我们这里“埋点/质检/回放”更适合哪个?
Y:Kafka 吞吐高,RabbitMQ 延迟低?我感觉都行,看团队喜好。
M:(皱眉)“都行”是面试大忌。说出语义:顺序、消费模型、回放、消息堆积。
Y:Kafka 可以回放,按 partition 顺序;RabbitMQ 更像传统队列。
M:这句对了。
Q3:M:你会如何做微服务间调用?OpenFeign + Resilience4j 怎么配合?
Y:Feign 调用很方便,Resilience4j 就是限流熔断降级。我一般加个 fallback。
M:fallback 只是表面。重试、超时、隔离、舱壁这些怎么选?
Y:看感觉……哪个报错就加哪个。
M:嗯,开始“凭感觉写代码”了。
Q4:M:数据库层:MyBatis 和 JPA/Hibernate 你怎么选?RAG 结果落库的表会怎么设计?
Y:复杂 SQL 用 MyBatis,简单 CRUD 用 JPA。表设计就:question、answer、time。
M:字段太少。引用片段、模型版本、embedding版本、traceId、反馈标签呢?
Y:啊对对对,可以再加。
M:……
第三轮:云原生可观测 + AI 工程化(3-5问)
业务设定升级:RAG 客服上线后出现:
- 高峰期 P95 延迟抖动
- 偶发“答非所问”(幻觉)
- 模型供应商切换(OpenAI ↔ Ollama/自建)
- 需要对接企业知识库,支持文档加载与增量更新
Q1:M:Kubernetes 上部署 Spring Boot,你会重点关注哪些资源与探针?怎么做灰度?
Y:资源就 CPU、内存;探针有 liveness、readiness;灰度用……分批发布?
M:基本点都对。灰度更细一点:Service、Ingress、或者 Service Mesh。你再想想。
Y:可以用 Kubernetes 的 rollout……或者直接手动?
M:行吧。
Q2:M:Prometheus + Grafana + Micrometer 你会采哪些指标定位“P95抖动”?
Y:JVM 指标、GC 指标、线程池指标……还有接口耗时。
M:继续。你如何区分是“下游慢”还是“GC慢”还是“连接池耗尽”?
Y:我看图……哪个高就哪个。
M:过于朴素。
Q3:M:链路追踪 Jaeger/Zipkin 怎么把一次“RAG请求”串起来?要打哪些 tag?
Y:traceId 串起来,span 里面写“检索”和“生成”。
M:还不够。向量检索命中数、topK、prompt token、completion token、模型名、温度、知识库版本都要。
Y:这些也能打吗?那我都打上。
M:……打多了也会贵。
Q4:M:谈谈 RAG 的“文档加载→向量化→语义检索→提示填充→生成→引用校验”。你怎么降低幻觉?
Y:幻觉就……让模型别乱说?提示词写严格点。
M:(沉默两秒)继续。
Y:加个“如果不知道就说不知道”。
M:这是入门级。还可以:检索质量、chunk策略、引用强约束、回答后验证、以及 Agentic RAG 的工具执行。
Y:我回去研究一下。
Q5:M:Spring AI / MCP / 工具调用标准化:如果要让客服 Agent “查订单、查物流、建工单”,你会怎么设计工具接口?
Y:我就写三个接口给它调……
M:怎么做权限、审计、幂等、防重复下单?
Y:呃……加 Spring Security?JWT?
M:至少知道安全框架。细节先到这。
面试收尾
M:今天整体看下来,你 Java/Spring 基础还可以,场景理解也有,但在可观测细化、容灾治理、以及 RAG 工程化细节上比较虚。你回去把这些链路再系统补一下,我们会综合评估,回家等通知。
Y:好的好的,我回去就把“凭感觉”升级成“凭数据”。
文末复盘:所有问题的详细答案(含业务落地)
下面按三轮问题逐一给出更“能上生产”的回答,小白可按此学习与扩展。
第一轮答案:Java / Web / 连接池 / 日志
A1:Java 8/11/17 常用特性与落地
- Java 8
- Lambda/Stream:用于集合处理、DTO转换、过滤排序。
- Optional:减少空指针,但避免滥用(不要把 Optional 当字段类型)。
- CompletableFuture:并行调用(如“FAQ缓存查询 + 热门知识库检索”可并发)。
- Java 11
- HttpClient:替代老旧 HttpURLConnection(微服务一般仍用 OkHttp/Apache HC)。
- String/Collection API 增强。
- Java 17
- 记录类 record:适合不可变 DTO(如检索结果、Embedding请求响应)。
- switch 表达式、文本块:拼 Prompt 更安全可读。
UGC/客服落地示例:
- 并行:
CompletableFuture同时拉取“用户画像/历史工单/常见FAQ”,最终合并为提示上下文。
A2:Spring MVC vs WebFlux,流式输出怎么选
- Spring MVC:Servlet 模型,线程-per-request,适合传统 CRUD。
- Spring WebFlux:基于 Reactor(Mono/Flux),非阻塞 I/O,适合:
- SSE/WebSocket 流式输出(LLM token streaming)
- 高并发下减少线程占用(但需要全链路非阻塞:Netty + R2DBC/Reactive Redis等)
选择建议:
- 现有系统若大量阻塞组件(JPA/JDBC),强上 WebFlux 可能“表面Reactive、内部阻塞”。
- 折中方案:核心仍 MVC,但对“生成回答”单独做 WebFlux/SSE 网关服务;或用异步 Servlet + chunked response。
A3:HikariCP 优势与关键参数
- 优势:
- 代码路径短、锁竞争少、性能稳定;Spring Boot 默认。
- 关键配置:
maximumPoolSize:并发上限(结合 DB 连接限制与QPS评估)minimumIdle:空闲连接connectionTimeout:拿不到连接等待多久(避免线程无限挂)leakDetectionThreshold:连接泄露检测(排查未关闭连接)
现象定位:
- 接口超时可能来自:连接池耗尽(active=maximumPoolSize)、慢SQL、事务未提交、连接泄露。
A4:接口偶发超时的排查与日志规范
排查优先级:
- 指标:P95/P99、线程池/连接池、GC、下游依赖延迟
- 日志:是否有超时/重试/熔断
- 链路追踪:定位慢在网关、服务、DB、MQ、第三方
日志实践:
- 统一用SLF4J + Logback/Log4j2,参数化:
log.info("orderId={}", id) - 关键链路打印:
traceId、用户id、请求耗时、下游耗时、错误码 - 注意脱敏(手机号、身份证、token)。
第二轮答案:缓存 / MQ / 微服务治理 / ORM与表设计
A1:Redis 缓存结构 + 热点Key + 穿透
缓存目标:FAQ命中、检索结果短缓存、会话上下文。
设计:
- Key 设计:
faq:answer:{normalizedQuery}rag:retrieval:{queryHash}(短TTL)
- 热点 Key:
- 本地缓存 Caffeine+ Redis 二级缓存;热点FAQ可以预热。
- 对极热点可用 Redis Cluster + Key hash tag、或拆分多Key。
- 缓存穿透:
- 布隆过滤器:对“FAQ问题集合/知识库文档id集合”做存在性判断。
- 对确实不存在的请求写入空值缓存(短TTL)避免重复打DB。
- 缓存击穿:
- 互斥锁/单飞:
SETNX或 Redisson Lock,确保同一key回源只发生一次。
- 互斥锁/单飞:
A2:Kafka vs RabbitMQ 的选择(埋点/质检/回放)
- Kafka更适合:
- 高吞吐日志/埋点
- 消费者组并行
- 消息回放(按 offset 重放质检)
- 长时间堆积(磁盘顺序写)
- RabbitMQ更适合:
- 复杂路由(topic/headers)
- 每条消息确认与低延迟队列语义
- 业务命令型消息(更强“队列感”)
本场景建议:
- 埋点、质检、对话回放:Kafka。
- 工单创建这类强一致命令:可用 RabbitMQ 或事务外盒 + DB。
A3:OpenFeign + Resilience4j 的治理组合
常见组合:
- Feign:声明式HTTP客户端
- Resilience4j:
- TimeLimiter:超时
- Retry:谨慎使用(只对幂等GET或可重试错误)
- CircuitBreaker:熔断,防止雪崩
- Bulkhead:舱壁隔离(线程池/信号量隔离)
- RateLimiter:限流
推荐策略(客服RAG):
- 检索服务:超时短(如 200-400ms),失败可降级“少量topK”或“只走FAQ”。
- LLM生成:超时较长(如 3-10s),失败返回“转人工/创建工单”。
- 对下游依赖加 Bulkhead,避免生成占满线程池拖垮全站。
A4:MyBatis vs JPA/Hibernate,RAG落库表设计
选型:
- MyBatis:复杂SQL、报表、多表join可控。
- JPA/Hibernate:领域模型清晰、CRUD高效,但复杂SQL可能难维护。
- 也可:Spring Data JDBC(更轻量)
RAG结果建议表:rag_conversation_turn
idconversation_id(会话)user_idquestion_textanswer_textcitations(JSON:文档id、chunkId、score、offset)retrieval_topk、hit_countkb_version、embedding_model、llm_model、prompt_versiontoken_prompt、token_completionlatency_ms(总耗时+分段耗时)trace_idfeedback(like/dislike/标签)created_at
配套:
- 用Flyway/Liquibase管理表结构演进。
第三轮答案:K8s、可观测、链路追踪、RAG与Agent工程化
A1:Kubernetes 部署要点 + 探针 + 灰度
- 资源:
- requests/limits 合理设置,避免 OOMKilled 或 CPU throttling
- JVM 参数与容器协同(如
-XX:MaxRAMPercentage)
- 探针:
- readiness:依赖就绪(DB/MQ连接、缓存预热)
- liveness:死锁/假死检测(不要把外部依赖失败当liveness失败)
- 灰度:
- 多 Deployment(v1/v2)+ Service 按标签切流
- Ingress/Nginx 按 header/cookie 做灰度
- 或使用 Service Mesh(Istio)做更精细流量治理
A2:Micrometer/Prometheus 指标定位 P95 抖动
必采指标:
- HTTP:QPS、P50/P95/P99、错误率
- JVM:GC次数/停顿、堆使用、线程数
- 线程池:active、queue size、reject count
- 连接池:Hikari active/idle/pending
- 下游依赖:HTTP client latency、DB query latency、Kafka produce latency
定位方法:
- 若 GC pause 与延迟同周期上升:调堆、对象分配、缓存结构。
- 若 Hikari
pending上升:慢SQL/连接泄露/池太小。 - 若下游依赖延迟上升:加超时、隔离、熔断、降级。
A3:Jaeger/Zipkin 链路追踪:RAG一次请求的 Span 设计
建议 span:
http:entrycache:faq_getretrieval:vector_searchprompt:renderllm:completionpostprocess:citation_checkdb:save_turnmq:kafka_produce
关键 tags(选取必要的,避免过量):
conversationId、userIdtopK、hitCount、maxScorekbVersion、embeddingModel、llmModel、promptVersiontokensPrompt、tokensCompletionprovider(OpenAI/Ollama)fallback是否触发
A4:RAG 全流程与降低幻觉的工程手段
流程:
- 文档加载(PDF/HTML/Confluence等)
- 清洗切分(chunk:长度、重叠、按标题层级)
- 向量化(Embedding模型)
- 向量库(Milvus/Chroma/Redis Vector)存储与索引
- 语义检索(topK、相似度阈值、混合检索BM25+向量)
- 提示填充(把“引用片段”注入prompt)
- 生成(LLM)
- 引用校验与后处理(必须基于引用回答)
降幻觉:
- 检索质量:合理 chunk、去噪、增量索引、阈值过滤
- 强约束回答格式:要求输出引用id;无引用则拒答/转人工
- 回答后验证:
- 规则校验(是否引用)
- 轻量模型/模板校验
- Agentic RAG:当问题需要“查订单/查物流”时,先工具调用拿到确定性数据,再生成。
A5:Spring AI / MCP / 工具调用标准化:工具接口设计
目标:让 Agent 安全、可审计、可扩展地调用业务能力。
做法:
- 工具清单(Tool Registry):
getOrderStatus(orderId)trackShipment(trackingNo)createTicket(category, content, attachments)
- 关键工程点:
- 鉴权:Spring Security + OAuth2/JWT,工具执行必须带用户上下文
- 审计:记录 toolName、参数摘要、结果摘要、traceId、耗时
- 幂等:如创建工单用幂等键(conversationId + turnId)
- 权限与风控:敏感操作二次确认、限频(Resilience4j RateLimiter)
- 客户端-服务器架构:Agent服务作为客户端,业务系统提供工具API(或通过 MCP 统一协议暴露)
学习路线(按面试暴露短板补齐)
- JVM/性能:GC、线程池、连接池、火焰图
- 微服务治理:超时/重试/熔断/隔离/限流的组合策略
- 可观测:指标 + 日志 + 追踪三件套联动
- RAG工程:chunk/索引/阈值/引用约束/工具调用与审计
完
