大厂Java面试实录:Spring Boot + JVM + Redis/Kafka + 微服务治理 + Spring AI/RAG 一条龙

大厂Java面试实录:Spring Boot + JVM + Redis/Kafka + 微服务治理 + Spring AI/RAG 一条龙

场景:某互联网大厂【电商内容社区 + UGC + AIGC 智能客服】团队面试。

角色:

  • 面试官:严肃、节奏快,喜欢追问落地细节。
  • 小Y:水货但嘴硬,简单题能答出来,复杂题开始"嗯...大概...应该..."。

第一轮(基础到中阶):单体服务扛得住吗?

业务背景:电商APP首页有"内容社区/UGC种草"信息流,后端是 Spring Boot 单体起步。大促时 QPS 暴涨,出现接口超时、CPU飙高。

Q1:JVM 里对象创建很频繁,为什么会导致 GC 抖动?你会怎么排查?

面试官 :大促期间你们信息流接口 GET /feed 超时,CPU 90%,你怀疑是 GC。说说对象创建频繁为什么会导致 GC 抖动?如何排查?

小Y :GC 抖动嘛...就是一直 GC。对象太多就会...回收不过来。排查的话我一般 jps 看一下,然后 jstat 看一眼......

面试官jstat 只是开始。你至少得讲出:Young GC 频率、晋升失败、Old GC、停顿时间,以及如何用堆转储定位热点对象。

小Y:嗯对对对...可以 dump 一下...然后用 MAT 分析......

面试官:还行,方向对。继续。


Q2:Java 并发下,为什么用线程池而不是每次 new Thread?线程池参数如何按接口类型设置?

面试官 :信息流接口做了并行聚合:商品、库存、推荐、广告。你用线程池还是 new Thread?线程池参数怎么拍?

小Y:肯定线程池啊,不然线程太多。参数嘛...核心线程数就 CPU 核数,最大线程数再大一点。队列随便用个 LinkedBlockingQueue。

面试官:随便?那你就等着 OOM。你得区分 IO 密集 vs CPU 密集,还要说明拒绝策略、队列长度、线程命名、可观测性。

小Y:嗯...是是是...我回去再细化一下。


Q3:Spring Boot 中 HikariCP 为什么快?连接池你会怎么避免连接泄漏?

面试官:你们用 MySQL,连接池从 C3P0 换到 HikariCP,说说为什么快?怎么防止连接泄漏?

小Y:HikariCP 就是轻量...快。泄漏的话...用完 close?

面试官:回答太"水"。不过你至少知道 close。再补点:超时、检测、监控指标。

小Y :嗯...可以设置 leakDetectionThreshold

面试官:这句终于像干过活的。


Q4:Redis 做缓存,如何解决缓存穿透、击穿、雪崩?并结合"UGC内容详情"场景说一下。

面试官 :UGC内容详情 GET /note/{id},热点内容被刷爆。缓存三大问题怎么解?

小Y:穿透就...布隆过滤器?击穿就加锁。雪崩就加随机过期。

面试官:不错,这题答得干净。可以继续深入了。


第二轮(进阶):微服务化后怎么不翻车?

业务背景:单体拆成微服务:内容服务、推荐服务、订单服务、用户服务。开始上 Spring Cloud/OpenFeign,消息用 Kafka。大促时出现:调用链很长、超时叠加、偶发雪崩。

Q1:OpenFeign 调用为什么会"越调越慢"?你怎么做超时与重试的治理?

面试官:内容服务调推荐服务,偶发 RT 3s 变 10s。Feign 为什么越调越慢?治理怎么做?

小Y:可能网络慢...或者对方慢...我们把超时调大点?

面试官:调大点是等死。要讲:超时分层、重试幂等、隔离与熔断。

小Y:嗯...可以用 Resilience4j 熔断限流?

面试官:终于提到关键组件了。


Q2:Kafka 在"订单创建事件"场景如何保证不丢消息、不重复消费?

面试官 :下单成功后发 OrderCreated 事件给推荐和营销。Kafka 怎么做到不丢?不重复?

小Y:不丢就...acks=-1?不重复...消费者自己去重?

面试官:能说出来 acks 还行。去重怎么做?

小Y:用数据库唯一键?或者 Redis set?大概是这样。

面试官:OK,算及格。


Q3:链路追踪怎么落地?Micrometer + Prometheus + Grafana + Jaeger/Zipkin 你会怎么选?

面试官:大促你怎么快速定位"慢在哪里"?讲讲指标、日志、链路三件套。

小Y:日志用 ELK,指标用 Prometheus,链路用 Jaeger?

