Java大厂面试实录:Spring Boot + Kafka + Redis 多场景联调,谢飞机的三轮闯关之旅

面试官:严肃、逻辑严密、爱画架构图;谢飞机:T恤印着「Hello World」,背包挂着小黄鸭,答对String常量池会比耶,答错ThreadLocal就掏出保温杯猛灌枸杞水。


🌟 第一轮:基础稳不稳?——音视频社区登录链路拆解

面试官(推了推眼镜):谢同学,请结合我们正在做的「弹幕实时互动音视频平台」,说说用户登录后,JWT令牌如何生成、校验、续期?为什么不用Session?Redis在这里起什么作用?

谢飞机(挠头):呃……JWT就是把用户ID、过期时间、签名拼一起加密?用HMAC-SHA256……啊对!因为咱们是微服务,每个服务都要验令牌,Session得存Tomcat里,不好扩展……Redis嘛,我上次在B站看视频,说可以存黑名单——比如用户点“退出登录”,就把这JWT的jti塞进Redis设个过期时间!

面试官(点头微笑):很好!补充一点:我们用spring-security-jwt已停更,现在推荐spring-boot-starter-oauth2-resource-server + JwtDecoder自定义解析;Redis还承担了「令牌续期」缓存——用户每活跃30分钟,就刷新Redis中该token的TTL,实现“滑动过期”。这是典型的无状态认证+有状态吊销组合方案。

面试官:第二个问题:登录成功后,首页要加载「最近观看的5个直播频道」,数据来自MySQL,但QPS峰值超8000。你怎么设计缓存策略?请画出读写流程图。

谢飞机(掏出马克笔在白板画):先查Redis!key是user:${uid}:recent_channels,类型用List……没命中?查DB,再LPUSH + LTRIM 5写回Redis!写DB时——(突然卡壳)那个……更新完DB,是删Redis还是直接SET?

面试官(赞许):你画对了Cache-Aside模式!答案是双删:先删Redis,再更新DB,再休眠100ms,再删一次Redis——防止主从同步延迟导致脏读。我们生产环境用的是Redisson分布式锁+Caffeine本地缓存二级联动,抗住了618大促压测。

面试官:第三题:如果某个频道被下架,怎么保证所有用户端「最近观看列表」实时失效?

谢飞机(眼睛一亮):发MQ!比如Kafka……topic叫channel.status.change,下游消费后,用DEL user:*:recent_channels通配删除?不对不对……(翻包掏手机查)啊!Redis不支持通配删除……那……用SCAN?太慢!

面试官(笑着递上咖啡):聪明!所以我们的方案是:频道下架时,发布事件携带channelId,各服务监听后执行EVAL脚本批量匹配并删除user:*:recent_channels中含该channelId的列表项——用Lua保证原子性。这也是事件驱动架构(EDA)与缓存一致性的经典落地。


🚀 第二轮:进阶能不能?——AIGC内容社区风控中台实战

面试官:现在切入「AI生成图文社区」,用户上传图片触发内容安全扫描(调用内部风控服务),结果异步返回。我们用Spring WebFlux + R2DBC重构了风控中台。请对比传统Spring MVC + MyBatis,说明响应式栈的价值,并指出R2DBC连接池和HikariCP的本质区别。

谢飞机(坐直):WebFlux是单线程非阻塞,像快递分拣流水线——一个工人(EventLoop)能同时盯1000个包裹(请求)!MyBatis是阻塞IO,每个请求占一个Tomcat线程……R2DBC?它不叫“连接池”,叫“连接工厂”!HikariCP管的是JDBC Connection,而R2DBC用的是ConnectionPool,底层是Netty Channel,没有“连接复用”概念,只有“连接生命周期管理”……

面试官(快速记录):精准!再问:风控结果返回后,需触发三件事——①落库审核记录 ②发站内信 ③更新用户信用分。如何保证最终一致性?若发消息失败怎么办?

谢飞机(拍大腿):Saga模式!第一步成功,发Kafka消息;第二步失败?发补偿消息回滚第一步……等等,我们用的是RocketMQ事务消息!Producer发半消息→执行本地事务→发Commit/rollback→Consumer消费→失败就进死信队列人工兜底!

面试官(赞许):正确!我们生产用spring-kafka + @Transactional注解开启事务,配合KafkaTransactionManager,确保DB写入与Kafka发送原子性。Bonus题:若信用分更新涉及分布式事务(跨用户服务),你会选Seata还是XA?为什么?

谢飞机(认真):Seata AT模式!XA锁表太久,我们信用分更新QPS高,AT用全局锁+undo_log,性能好太多……而且我们用Nacos做TC注册中心,比Eureka更轻!


🌐 第三轮:系统行不行?——智慧医疗供应链多云协同

面试官:最后一题,来自我们为三甲医院打造的「医疗耗材智能调度平台」。需求:北京中心仓、上海区域仓、深圳边缘节点(5G医疗车)需实时同步库存。要求:网络分区时本地可写,恢复后自动合并,冲突率<0.1%。技术栈:Spring Cloud Alibaba + Nacos + Sentinel + Kafka + CRDTs。

谢飞机(深呼吸):CRDTs……Conflict-Free Replicated Data Type!比如用G-Counter统计总入库量,每个节点只增不减,合并时取max……但库存是增减都有……啊!用PN-Counter!正数增,负数减,合并时分别sum……

