谢飞机面Java大厂:音视频场景下的Spring Boot + Kafka + Redis实战三连问
面试官:张工,某一线大厂音视频中台资深架构师(黑眼圈深、咖啡杯不离手)
求职者:谢飞机,三年Java经验,简历写着"精通Spring全家桶",实际靠Ctrl+C/V活到今天 🛩️
🌟 第一轮:音视频上传链路------从HTTP到异步解耦
面试官(翻简历,微笑):谢同学,你们做过短视频上传功能吗?用户点"发布"后,后端怎么处理?
谢飞机 (自信):当然!用Spring Boot写个@PostMapping("/upload"),接MultipartFile,存到本地磁盘或OSS......
面试官(点头):很好。那如果10万用户同时上传,且要生成封面、转码、打标、审核------你还敢同步处理吗?
谢飞机(挠头):呃......好像会卡死?
面试官:对。那你怎么解耦?
谢飞机(灵光一闪):啊!用消息队列!比如......Kafka?
面试官(赞许):✅ 正确。为什么选Kafka,而不是RabbitMQ或RocketMQ?
谢飞机(支吾):因为......它名字带'k'?(小声)......或者......吞吐高?
🌟 第二轮:实时性与一致性------Redis在音视频元数据中的妙用
面试官:上传成功后,前端要立刻显示"已提交,正在处理",并查进度条。你用什么存这个状态?DB?
谢飞机 :MySQL加个status字段呗......
面试官:如果每秒5000次进度查询呢?
谢飞机(冒汗):......那......Redis?
面试官(赞许):✅ 正确。那用String还是Hash?过期时间设多久?怎么避免缓存穿透?
谢飞机:String......30分钟?穿透?是不是......加个空值缓存?
面试官(轻笑):接近了。那如果用户刷新太快,频繁查同一key,但后端还没写入Redis------你如何保证"最终一致性"?
谢飞机(沉默5秒):......我......先返回个默认值?
🌟 第三轮:故障与降级------当Kafka积压、Redis宕机时怎么办?
面试官:上线后发现Kafka集群磁盘告警,积压了2小时消息。用户上传成功却一直卡在"处理中"。你第一反应是什么?
谢飞机:重启Kafka?......或者......删掉积压消息?
面试官(摇头):错。这是生产事故。你应该先做三件事:① 熔断上传入口;② 切换为本地文件队列(如Disruptor)临时缓冲;③ 推送降级提示给前端。
谢飞机(眼睛一亮):哦!类似Hystrix?
面试官 :现在Spring Cloud Alibaba用Sentinel更多。那Redis挂了呢?上传流程还能继续吗?
谢飞机:......应该不能查进度了......但上传本身还能走?
面试官 :✅ 对。所以Redis是非核心依赖,必须支持无缓存兜底------比如降级查DB(加读写分离+连接池优化),或引入Caffeine做本地缓存。
💼 终场话术
面试官 (合上笔记本):谢同学,基础概念有认知,对音视频场景的痛点也有直觉,但深度和落地细节还需加强。建议回去把《Kafka权威指南》第4章、《Redis设计与实现》缓存章节、以及Spring Boot官方文档的spring-boot-starter-cache和spring-kafka模块通读两遍,再动手搭个最小可行Demo。
谢飞机(起身握手):谢谢张工!我回去就写!
面试官(微笑):好。我们会在5个工作日内通过邮箱通知你后续安排。祝你------
两人齐声 (玩笑):起飞顺利,不掉帧,不丢包,不OOM! ✈️
📘 【附:小白也能懂的技术解析】
🔹 场景定位:音视频中台的"上传-处理-反馈"闭环
- 业务特征:高并发写(上传)、强实时读(进度)、长耗时异步任务(转码/AI打标)、失败容忍度低(用户感知明显)
- 技术选型逻辑 :
- ✅ Kafka:百万级TPS、分区有序、持久化+副本保障不丢消息,适合"上传事件→触发转码流水线"这类事件驱动架构;RabbitMQ更适合金融类强事务,RocketMQ国内生态好但跨云部署稍重。
- ✅ Redis :用
Hash结构存{video_id: {status:"processing", progress:65, updated_at:"2025-04-05T10:20:00"}},比String更省内存;过期时间设2h(覆盖最长转码时长+缓冲);防穿透用布隆过滤器+空值缓存双保险。 - ✅ 容灾设计 :
- Kafka积压 →
Sentinel配置QPS阈值自动熔断/upload接口,同时启用@Async本地队列作为fallback; - Redis宕机 →
@Cacheable(cacheNames="videoStatus", unless="#result == null")注解自动降级到JdbcTemplate查MySQL,配合HikariCP连接池max-lifetime=1800000防连接老化。
- Kafka积压 →
🔹 关键代码片段(Spring Boot 3.x + Kafka 3.6 + Redis 7)
java
// 1. 发送上传事件(异步解耦)
public void onVideoUploaded(VideoUploadEvent event) {
kafkaTemplate.send("video-upload-topic", event.getVideoId(), event);
}
// 2. Redis进度管理(使用StringRedisTemplate + Hash)
public void updateProgress(String videoId, int progress) {
String key = "video:status:" + videoId;
redisTemplate.opsForHash().put(key, "progress", String.valueOf(progress));
redisTemplate.expire(key, Duration.ofHours(2)); // 自动过期
}
// 3. 容错降级:Redis异常时查DB
@Cacheable(value = "videoStatus", key = "#videoId", unless = "#result == null")
public VideoStatus getStatusFromCache(String videoId) {
return redisService.getStatus(videoId); // 可能抛异常
}
@Cacheable(value = "videoStatus", key = "#videoId", cacheManager = "fallbackCacheManager")
public VideoStatus getStatusFromDb(String videoId) {
return jdbcTemplate.queryForObject(
"SELECT status, progress FROM video_task WHERE video_id = ?",
new Object[]{videoId},
(rs, _) -> new VideoStatus(rs.getString("status"), rs.getInt("progress"))
);
}
💡 学习建议:不要死记API!重点理解------每个技术组件在该业务链路中解决什么本质问题?替代方案为何不合适?出问题时谁兜底?
📌 延伸思考题(自测用):
- 如果要求"用户上传后3秒内必须返回进度条",Kafka是否还适用?应改用什么?
- Redis用作进度存储,如何避免多实例部署时的并发覆盖?(Hint:Lua脚本 or Redisson分布式锁)
- Spring Boot整合Kafka时,
enable.auto.commit=false为什么要手动acknowledge.acknowledge()?不这么做会怎样?
✅ 本文覆盖技术栈:
- Web框架:Spring Boot
- 消息队列:Kafka
- 缓存技术:Redis
- 监控与运维:(隐含)通过Kafka Lag监控+Redis INFO指标实现可观测性
- 微服务治理:Sentinel熔断降级
- 构建工具:Maven(默认)
- 测试框架:JUnit 5 + Mockito(可为上述逻辑补单元测试)
欢迎评论区讨论你的答案 👇