面试官:选型没问题。关键是:你怎么把 traceId 串起来,怎么把慢 SQL、线程池队列长度都指标化。

小Y:嗯...用 MDC?然后埋点...Micrometer?

面试官:可以,再往下。


Q4:Kubernetes 上灰度发布怎么做?CI/CD 用 Jenkins/GitLab CI 你怎么设计流水线?

面试官:你们上了 K8s。新版本推荐服务想灰度,怎么做?流水线怎么配?

小Y:Jenkins 打包 Docker 镜像,推镜像仓库,然后 kubectl apply。灰度...可以搞两个 deployment?

面试官:太粗糙。至少得讲 RollingUpdate、金丝雀、流量分配、回滚与健康检查。

小Y:嗯...回滚就是把镜像 tag 改回去......

面试官:回去好好补补。


第三轮(高阶&加分):AIGC 智能客服怎么接入又不"胡说八道"?

业务背景:你们要做【电商智能客服 + 企业知识库问答】。需求:

  • 用户问"怎么退货/发票/物流异常"
  • 模型回答要基于企业文档,不能瞎编(Hallucination)
  • 要支持复杂流程:查订单、查物流、创建工单

Q1:用 Spring AI 做 RAG,你的链路设计是什么?需要哪些组件?

面试官:RAG 说说链路,别背概念。给我一条从"用户提问"到"答案返回"的工程流程。

小Y:就是...先把问题丢给大模型,然后它会回答...RAG 就是再查一下资料?

面试官:你这叫"祈祷式AI"。你要讲:文档加载、切分、向量化、向量库检索、提示填充、引用来源。

小Y:嗯...向量库可以用 Milvus 或者 Redis?Embedding 用 OpenAI 或 Ollama?

面试官:这句可以,加分。


Q2:怎么降低 AI 幻觉?以及如何让答案"可追溯可解释"?

面试官:客服最怕胡说。你怎么降低幻觉?怎么让答案可解释?

小Y:在 prompt 里让它不要胡说?

面试官:不够。还要:检索约束、引用片段、置信度阈值、拒答策略、敏感词与合规。

小Y:拒答...就是让它回答"我不知道"?

面试官:以及转人工。


Q3:Agent(智能代理)在"查订单+改地址+触发退款"这种复杂工作流怎么做?工具执行框架如何设计?

面试官:用户说"把昨天订单的收货地址改成公司,并把发票抬头改成xx"。你如何用 Agent 调用内部服务?

小Y:Agent 就是...它自己会调用?我们给它一些接口就行。

面试官:接口怎么标准化?参数怎么校验?怎么做权限?怎么防止它乱调?

小Y:呃...加鉴权?JWT?

面试官:你开始飘了。说点工程化:工具注册、schema、审批、沙箱、幂等。

小Y:嗯...我知道 MCP 是模型上下文协议...可以用来做工具调用标准化?

面试官:行,至少没完全跟不上。


Q4:聊天会话内存怎么做?短期记忆、长期记忆分别放哪?

面试官:客服是多轮对话。会话内存怎么设计?

小Y:存在 Redis?

面试官:Redis 适合短期。长期呢?

小Y:存数据库?或者向量库?

面试官:可以。关键是:隐私、过期、召回策略。


面试收尾

面试官:整体看你基础题还行,缓存那块答得不错。但微服务治理、K8s 发布、以及 AI 工程化你还需要系统补一补。

面试官:今天先到这,回去等通知。有结果我们 HR 会联系你。

小Y:好的好的!谢谢老师!(小声)回去我就把 Resilience4j 和 Spring AI 速成一遍...


面试题答案详解(按业务场景讲清楚)

目标:让小白能把每个点落到"为什么+怎么做+怎么验证"。


第一轮详解:单体服务性能与稳定性

1)对象创建频繁为何导致 GC 抖动?如何排查?

现象:接口 RT 抖动、吞吐下降、CPU 升高;GC 日志显示频繁 Young GC,甚至 Full GC。

原因链路

  • 请求高峰产生大量短生命周期对象(DTO、临时集合、字符串拼接、Jackson反序列化中间对象)。
  • Eden 很快被填满 → 频繁 Minor GC
  • 如果对象"活过一次 GC"(比如被缓存、被线程池任务引用、或存活时间略长),会进入 Survivor/Old。
  • Old 区增长过快或发生 晋升失败/碎片化 → 触发 Full GC(停顿更长)。

