从Spring Boot到Spring AI:音视频AIGC内容社区Java大厂面试三轮连环问(含Kafka/Redis/安全/可观测性答案)
场景:某互联网大厂"内容社区 + UGC + 音视频 + AIGC"业务线。你(候选人小Y)来面Java后端。面试官老周严肃认真,但会在你答对时适度引导;你一旦遇到复杂题,就开始"战略性含糊"。
第一轮:从业务入手------UGC音视频上传与审核链路(基础到进阶)
Q1(业务开场):
面试官老周: 我们做内容社区,用户发视频,上传成功后会进入转码、截图、内容审核、推荐入库。你用 Spring Boot 设计一个"上传后异步处理"的链路,怎么拆?
小Y: 这个我熟!上传接口Spring MVC写一个Controller,先把文件丢对象存储,然后发个消息......后面异步转码审核就行。
面试官老周: 思路对。你说说消息发到哪,如何保证不丢?
Q2(技术衔接:消息队列选型与语义):
面试官老周: 你会选 Kafka / RabbitMQ / Pulsar 哪个?分别适合什么?我们这个"转码任务"更像哪类?
小Y: Kafka吧,吞吐高!Rabbit也行......Pulsar我也略懂一点点。
面试官老周: "略懂"先放一边。那Kafka如何做"至少一次"和幂等?
Q3(数据一致性:DB + MQ + 幂等):
面试官老周: 上传成功要写DB(视频表、任务表),同时发消息。你如何避免"DB成功但消息没发出去/发出去了但DB回滚"?
小Y: 这个......可以加事务?Spring事务一开就行吧。或者用分布式事务......
面试官老周: (沉默两秒)你说的太"大"。这里你更希望讲 Outbox/本地消息表 或者 事务消息。继续。
Q4(缓存与热点:视频详情页):
面试官老周: 视频详情页QPS很高。你用 Redis + Spring Cache/Caffeine 怎么做两级缓存?如何防穿透、击穿、雪崩?
小Y: Redis我熟!加缓存、加过期时间、防穿透用布隆过滤器......击穿加互斥锁......雪崩就随机过期!
面试官老周: 不错,回答比较像"活人"。那你会怎么设计Key?
第二轮:微服务治理------高可用、限流熔断、安全
Q1(架构推进:微服务拆分与通信):
面试官老周: 现在有 Upload-Service、Transcode-Service、Audit-Service、Feed-Service。你会用 OpenFeign + Spring Cloud 还是 gRPC/Thrift?在什么场景换?
小Y: Feign开发快嘛,gRPC性能好......我觉得都可以,看心情。
面试官老周:(微笑)我们不看心情,看延迟、吞吐、IDL约束。那你说说gRPC适合的理由。
Q2(稳定性:Resilience4j):
面试官老周: Audit-Service偶发慢导致链路堆积。你会用 Resilience4j 做哪些保护?限流、重试、舱壁、熔断怎么配合?
小Y: 我一般就......加个重试?多试几次总会成功。
面试官老周: 重试是把双刃剑。那在下游慢的时候,重试会带来什么后果?
Q3(安全:JWT/OAuth2/Spring Security):
面试官老周: 用户上传必须鉴权。我们有App、Web、小程序。你如何用 Spring Security + OAuth2/JWT 做统一登录?JWT放哪里?如何续期?
小Y: JWT就是一个token嘛,放Header里。续期......就让用户重新登录?
面试官老周:(叹气)能跑,但体验差。你至少讲出Refresh Token或滑动过期。
Q4(数据层:MyBatis/Hibernate + HikariCP + 迁移工具):
面试官老周: 任务表写入很频繁。你会选 MyBatis 还是 JPA/Hibernate ?连接池用 HikariCP 的关键参数怎么配?用 Flyway/Liquibase 如何做灰度变更?
小Y: MyBatis写SQL直观,JPA也能用......Hikari参数就默认吧,Flyway就是跑脚本。
面试官老周: 默认不等于最优。你至少要知道maxPoolSize、connectionTimeout、leakDetectionThreshold的意义。
第三轮:可观测性 + 大数据检索 + Spring AI/RAG(从"能用"到"能解释")
Q1(链路追踪与指标):
面试官老周: 线上说"上传后审核卡住"。你如何用 Micrometer + Prometheus/Grafana 看指标,用 Jaeger/Zipkin 做链路追踪?日志用 SLF4J + Logback/Log4j2 + ELK 怎么串起来?
小Y: 就加日志嘛,出了问题grep一下......Prometheus我也用过,Grafana画个图。
面试官老周: 你这回答像"运维同学的噩梦"。请说具体:你会埋哪些指标?traceId怎么贯穿?
Q2(搜索与推荐:Elasticsearch + 语义检索):
面试官老周: 我们要做"搜视频",还要支持"自然语言语义搜索"。你会怎么组合 Elasticsearch 和 向量数据库(Milvus/Chroma/Redis)?
小Y: ES我会倒排。语义检索就是......加个AI模型?把句子变成向量,然后查。
面试官老周: 方向对。那向量怎么来?Embedding模型怎么选?
Q3(Spring AI + RAG + 企业文档问答):
面试官老周: 我们想做"创作者助手":
- 根据平台规则回答"这个视频会不会违规";
- 自动生成标题/标签;
- 引用规则原文,尽量减少AI幻觉。
你会如何用 Spring AI + RAG(检索增强生成) 实现?涉及哪些组件:文档加载、向量化、语义检索、提示填充、聊天会话内存、工具执行框架?
小Y: 这个我最近也在看......就是把文档丢进去,然后问的时候它就会回答,还能引用。提示词写好点就行。
面试官老周:(点头但表情严肃)你需要讲清楚"检索"和"生成"的边界,以及如何让模型必须引用检索到的片段。
Q4(Agent与工具调用):
面试官老周: 如果要做"智能客服系统",需要它能查订单、查违规记录、触发工单。你如何设计 Agent(智能代理) 的工具调用?如何用 MCP(模型上下文协议)/工具调用标准化 扩展能力?
小Y: Agent就是让它自己决定用哪个接口......MCP我知道是个协议,反正接上就能用。
面试官老周:(合上笔记本)行。
面试收尾
面试官老周: 今天先到这。整体看你基础题还行,但架构治理、可观测性和AI落地这块需要更"可落地"的方案。回去等通知吧,我们一周内给结果。
小Y: 好的好的,我回去......再"深入理解一下"。
题目答案与知识点拆解(按轮次对照)
下面给出"面试官期望答案"。小白可以按场景把知识串起来学。
第一轮答案:UGC音视频上传与异步处理
A1:Spring Boot异步处理链路怎么拆
目标: 上传接口快速返回,后续转码/审核异步执行。
典型拆分:
- Upload-Service(同步) :Spring MVC Controller接收上传请求 -> 校验JWT -> 生成videoId -> 将文件上传到对象存储(如S3/OSS/COS) -> 写DB状态为
UPLOADED。 - 发消息(异步触发) :发送
VideoUploadedEvent(videoId, url, userId, ...)到MQ。 - Transcode-Service :消费消息 -> 拉取源文件 -> 转码多码率 -> 产出m3u8/mp4 -> 写DB状态
TRANSCODED-> 发VideoTranscodedEvent。 - Audit-Service :消费转码完成事件 -> 调用内容审核(涉黄涉政+OCR+ASR)-> 更新状态
APPROVED/REJECTED。 - Feed/Index-Service:审核通过后入ES索引、推荐池。
关键点:
- 上传接口要"短事务",避免把转码/审核放在同一请求线程。
- 事件驱动更易扩展:后续加"截图服务/水印服务/封面生成"只需新增消费者。
A2:Kafka/RabbitMQ/Pulsar怎么选;Kafka至少一次与幂等
选型:
- Kafka:高吞吐、顺序性(分区内)、适合日志/事件流/任务分发(转码任务)。
- RabbitMQ:路由能力强(exchange/queue),更适合复杂路由、低延迟中等吞吐。
- Pulsar:分层存储、topic多租户、消费模型灵活,云原生友好。
转码任务特点:
- 写入量大、可追溯、可重放 -> Kafka/Pulsar更合适。
Kafka"至少一次"实现:
- 生产者:
acks=all、retries、enable.idempotence=true(避免重试导致重复写入分区)。 - 消费者:处理成功后再提交offset(手动提交),失败不提交则会重放。
幂等处理:
- 业务侧以
videoId + taskType做幂等键; - 在DB中建唯一索引(如
(video_id, stage)),插入冲突则忽略/更新; - 或使用Redis
SETNX做短期幂等锁(注意过期)。
A3:DB与MQ一致性(避免"写库成功但消息丢")
常见方案:
-
Outbox(本地消息表):
- 在同一个本地事务里:写业务表 + 写outbox表(待发送事件)。
- 由后台任务/CDC(如Debezium)将outbox表事件投递到Kafka。
- 投递成功后标记已发送。
-
事务消息(部分MQ支持):
- 半消息/预提交 -> 本地事务成功再提交消息。
-
最终一致性:
- 允许短暂不一致,靠重试/补偿修复。
为什么不直接"Spring事务包住发消息"?
- MQ不在同一资源管理器内,无法用简单
@Transactional保证跨资源原子性。
A4:Redis + Caffeine两级缓存;穿透/击穿/雪崩;Key设计
两级缓存:
- 本地缓存Caffeine:热点数据,纳秒级访问,适合单机热点。
- 分布式缓存Redis:跨实例共享。
Spring Cache落地:
@Cacheable可用于读多写少场景;复杂场景建议手写缓存逻辑。
三大问题:
- 穿透 (查不存在的key):
- 布隆过滤器(Guava BloomFilter或RedisBloom);
- 缓存空值(短TTL)。
- 击穿 (热点key刚好过期,大量请求打到DB):
- 互斥锁(Redis分布式锁)/单飞(singleflight);
- 逻辑过期+异步刷新。
- 雪崩 (大量key同时过期):
- TTL加随机;
- 分批过期;
- 降级兜底。
Key设计示例:
video:detail:{videoId}video:stat:{videoId}(播放数/点赞数)user:profile:{userId}
第二轮答案:微服务治理与安全
B1:OpenFeign vs gRPC/Thrift怎么选
- OpenFeign(HTTP/JSON) :
- 优点:开发效率高、可读性好、易调试;
- 缺点:序列化开销更大、接口契约更松散。
- gRPC(HTTP/2 + Protobuf) :
- 优点:高性能、强IDL、双向流、适合内部高频调用;
- 缺点:调试门槛更高、对网关/浏览器不友好。
何时换gRPC:
- 内部服务间调用量巨大、对延迟敏感(如推荐特征服务、转码回调链路)。
B2:Resilience4j如何组合限流/重试/舱壁/熔断
常见组合:
- 限流 RateLimiter:保护自身线程/下游容量。
- 舱壁 Bulkhead:隔离资源(线程池/并发量),防止一个慢接口拖垮全局。
- 熔断 CircuitBreaker:错误率/慢调用比例超阈值就快速失败,避免堆积。
- 重试 Retry:只对幂等请求、可恢复错误使用;与熔断配合(先限流/舱壁,再重试)。
为什么"只加重试"危险:
- 下游已慢/已崩,重试会放大流量,形成"重试风暴"。
B3:Spring Security + OAuth2/JWT统一登录;续期
典型做法:
- 统一认证中心(可用Keycloak或自建)签发:
- Access Token(JWT) :短有效期(如15min),放
Authorization: Bearer xxx; - Refresh Token:长有效期(如7天),用于换新access token。
- Access Token(JWT) :短有效期(如15min),放
续期策略:
- Refresh Token换取新Access Token(静默续期);
- 或滑动过期(谨慎,需防盗用)。
JWT安全点:
- 签名算法与密钥管理;
- token撤销(黑名单/短时token + refresh轮换);
- 防重放(jti + 存储校验可选)。
B4:MyBatis vs JPA;HikariCP参数;Flyway灰度
ORM选择:
- MyBatis:高频写、复杂SQL、性能可控。
- JPA/Hibernate:领域建模强、CRUD效率高,但需注意N+1、脏检查开销。
HikariCP关键参数:
maximumPoolSize:最大连接数(与DB承载、线程数匹配)。minimumIdle:最小空闲连接。connectionTimeout:获取连接超时时间。idleTimeout/maxLifetime:避免连接被服务端断开导致异常。leakDetectionThreshold:连接泄漏检测。
Flyway/Liquibase灰度:
- 变更脚本可版本化;
- 先加字段/表(向前兼容)-> 双写/兼容读 -> 再删旧字段(向后清理);
- 配合发布节奏,避免"先发代码后发DDL"造成故障。
第三轮答案:可观测性 + 搜索 + Spring AI/RAG
C1:Micrometer/Prometheus/Grafana + Jaeger/Zipkin + ELK怎么联动
指标(Metrics):
- 使用 Micrometer 统一埋点:
- HTTP请求:QPS、延迟P95/P99、错误率;
- 线程池/队列:活跃线程、队列长度;
- MQ消费:lag、处理耗时;
- 业务指标:上传成功数、转码成功率、审核通过率。
- Prometheus 抓取
/actuator/prometheus。 - Grafana 展示看板与告警。
链路追踪(Tracing):
- 使用OpenTelemetry或Spring Cloud Sleuth(视版本)生成
traceId/spanId。 - trace通过HTTP header(如
traceparent)在服务间传递。 - 上报到 Jaeger/Zipkin,定位卡点(哪个span耗时)。
日志(Logging):
- 统一用 SLF4J 门面,落地Logback/Log4j2。
- 日志中打印
traceId(MDC),便于从日志反查链路。 - 采集到 ELK(Filebeat -> Logstash -> Elasticsearch -> Kibana)。
C2:Elasticsearch + 向量数据库实现"关键词+语义"混合检索
混合检索方案:
- 关键词检索:ES倒排索引(标题、标签、ASR文本、OCR文本)。
- 语义检索 :
- 用Embedding模型把文本(query与文档)转向量;
- 存入向量库(Milvus/Chroma/Redis Vector)或ES向量能力;
- 通过向量相似度召回topK。
- 融合排序 :
- 关键词得分(BM25)+ 向量相似度 + 业务特征(热度/时效/作者权重)。
向量从哪来:
- 文档侧:视频标题、简介、评论摘要、ASR转写内容;
- query侧:用户自然语言。
Embedding模型选择:
- 兼顾成本与效果:可用OpenAI/本地Ollama等;
- 中文场景关注中文语义能力与维度;
- 需要离线批量向量化 + 增量更新。
C3:Spring AI + RAG实现"规则问答+引用+降幻觉"
RAG核心链路:
- 文档加载(Document Loading):加载平台规则/审核规范(PDF、Wiki、网页、数据库)。
- 切分(Chunking):按段落/标题切chunk,保留来源元数据(章节、链接)。
- 向量化(Embedding):用Embedding模型把chunk转向量。
- 存储(Vector Store):Milvus/Chroma/Redis等。
- 检索(Retrieval):根据用户问题检索topK相关chunk。
- 提示填充(Prompt Template):把检索到的chunk塞进prompt,让模型"仅基于材料回答"。
- 生成(LLM):输出答案,并要求列出引用来源。
- 聊天会话内存(Memory):保存上下文(用户是谁、视频类型、历史问题),避免重复问。
降低幻觉策略:
- Prompt中强约束:
- "若材料不足,请回答不知道并建议补充信息";
- "必须引用提供的条款编号/原文片段"。
- 输出结构化:结论 + 引用 + 风险点。
- 评测与监控:抽样人工校验、对抗测试。
C4:Agent工具调用 + MCP/标准化扩展
Agent适用场景:
- 需要"多步决策 + 调多个系统工具":查订单、查违规、创建工单、退款等。
设计要点:
- 工具清单(Tools):每个工具定义输入/输出Schema(如订单查询、工单创建)。
- 工具执行框架:由Agent决定调用哪个工具,系统负责安全执行与审计。
- 权限与风控:不同用户/角色可调用的工具不同;敏感操作要二次确认。
- MCP/工具调用标准化 :
- 让"模型端"以统一协议发现与调用工具;
- 便于扩展更多企业内部系统;
- 支持客户端-服务器架构,工具服务可独立部署。
完整学习路径建议:先把"事件驱动 + 一致性 + 缓存"打牢,再补"可观测性与治理",最后落到"RAG/Agent工程化"。