Java大厂面试实录:Spring Boot + Kafka + Redis 在电商秒杀场景下的应用与坑点

Java大厂面试实录:Spring Boot + Kafka + Redis 在电商秒杀场景下的应用与坑点

面试官:资深架构师 | 谢飞机:自学成才的“注解型”程序员


🎬 面试场景设定:电商大促秒杀系统设计

某互联网大厂正在搭建“618”大促秒杀平台,要求高并发、低延迟、防超卖。面试官围绕此业务背景,对候选人谢飞机展开三轮技术拷问。


🔹 第一轮:基础构建 —— 从项目搭建到核心组件选型

Q1:如果让你用 Spring Boot 搭建一个秒杀服务,你会怎么组织项目结构?依赖怎么管理?

谢飞机:呃……我一般直接去 start.spring.io 创建项目,勾选 Web、JPA、Redis 就行了!Maven 管依赖,pom.xml 自动搞定~

面试官(点头):还行,至少知道脚手架和 Maven。但要注意版本对齐,比如 Spring Boot 3.x 要求 Java 17+,别在生产环境用快照版。


Q2:为什么选择 Redis 而不是本地缓存如 Caffeine 来存库存?

谢飞机:因为……Redis 快啊!还能持久化!而且我们老师说“缓存必须上 Redis”,不然不高级!

面试官(微微一笑):方向没错,但没说到点子上。关键在于分布式一致性。多台机器部署时,本地缓存无法同步库存扣减,会导致超卖。而 Redis 是集中式存储,配合 Lua 脚本可实现原子扣减。


Q3:数据库连接池你用过哪些?HikariCP 为什么是 Spring Boot 默认?

谢飞机:我只用过默认的,没改过配置……HikariCP 听起来像日语,可能是因为日本人写得快?

面试官(忍住笑):它确实是日本人写的,但“快”不只是语言优势。HikariCP 的核心是极致优化——基于字节码增强、轻量锁、无垃圾回收设计,在高并发下性能碾压其他池(如 C3P0)。这也是为何 Spring Boot 2.x 开始将其设为默认。

小结:第一轮过关,基础尚可,但缺乏深度思考。


🔹 第二轮:进阶挑战 —— 并发控制与消息削峰

Q4:用户抢购时大量请求涌入,数据库扛不住怎么办?如何用 Kafka 削峰?

谢飞机:这个我知道!加 Kafka!所有请求先发到 Kafka,然后慢慢消费,就像……早高峰地铁限流!

面试官:比喻不错。具体流程呢?

谢飞机:呃……前端调接口 → 写入 Kafka → 消费者读出来 → 扣库存?

面试官:接近了。正确姿势是:

  1. 秒杀接口校验通过后,将订单请求封装为消息投递至 Kafka Topic;
  2. 异步消费者组从 Topic 拉取,执行最终落库;
  3. 用户端返回“排队中”,通过 WebSocket 或轮询查结果。

⚠️ 注意:不能把数据库压力转移到 Kafka 生产者!需前置限流(如令牌桶)、幂等处理、防止重复下单。


Q5:Kafka 如何保证消息不丢失?尤其是在宕机情况下?

谢飞机:嗯……Kafka 很稳定,很少丢数据吧?

面试官:这不是答案。要从三个层面保障:

  • Producer:设置 acks=all,确保 ISR 全体副本确认;
  • Brokerreplication.factor >= 3min.insync.replicas=2
  • Consumer:手动提交 offset,且在业务处理成功后再提交。

否则,自动提交可能导致“消息已消费但未落库”的悲剧。


Q6:如果多个消费者同时消费同一个商品的消息,会不会重复扣减库存?

谢飞机:那……可以让只有一个消费者?或者加 synchronized?

面试官:synchronized 只能在单机生效。分布式环境下要用:

  • Kafka 分区策略:相同商品 ID 映射到同一 Partition,确保单消费者线程处理;
  • 数据库乐观锁UPDATE stock SET count = count - 1 WHERE id = ? AND count > 0
  • 或使用 Redis 分布式锁(如 Redlock),但注意复杂性和性能损耗。

🚫 切忌盲目加锁,影响吞吐量。