排查步骤(Java 8/11/17通用思路)

  1. 先证据 :开启/收集 GC 日志(Java 11+ -Xlog:gc*,Java 8 -XX:+PrintGCDetails 等)。
  2. 运行态观察
    • jstat -gcutil <pid> 1s 20 看 YGC/FGC 次数与耗时。
    • jcmd <pid> VM.native_memory summary(11+)看本地内存。
  3. 堆转储jcmd <pid> GC.heap_dump /path/heap.hprof
  4. MAT/YourKit 分析 :找 Top Dominators:
    • 是否存在大集合、缓存不当、重复字符串、巨型 byte[]。
  5. 代码层优化
    • 减少临时对象:复用对象/缓冲区(注意线程安全)。
    • 避免无意义的 new ArrayList()/String +,使用 StringBuilder。
    • Jackson 反序列化优化:字段裁剪、避免深层嵌套。

验证:对比 GC 次数、P99 RT、吞吐(QPS)、CPU 使用率。


2)为什么用线程池?参数如何设置?

为什么不用 new Thread

  • 线程创建/销毁成本高。
  • 无上限会导致线程爆炸 → 上下文切换过多 → 吞吐下降,甚至 OOM(unable to create new native thread)。

线程池参数按任务类型估算

  • CPU 密集(计算、压缩、加密):线程数≈CPU核数或核数+1。
  • IO 密集 (HTTP/RPC/DB):线程数可大于核数,粗略:Nthreads ≈ Ncpu * (1 + Wait/Compute)

队列与拒绝策略

  • LinkedBlockingQueue 默认可"无限长"→ 高峰堆积任务导致内存膨胀,危险。
  • 建议:
    • 明确队列长度(如 1000/5000),用 ArrayBlockingQueue
    • 拒绝策略:
      • CallerRunsPolicy:降速保护系统(常用)。
      • AbortPolicy:快速失败(需要上层兜底)。

工程化建议

  • 线程命名(便于排查):ThreadFactory
  • 指标化:活跃线程数、队列长度、拒绝次数(Micrometer)。

3)HikariCP 为什么快?如何防止连接泄漏?

快的原因(核心点)

  • 设计极简,减少锁竞争;高性能的连接管理。
  • 更少的内部对象与逻辑路径,延迟更低。

防泄漏措施

  • 确保 try-with-resources 正确关闭 Connection/Statement/ResultSet
  • Hikari 参数:
    • leakDetectionThreshold:超过阈值未归还连接会打印堆栈。
    • maxLifetimeidleTimeoutconnectionTimeout 防止僵尸连接。
  • 监控:连接池使用率、等待时间(Micrometer 自带 binder)。

4)Redis 缓存穿透/击穿/雪崩(UGC详情)

GET /note/{id} 为例:

  • 穿透 (大量请求不存在的 id):
    • 布隆过滤器(Bloom Filter)拦截。
    • 对空值缓存(短 TTL)防止重复打 DB。
  • 击穿 (某热点 key 过期瞬间):
    • 互斥锁(Redis setnx)或 singleflight,只有一个请求回源。
    • 逻辑过期(缓存值带过期时间,后台异步刷新)。
  • 雪崩 (大量 key 同时过期):
    • TTL 加随机抖动。
    • 分批预热、热点隔离、限流降级。

第二轮详解:微服务治理、消息与可观测性

1)Feign 为什么越调越慢?如何治理超时/重试?

常见根因

  • 下游变慢导致上游线程池/连接池耗尽(级联放大)。
  • 不合理重试:在已慢的情况下重试叠加,雪上加霜。
  • 超时配置不分层:连接超时、读超时、整体超时混乱。

治理套路

  • 超时:设置合理 connect/read timeout,并在网关/调用方设全局 deadline。
  • 重试:只对幂等接口(GET/可安全重放的请求)重试;限制次数并加退避。
  • 隔离:线程池隔离/舱壁(Resilience4j Bulkhead)。
  • 熔断/限流:Resilience4j CircuitBreaker + RateLimiter。
  • 降级:返回兜底数据或"稍后重试",保护核心链路。

2)Kafka 如何保证不丢与去重?

不丢(生产端)

  • acks=all(等 ISR 确认)+ 合理 retries
  • 开启幂等生产者(enable.idempotence=true)减少重复。

不丢(消费端)

  • 手动提交 offset:处理成功再 commit。
  • 失败重试进入重试队列/死信队列(业务层设计)。

