Java大厂面试实录:Spring Boot + Redis + Kafka + Spring Security 全链路实战(谢飞机版)
Java大厂面试实录:Spring Boot + Redis + Kafka + Spring Security 全链路实战(谢飞机版)
面试官严肃如铁,谢飞机可爱如谜——一场让HR笑出腹肌、让技术总监默默记笔记的面试
🌟 第一轮:基础稳不稳?——音视频社区登录与用户态管理
面试官(推了推眼镜,目光如炬):谢同学,请坐。我们先从最贴近用户的一环开始:假设你在开发「弹幕音视频社区」App 的后端,用户登录后要实时加载头像、昵称、会员等级、未读消息数——这四个字段分别来自不同微服务。你怎么设计登录态?为什么不用 Session?
谢飞机(挠头):啊…Session 是存在服务器内存里的,集群下要同步,麻烦!我用 JWT!把用户 ID、角色、过期时间塞进去,签名加密,前端存在 localStorage,每次请求带在 Authorization: Bearer xxx 里…(小声)其实我抄过 Spring Security + JWT 的 demo…
面试官(点头):很好,那 JWT 的密钥怎么管理?如果 Token 泄露,如何快速失效?
谢飞机(眼睛一亮):密钥放配置中心!比如 Nacos,不硬编码!失效…呃…(掰手指)可以用 Redis 存个黑名单?比如 blacklist:token:xxx,设个和 JWT 一样的过期时间!
面试官(嘴角微扬):✅ 正确。补充一句:这就是「无状态认证 + 有状态注销」的经典平衡。你答得比简历写得扎实。
面试官:最后一个问题——登录成功后,首页要查「最近3条热门弹幕」,数据来自 Kafka 消费的实时埋点流。你会用哪种消费模式?为什么不用 @KafkaListener 直接处理并返回给前端?
谢飞机(挺胸):不能!那是异步的!我要的是「同步响应」!所以…我让登录接口只查 Redis 缓存的 hot_danmu:latest,这个 key 由一个独立的 Kafka Consumer Service 持续更新——它消费弹幕日志,聚合 TOP3,定时刷进 Redis!(拍桌)缓存+异步解耦,稳!
面试官(记录):✔️ 理解分层职责。进入第二轮。
🌟 第二轮:架构深不深?——AIGC内容审核微服务链路
面试官:现在业务升级:用户上传 AI 生成的图文内容,需经「敏感词过滤 → 图像鉴黄 → 文本语义风险识别」三级审核。三个服务独立部署,调用链路必须可追踪、可熔断、可降级。请画出核心流程,并说明技术选型。
谢飞机(掏出马克笔,在白板上狂画):
[User Upload]
↓ (Feign + LoadBalancer)
[TextFilter-Service] → (OpenFeign + Resilience4j fallback)
↓ (gRPC 同步调用,因图像识别耗时长且需二进制传输)
[ImageAudit-Service] → (gRPC streaming 支持大图分块)
↓ (RabbitMQ 异步发结果,解耦 + 削峰)
[SemanticRisk-Service] → (监听 MQ,完成再回调 TextFilter 更新 DB)
↓
[Update Content Status in MySQL via MyBatis]
面试官(挑眉):为什么文本用 Feign,图像用 gRPC?
谢飞机:Feign 是 HTTP/JSON,适合轻量文本;gRPC 是 HTTP/2 + Protobuf,序列化快、带宽省、支持流式——传 5MB 的图,JSON 序列化会胖3倍!而且…(压低声音)我们用的是 Quarkus + gRPC,启动只要 80ms!
面试官:监控呢?如果 ImageAudit-Service 响应 P99 达到 8s,你怎么第一时间发现?
谢飞机(秒答):Micrometer 打点!暴露 /actuator/metrics,配 Prometheus 抓,Grafana 做告警看板!我还加了 @Timed 注解在 gRPC 方法上…(眨眨眼)老板说这是「可观测性基本素养」。
面试官(微笑):第三轮,我们聊聊「活下来」的事。
🌟 第三轮:生死线在哪?——电商大促下的库存超卖与资损防控
面试官:双十一大促,商品 A 剩余库存 100 件。瞬间 5000 请求并发扣减。若用传统 SELECT ... FOR UPDATE,数据库直接堵死。你的方案?
谢飞机(深呼吸):三重防护!
1️⃣ Redis 预减库存:DECR stock:A,为负则拒绝,毫秒级拦截 99% 流量;
2️⃣ Lua 脚本原子执行:if redis.call('GET', KEYS[1]) >= ARGV[1] then ... end,防 Redis 主从延迟导致的超卖;
3️⃣ 最终一致性校验:异步落库前,再查 MySQL 库存(加 SELECT ... FOR UPDATE),不一致则发告警 + 补单!
面试官:如果 Redis 挂了?
谢飞机(认真):就切到「本地缓存 + 限流」!用 Caffeine 做二级缓存,Guava RateLimiter 控制每秒最多 200 单,同时触发 Sentinel 熔断,降级返回「系统繁忙,请稍后再试」——宁可少卖,绝不资损!
面试官:最后一问:订单创建成功后,要发短信、写 Elasticsearch、推送 App Push。这三个操作,哪个必须强一致?哪个可以最终一致?为什么?
谢飞机(掰手指数):
- ✅ 写 ES 必须最终一致:用 Canal 监听 MySQL binlog,异步同步,丢一条不影响交易;
- ✅ App Push 最终一致:MQ 保证至少一次,失败重试 + 死信队列人工兜底;
- ❗ 短信发送必须强一致?错!其实是「业务最终一致」:我们用「状态机 + 定时补偿」——订单表加
sms_status字段,定时任务扫status=created AND sms_status=pending的单,调短信网关重发。既不阻塞主链路,又确保100%触达!
面试官(合上笔记本,起身握手):谢同学,你对技术的敬畏感、对业务的理解力、对故障的想象力,远超同龄人。回去等通知吧。顺便——(递上一张印着「谢飞机·准高级工程师」的卡通工牌)这是 HR 提前给你的纪念品。
📚 附录:标准答案与学习指南(小白友好版)
Q1:JWT 黑名单如何高效实现?
✅ 答案:用 Redis 的 SET key value EX seconds 存 token,key 设为 blacklist:token:${jwtId};验证时 EXISTS blacklist:token:${jwtId}。注意:JWT 自带 jti 字段作唯一ID,务必开启!
💡 小白学:别存全Token(太长),只存 jti;用 EX 而非 EXPIRE,避免时钟漂移。
Q2:Kafka 消费为何不能直接同步返回?
✅ 答案:@KafkaListener 是纯异步事件驱动模型,方法返回值不参与 HTTP 响应体。HTTP 接口必须同步返回,因此需「预加载缓存」+「异步刷新」解耦。
💡 小白学:记住口诀——“请求要快,消费要稳,缓存是桥”。
Q3:gRPC vs Feign 选型逻辑?
✅ 答案:
- Feign:HTTP/1.1 + JSON,调试友好,适合服务间轻量文本交互;
- gRPC:HTTP/2 + Protobuf,性能高、天然支持流、跨语言强,适合高性能/二进制/流式场景(如音视频、AI推理)。
💡 小白学:Protobuf 不是 JSON!它是二进制协议,.proto文件定义结构,自动生成代码,体积小、解析快。
Q4:Redis 预减库存为何要 Lua?
✅ 答案:Redis 单命令原子,但「判断 + 减」是两步!网络延迟或主从同步间隙会导致超卖。Lua 在服务端原子执行,规避竞态。
💡 小白学:把 Lua 当成 Redis 的“存储过程”,用 redis.call() 串起多条指令,整个脚本要么全成功,要么全失败。
Q5:短信为什么不是强一致?
✅ 答案:强一致要求「所有操作全部成功或全部失败」,但短信网关是外部依赖,不可控。业务上只要「100%送达」即可,用「状态机 + 补偿」比「两阶段提交」更可靠、更简单。
💡 小白学:分布式系统没有银弹,优先保核心(订单),外围用「最终一致+人工兜底」。
🌈 学习路径推荐:
① 先吃透 Spring Boot + Redis + Kafka 三件套(官方 Guides);
② 再学 Spring Security OAuth2 和 Resilience4j 熔断;
③ 最后攻 Micrometer + Prometheus 全链路监控;
④ 所有知识,务必在「本地生活优惠券核销」「在线教育课程抢购」等真实业务场景中动手复现!
💡 文末彩蛋:谢飞机回家路上,用 Lombok 的
@Builder写了个InterviewResult.builder().pass(true).offerAmount(35K).build()——然后被猫按在键盘上,发到了公司全员群…
更多推荐



所有评论(0)