面试官(眼睛发亮):完全正确!我们用LWW-Element-Set(Last-Write-Win)处理“耗材上架/下架”事件,时间戳来自NTP授时+逻辑时钟纠偏。再问:当深圳医疗车断网3小时后重连,如何避免Kafka重复消费导致库存扣减两次?

谢飞机(迅速):消费者手动提交offset!用enable.auto.commit=false,处理完DB+Redis才commitSync()……但万一提交成功、业务失败呢?所以加幂等表——联合event_id + business_id唯一索引!

面试官(起身握手):谢同学,你对技术本质的理解远超简历所写。从JWT到CRDT,从阻塞IO到事件溯源,你展现了扎实的工程直觉和业务抽象能力。尤其能关联“医疗车断网”这种真实约束,非常难得。


面试官(微笑合上笔记本):今天的面试到此结束。请回家耐心等待通知。无论结果如何,希望你继续保持这份对技术的好奇与真诚——毕竟,每个优秀的工程师,都曾是那个一边debug一边啃煎饼果子的谢飞机。


📚 附录:标准答案与学习指南(小白友好版)

Q1:JWT + Redis 实现登录态管理

  • 核心答案:JWT负责无状态认证(Header.Payload.Signature),Redis负责有状态吊销(黑名单)与滑动续期(TTL刷新)。避免Session在微服务间共享难题。
  • 🌐 业务贴合:音视频平台需支撑千万级并发登录,无状态是弹性伸缩前提;弹幕互动要求毫秒级登录态验证,Redis亚毫秒响应完美匹配。
  • 📚 小白学:JWT就像机场登机牌(含身份+有效期+防伪码),Redis是安检黑名单屏——登机牌本身有效,但一旦挂失(退出登录),屏幕立刻标红拦截。

Q2:缓存穿透/击穿/雪崩应对

  • 核心答案
    • 穿透(查不存在数据)→ 布隆过滤器前置拦截 + 空值缓存(SET key "" EX 60
    • 击穿(热点key过期)→ 逻辑过期(Redis值含时间戳)+ 互斥锁(RedissonLock)
    • 雪崩(大量key同时过期)→ 过期时间加随机值(EX 3600 + RANDOM(600)
  • 🌐 业务贴合:直播频道列表是典型热点数据,618期间某头部主播开播,瞬时百万用户刷首页,必须扛住缓存层冲击。
  • 📚 小白学:想象奶茶店——穿透是顾客问“有没有珍珠奶茶”(其实没这品),店员先查菜单(布隆过滤器);击穿是“芋圆波波”卖光了(key过期),后面排队全挤在柜台(锁);雪崩是所有奶茶同时打烊(集体过期),得错峰关门(加随机时间)。

Q3:响应式编程 vs 阻塞式

  • 核心答案:WebFlux基于Netty+Reactor,单线程处理数千连接;MVC基于Servlet容器(如Tomcat),每个请求独占线程(默认200线程池)。R2DBC是纯异步数据库驱动,无连接池概念,而是连接工厂+连接生命周期管理。
  • 🌐 业务贴合:AIGC风控需毫秒级响应(用户不愿等AI审核3秒),且GPU资源昂贵,必须用最少线程榨干CPU/IO。
  • 📚 小白学:MVC像餐厅服务员——每人盯一桌(线程=服务员),客人多就雇更多人(线程池扩容);WebFlux像自助餐——1个阿姨(EventLoop)管100个取餐口(连接),谁取完谁走,阿姨永远不闲着。

Q4:最终一致性保障

  • 核心答案:优先选可靠事件队列(Kafka事务消息) + 本地事务表 + 死信队列人工干预。避免分布式事务(Seata/XA)的复杂性与性能损耗。
  • 🌐 业务贴合:医疗风控结果影响用户发帖权限,必须100%可靠;但信用分计算可容忍秒级延迟,最终一致即可。
  • 📚 小白学:就像快递发货——你下单(本地事务)→ 快递公司打单(发Kafka)→ 若打单失败,系统自动重试3次,再失败就发短信让你手动补发(死信告警)。

Q5:多活库存与CRDT

  • 核心答案:CRDT是无需协调的最终一致性数据结构。医疗场景选LWW-Element-Set(最后写入获胜),因“上架/下架”操作天然有时序性;用Nacos同步逻辑时钟,解决设备时钟漂移。
  • 🌐 业务贴合:5G医疗车在山区断网是常态,必须支持离线作业;恢复后库存自动收敛,避免护士手工对账。
  • 📚 小白学:想象多人编辑在线文档——你删一行,我删同一行,CRDT保证最终都删掉,且不打架。库存就是“谁最后点下架按钮,谁说了算”。

💡 延伸学习路径
1️⃣ JWT → RFC 7519 + Spring Security官方文档
2️⃣ Redis缓存 → 《Redis设计与实现》第11章 + 阿里云Redis最佳实践
3️⃣ WebFlux → Spring Framework 5.0 Release Notes + Project Reactor官网
4️⃣ Kafka事务 → Confluent官网《Exactly Once Semantics》
5️⃣ CRDT → 《Designing Data-Intensive Applications》第9章 + crdt.io


本文由CSDN「Java面试研究所」出品 | 所有案例均源自真实大厂架构演进,拒绝纸上谈兵

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