🔹 第三轮:高阶陷阱 —— 缓存一致性与安全防护

Q7:Redis 中库存为 0 后,数据库还没更新完,这时来了新请求怎么办?

谢飞机:哦!我知道!这就是缓存穿透!要用布隆过滤器!

面试官(皱眉):你搞混了。这是缓存与数据库不一致问题。你说的布隆过滤器是用来防“查不存在的商品ID”的。

当前情况应采用:

  • 双写一致性:更新数据库后,主动失效 Redis 缓存(Cache Aside Pattern);
  • 延迟双删:删除缓存 → 更新 DB → 延迟几百毫秒再删一次,应对主从复制延迟;
  • 订阅 binlog(如 Canal):监听 MySQL 变更,异步刷新缓存,实现最终一致。

Q8:如何防止脚本恶意刷单?比如有人用 JMeter 模拟万人抢购。

谢飞机:加验证码呗!图形验证码、滑动验证码都行!

面试官:可以,但不够。还需:

  • 接口级限流(如 Resilience4j 限流器,每秒最多 1000 次);
  • 用户行为分析(如登录态、设备指纹、IP 黑名单);
  • 商品维度限流(每人限购一件);
  • 前端混淆 + HTTPS 加密防抓包。

安全是个体系,不能只靠验证码“守门”。


Q9:整个链路监控怎么做?比如某个请求卡住了,怎么定位?

谢飞机:看日志……Logback 输出 info……不行就 debug 断点?

面试官:生产环境不能 debug!你应该:

  • 使用 SkyWalking / Zipkin 做分布式追踪,通过 TraceID 串联全流程;
  • 集成 Prometheus + Grafana 监控 QPS、响应时间、错误率;
  • 日志统一收集到 ELK,便于搜索异常堆栈;
  • 关键指标设置告警(如 Kafka Lag > 1000 触发企业微信通知)。

这才是可观测性三大支柱:Logging, Tracing, Metrics。


✅ 面试尾声

面试官:今天的问题就到这里。你的基础知识还有提升空间,尤其对原理理解不够深入。不过思维活跃,有潜力。

谢飞机:那……我是过了吗?

面试官(微笑):回去等通知吧。


💡 最终解析:技术点全景图

🎯 业务场景:电商秒杀系统

目标:支撑百万级 QPS 抢购,防止超卖、保障用户体验、系统稳定。

🧩 技术架构图(简化)

用户请求 → Nginx 负载均衡 → API Gateway(限流/鉴权)
                             ↓
                   Spring Boot 应用集群
                             ↓
        ┌──────────── Redis(库存缓存) ← Canal ← MySQL
        │                    ↑
        ↓                    ↓
   Kafka(消息队列) ← 秒杀请求
        ↑                    ↓
        └── 消费者服务 → 数据库落单

🔍 核心技术点总结

| 技术栈 | 作用 | 最佳实践 | |--------|------|-----------| | Spring Boot | 快速构建微服务 | 使用 Starter 统一管理依赖 | | Redis | 高速库存访问、分布式锁 | 使用 Lua 脚本保证原子性 | | Kafka | 请求削峰、异步解耦 | 设置合理分区数,避免热点 | | MySQL + JPA/Hibernate | 持久化订单 | 乐观锁防超卖 | | HikariCP | 数据库连接池 | 合理配置最大连接数 | | Resilience4j | 限流降级 | 定义规则保护核心资源 | | Prometheus + Grafana | 系统监控 | 自定义 Dashboard | | Zipkin/SkyWalking | 链路追踪 | 注解或 Agent 注入 TraceID | | Flyway/Liquibase | 数据库版本控制 | CI/CD 中自动执行 |

📚 学习建议

  1. 不要停留在“会用”,要探究“为什么”;
  2. 多画架构图,理清组件关系;
  3. 动手搭建迷你项目(如 mini-seckill),跑通全流程;
  4. 阅读官方文档,特别是 Spring 和 Kafka 的 Reference Guide。

🌟 记住:面试不是背八股,而是展现你解决问题的能力。

—— 本文献给每一位在深夜调试代码、准备面试的你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值