大厂Java面试实战:Spring Boot + Redis + Kafka + Kubernetes + RAG 的三轮追问(附答案解析)
角色设定
- 面试官(M):语气平稳、追问精准、不给水分。
- 小Y(Y):自称"全栈架构师",简单题能答,复杂题开始"灵魂出窍"。
业务背景
一家内容社区(UGC)正在做两件事:
- 发帖/评论高并发,要求热点内容"秒开"。
- 上线一个**企业文档问答(RAG)**的智能客服,要求可观测、可扩展、可降级。
第一轮:单体到服务化的基础功(4题)
Q1:Spring Boot 项目里,为什么一般不用 new 创建服务对象,而是交给容器?
M: 解释下 Spring IoC/DI 对可测试性和解耦的价值。
Y: 因为......@Autowired 比较方便,new 了它可能就不生效。
M: 方向对了。再补一句:为什么对测试有帮助?
Y: 呃......能 mock?
M: 可以。
Q2:UGC 发帖接口做成 REST,你会怎么设计幂等?
M: 说说幂等键、数据库唯一约束、以及在分布式下如何避免重复发帖。
Y: 我会加个 token......放 Redis 里,来一次删一次。
M: 还可以。但如果 Redis 抖了呢?
Y: 那就......重试?
M: 好,我们后面再聊。
Q3:数据库连接池你选 HikariCP 的理由?以及常见参数怎么定?
Y: 因为快。
M: 快是结果,原因是什么?比如实现机制、线程模型?
Y: 它......算法很先进。
M:(沉默两秒)继续。
Q4:你如何用 Flyway/Liquibase 管理线上表结构变更?
Y: 我一般直接在 Navicat 上改,然后同步一下。
M:(眼神更严肃)
第二轮:缓存、消息、微服务链路(4题)
Q5:热点帖子详情页"秒开",你会怎么用 Redis?
M: 说出缓存模式、TTL、穿透/击穿/雪崩的治理,以及与本地缓存 Caffeine 的组合。
Y: 我就 get,没有就查数据库,再 set。
M: 这是最基础。那击穿怎么防?
Y: 加锁?比如 synchronized。
M:(点头)至少知道"锁"。
Q6:评论异步审核与通知,用 Kafka 还是 RabbitMQ?
M: 从吞吐、顺序、消费语义、延迟、消息堆积与回溯说。
Y: Kafka 吞吐高,RabbitMQ 更可靠。
M: "更可靠"怎么定义?ACK、重试、死信?
Y: 就是......它比较传统。
Q7:微服务调用用 OpenFeign,如何做超时、重试、熔断与降级?
M: 说说 Resilience4j 和 Spring Cloud 的组合,别只会配置。
Y: 我会把 timeout 配大一点。
M:(轻叹)那我们继续。
Q8:链路追踪你怎么做?Jaeger/Zipkin/Micrometer/Prometheus 在体系里各干什么?
Y: Prometheus 就是看 CPU;Jaeger 就是看调用。
M:(语气缓和一点)至少你没把它们和 ELK 搞混。
第三轮:云原生 + AI RAG 的综合追问(4题)
Q9:服务上 Kubernetes 后,健康检查怎么设计?
M: readiness/liveness 的差异?Spring Boot Actuator 怎么配?
Y: 就写个 /health,返回 200。
M: 如果依赖的数据库挂了,readiness 应该怎样?
Y: 也 200......不然用户访问不到。
M:(摇头)
Q10:你们要做"企业文档问答(RAG)",从上传文档到问答,你的技术链路怎么设计?
M: 讲清:文档加载、切分、向量化(embedding)、向量库(Milvus/Chroma/Redis)、检索、提示填充、回答生成,以及如何减少幻觉。
Y: 就把文档丢给大模型,它就会回答。
M:(非常平静)那是"祈祷式架构"。
Q11:RAG 系统如何做会话内存与权限控制?
M: 聊天会话内存放哪里?如何隔离租户?如何用 Spring Security/OAuth2/JWT?
Y: JWT 就是加密的 token,放啥都行。
M: JWT 不是"想放啥就放啥"。
Q12:RAG+工具调用(Agent)落地:如何把"查订单/开工单/查物流"变成工具执行框架?
M: 讲讲 MCP/工具调用标准化、幂等、审计、以及失败重试。
Y: 让模型自己请求接口就行......
M:(收起简历)好的,今天先到这。
面试结束
M: 你回去等通知吧。如果后续进入下一轮,我们会让你补一份"RAG 方案设计 + 缓存一致性"的文档。
Y: 好的好的,我回去就"深入研究一下"。
答案解析(把小Y含糊的地方一次讲清)
下面按题号给出可直接背诵+可落地的解释,结合"内容社区 + 智能客服RAG"的业务。
A1:为什么交给 Spring 容器(IoC/DI)而不是 new
- 解耦:依赖以接口形式注入(DI),调用方不关心实现类创建细节,方便替换实现(例如本地实现→远程实现)。
- 生命周期与横切能力:容器能统一管理单例/原型、初始化/销毁,并织入 AOP(事务、鉴权、日志、监控)。
- 可测试性 :
- 单元测试可用 Mockito 替换依赖:
@Mock+@InjectMocks或 Spring Test 的@MockBean。 - 依赖可配置(profile),测试环境可换 H2、Testcontainers。
- 单元测试可用 Mockito 替换依赖:
A2:发帖接口幂等设计(防重复提交)
业务:用户网络抖动、App 重试、网关重放都可能导致重复发帖。
可组合方案:
- 幂等键(Idempotency-Key):客户端生成 UUID,放 Header;服务端记录 key→结果。
- Redis 去重 (快路径):
SET key value NX EX 60成功才处理;失败直接返回"重复提交"。- 注意:需返回同一幂等键对应的相同结果(可把创建的 postId 缓存起来)。
- 数据库兜底唯一约束 (最终一致的防线):
- 例如
unique(user_id, client_token)或业务唯一号。 - 即使 Redis 故障也能靠 DB 防重复。
- 例如
- 分布式下的失败处理 :
- 处理超时要能查到"是否已成功落库"。
- 对外返回可用"查询创建结果"的接口。
A3:HikariCP 为什么快、参数怎么定
- 快的原因(工程化点) :
- 更少的锁竞争与对象创建;连接获取路径短。
- 连接检测策略更高效(避免频繁 test query)。
- 关键参数 (经验值需压测校准):
maximumPoolSize:常见按 CPU核数 与 DB承载 综合定;不要盲目大。minimumIdle:稳定流量可设为接近 max;波动大可偏小。connectionTimeout:获取连接超时(如 300ms~2s),用于快速失败。idleTimeout/maxLifetime:避免连接被 LB/防火墙断开(maxLifetime通常 < DB 连接回收时间)。
A4:Flyway/Liquibase 做表结构版本化
业务:多人协作、灰度发布、回滚审计。
- 核心思想:把 DDL 变更当作代码提交(Git),由流水线自动执行。
- Flyway:以 版本号脚本 为主(
V1__init.sql)。 - Liquibase:支持 XML/YAML/SQL,适合更复杂的变更描述与回滚。
- 最佳实践 :
- 禁止手工直改生产;所有变更必须可追溯。
- 脚本向前兼容(先加字段再读写切换,再删字段)。
A5:Redis 缓存热点内容:模式与三大问题治理
业务:帖子详情、作者信息、评论数。
- 缓存模式 :
- Cache-Aside(旁路缓存):读:先缓存后 DB;写:先 DB 再删除/更新缓存。
- TTL :热点长 TTL + 随机抖动(
ttl + rand(0..N))防雪崩。 - 穿透(查不存在):布隆过滤器 / 缓存空值(短 TTL)/ 参数校验。
- 击穿 (热点 key 过期瞬间):
- 互斥锁(Redis 分布式锁)/ singleflight;只让一个线程回源 DB。
- 雪崩 (大量同时过期或 Redis 故障):
- TTL 打散、分批预热、降级(返回兜底页/旧数据)。
- 本地缓存 Caffeine + Redis :
- Caffeine 抗极致热点;Redis 做跨实例共享。
- 注意一致性:可用消息通知或短 TTL。
A6:Kafka vs RabbitMQ(评论审核与通知)
- Kafka :
- 优势:高吞吐、可回溯(按 offset 重放)、适合日志/行为流/事件总线。
- 关注:顺序性在分区内;消费语义通常是至少一次(配合幂等)。
- RabbitMQ :
- 优势:低延迟、路由灵活(topic/direct/fanout)、ACK/死信队列更易用。
- 适合:业务命令型消息、需要复杂路由与延迟队列场景。
- 落地建议(本场景) :
- 审核流水、行为流:Kafka。
- 站内信/短信/邮件触达:RabbitMQ 或 Kafka+专用消费者均可。
A7:OpenFeign + Resilience4j:超时、重试、熔断、降级
业务:评论服务调用用户服务、风控服务。
- 超时:连接超时 + 读超时要合理(例如 200ms~1s);不要"配大点"。
- 重试 :只对幂等请求重试(GET/查询);写操作要用幂等键。
- 熔断:下游错误率高时打开熔断,保护线程池与自身可用性。
- 隔离:Bulkhead(舱壁)限制并发,避免某下游拖死全部。
- 降级:返回兜底数据(例如用户昵称"匿名用户"),并打点报警。
A8:可观测体系:Micrometer/Prometheus/Grafana/ELK/Jaeger
- Micrometer:应用侧指标门面(埋点、Timer、Counter)。
- Prometheus:拉取并存储时序指标(QPS、P99、线程池、GC)。
- Grafana:指标可视化与告警。
- ELK:日志采集检索(排查错误堆栈、业务日志)。
- Jaeger/Zipkin:分布式追踪(traceId/spanId),定位慢点在谁。
A9:Kubernetes 健康检查:readiness vs liveness
- livenessProbe:进程是否"活着"。失败会重启 Pod。
- readinessProbe:是否"可接流量"。失败会从 Service Endpoints 摘除。
- 正确做法 :
- DB/Redis 不可用时:readiness 失败(不接新流量),但 liveness 不一定失败(避免无意义重启风暴)。
- Spring Boot Actuator:暴露
/actuator/health/liveness与/actuator/health/readiness。
A10:企业文档问答 RAG 全链路设计
业务:企业内部 SOP、产品手册、工单知识库。
- 文档加载(Document Loader):PDF/Word/网页/Confluence 等。
- 切分(Chunking):按标题/段落/Token 切块,保留元数据(来源、权限、时间)。
- 向量化(Embedding):选 embedding 模型(OpenAI/Ollama),把 chunk→向量。
- 向量数据库:Milvus/Chroma/Redis Vector,存向量+metadata。
- 检索:语义检索(TopK)+ 关键词 BM25(可选混合检索)。
- 提示填充(Prompt):把检索到的片段作为 context,拼装系统提示与约束。
- 生成回答:LLM 输出,并要求引用来源。
- 降低幻觉 :
- 只允许基于检索片段回答;无依据时输出"未找到"。
- 输出带引用;增加事实核验(自检/多路检索)。
A11:会话内存与权限控制(多租户)
- 会话内存 :
- 短期:Redis(conversationId→messages/summary),设置 TTL。
- 长期:MySQL/ES(可检索)或对象存储(审计)。
- 权限控制 :
- Spring Security + OAuth2/OIDC(Keycloak)统一登录。
- JWT 放的是"声明(claims)",不是加密保险箱;敏感信息不放 JWT。
- 文档检索要做租户隔离:metadata 带 tenantId、docACL,检索过滤。
A12:Agent + 工具调用(MCP/标准化)如何落地
业务:客服问"订单到哪了""给我开工单"。
- 工具执行框架 :
- 定义工具 schema(name/params/权限/幂等等),模型只负责"选择工具+填参"。
- 服务端负责鉴权、参数校验、限流、审计。
- MCP/工具调用标准化 :
- 把外部系统能力(订单、物流、工单)以标准接口暴露,便于扩展。
- 幂等与审计 :
- 写操作必须有幂等键;所有工具调用落库记录(谁、何时、做了什么)。
- 失败处理 :
- 重试只用于幂等工具;非幂等需要补偿/人工确认。
小结:如果你要把这场面试"答满分"
- UGC:缓存一致性 + MQ 解耦 + 可观测。
- 云原生:K8s 探针与限流熔断。
- AI:RAG 不是"把文档丢给模型",而是一条工程链路;权限与审计必须先行。