不重复(业务语义)

  • Kafka 只能做到"至少一次/至多一次/接近恰好一次",业务通常要 幂等消费
    • 数据库唯一键(orderId + eventType
    • Redis 去重 key(带 TTL)

3)指标+日志+链路怎么落地?

  • 指标(Prometheus+Grafana)
    • HTTP 请求 QPS、P95/P99、错误率
    • 线程池 active/queue/reject
    • Hikari 连接池 active/pending
  • 日志(ELK)
    • JSON 日志结构化,关键字段:traceId、userId、orderId
    • 使用 SLF4J + Logback/Log4j2,MDC 注入 traceId
  • 链路(Jaeger/Zipkin + OpenTelemetry)
    • 统一 traceId 贯穿网关→服务→DB→MQ
    • 关键 span:Feign 调用、SQL、Kafka produce/consume

4)K8s 灰度发布与 CI/CD

灰度/发布策略

  • RollingUpdate:逐步替换 pod,配 readiness/liveness。
  • 金丝雀(Canary):
    • 两套版本并存,按流量比例或按用户标签导流(配合网关/Service Mesh)。
  • 回滚:
    • 保留历史 ReplicaSet/镜像 tag,失败自动回滚。

流水线(Jenkins/GitLab CI)

  1. 单测(JUnit5 + Mockito)
  2. 构建(Maven/Gradle)
  3. 安全扫描/制品归档
  4. Docker build & push
  5. 部署到测试环境(Helm/Kustomize)
  6. 自动化回归/冒烟
  7. 灰度到生产 + 监控验收

第三轮详解:Spring AI / RAG / Agent 工程化

1)Spring AI 做 RAG 的工程链路

离线(知识入库)

  1. 文档加载(PDF/HTML/Confluence/数据库):Document Loaders
  2. 文本切分(chunking,带重叠)
  3. 向量化(Embedding:OpenAI/Ollama)
  4. 写入向量数据库(Milvus/Chroma/Redis Vector)

在线(问答)

  1. 用户问题 → embedding
  2. 向量库相似度检索 topK(语义检索)
  3. 将检索片段 + 业务约束(不确定就拒答)做 提示填充
  4. 调用大模型生成回答(带引用来源)
  5. 返回:答案 + 引用文档/片段 id(可追溯)

2)降低幻觉与可追溯

  • 检索约束:只允许基于检索内容回答;未检索到足够证据则拒答。
  • 引用输出 :要求模型输出 sources[](文档ID/段落)。
  • 阈值策略:相似度低于阈值 → "转人工/创建工单"。
  • 提示模板:明确格式、禁止编造。
  • 合规:敏感信息脱敏、权限校验(不同用户可见知识不同)。

3)Agent 工作流与工具执行框架

核心思想:模型负责"决定调用哪个工具",系统负责"安全地执行工具"。

工程要点:

  • 工具注册:每个工具有名称、描述、入参 schema、出参 schema。
  • 标准化调用:可借鉴 MCP/Function Calling 思路,让调用可解析可验证。
  • 权限与审计:JWT/OAuth2 校验用户身份;记录每次工具调用。
  • 幂等:退款/改地址必须有幂等 key,防止重复执行。
  • 沙箱与护栏:限制可调用工具集合、调用次数、参数范围;高风险操作需二次确认。

4)会话内存:短期 vs 长期

  • 短期记忆 (本次会话上下文、最近N轮对话):
    • Redis/内存缓存(带 TTL)
  • 长期记忆 (用户偏好、历史工单摘要、可检索的历史对话):
    • 结构化数据:MySQL/PostgreSQL
    • 语义召回:向量库(对摘要做 embedding)

注意:隐私合规、过期策略、可删除(Right to be forgotten)。

相关推荐
2301_779622411 小时前
如何修复SQL嵌套查询死锁_调整锁粒度与执行顺序
jvm·数据库·python
HelloWorld工程师1 小时前
Redis 小小知识点
数据库·redis·缓存
iAm_Ike1 小时前
HTML怎么显示灵感便签关联项目_HTML拖拽绑定项目入口【详解】
jvm·数据库·python
有梦想的小何1 小时前
Cursor AI 编程实战(篇三):Domain、Infrastructure 与策略模式
java·ai编程·策略模式
2301_809204701 小时前
SQL如何实现实时数据的滑动窗口分析_SQL性能调优
jvm·数据库·python
yexuhgu1 小时前
如何在 JavaScript 循环中动态构建 HTML 字符串
jvm·数据库·python
西凉的悲伤1 小时前
java通过url获取 jpg、png、pdf 文件格式
java
SunnyDays10111 小时前
Java 实现 PDF 附件的添加与删除:四种实用方法
java·pdf·附件
wang3zc1 小时前
使用BERTopic对名言数据集进行批量主题建模的完整实践指南
jvm·数据库·python