谢飞机面Java大厂:电商秒杀场景下的Spring Boot + Redis + Kafka + Sentinel全链路面试实录(附小白级技术解析)

面试官:严肃、眼神锐利、笔记本上密密麻麻记着“QPS/缓存雪崩/消息堆积”; 谢飞机:T恤印着“Hello World”,左手捏半块饼干,右手点开手机备忘录——里面只有一行字:“Spring Boot启动类加@SpringBootApplication”。


🌟 第一轮:从「用户点下秒杀按钮」开始——基础链路与性能瓶颈

面试官(微笑):谢同学,假设你在某头部电商平台做秒杀系统。用户点击“立即抢购”后,请求首先进入哪个组件?请描述典型调用链。

谢飞机(挺直腰板):“啊!这个我会!前端Vue发HTTP请求→Nginx负载均衡→Spring Boot的Controller→Service→Mapper→MySQL!”

面试官点头:“很好,路径清晰。那如果10万人同时点,MySQL直接扛不住,你怎么提前拦住无效流量?”

谢飞机(挠头):“呃……加个if判断?比如‘if (库存 > 0) { 扣减 }’?”

❌ 面试官轻笑:“这叫‘事后拦截’,不是‘事前防护’。再想想——哪个层最靠近用户、成本最低、响应最快?”

谢飞机(灵光一闪):“哦!Redis!先查缓存库存!对对对,我背过——decr原子扣减!”

面试官赞许:“非常棒!Redis预减库存是秒杀第一道闸门。那如果缓存里根本没这个商品key呢?”

谢飞机(卡壳):“……啊?那就…查DB?然后塞进去?但万一很多人一起查DB…”

💡 面试官引导:“这就引出经典问题——缓存穿透。你打算怎么防?”


🌟 第二轮:当流量洪峰撞上系统——高可用加固实战

面试官:假设Redis缓存穿透被绕过,大量请求击穿到DB,且DB已出现慢SQL。此时你如何避免整个订单服务雪崩?

谢飞机(咽口水):“呃…重启服务?或者…加服务器?”

❌ 面试官摇头:“扩容是兜底,不是设计。我们讲主动防御——比如用Sentinel做熔断降级。”

谢飞机(眼睛一亮):“Sentinel!我知道!控制台能看QPS,还能设阈值!”

面试官追问:“设阈值容易,关键是怎么定义‘失败’?是HTTP 500?还是数据库超时?还是Feign调用延迟>800ms?”

谢飞机(犹豫):“应该…是接口返回时间?或者…异常次数?”

💡 面试官补充:“对,Sentinel支持基于RT(响应时间)、异常比例、QPS多维度规则。那如果降级了,用户看到什么?”

谢飞机(自信):“返回‘秒杀太火爆,请稍后再试’!我写过fallback方法!”

面试官点头:“很好。那下一个问题——秒杀成功后,要发短信、更新物流、推送APP通知,这些操作不能阻塞主流程。你怎么解耦?”

谢飞机(脱口而出):“Kafka!异步发消息!生产者发完就干别的,消费者慢慢处理!”

面试官微笑:“完全正确。那如果Kafka突然挂了,消息丢了怎么办?”

谢飞机(声音变小):“……重发?或者…本地存个日志?”


🌟 第三轮:从单体到云原生——可观测性与弹性交付

面试官:现在系统拆成了秒杀服务、库存服务、通知服务三个Spring Cloud微服务。上线后发现秒杀接口P99延迟从200ms飙升到2s,你第一步查什么?

谢飞机(认真):“看日志!Logback打印的info日志!”

❌ 面试官:“日志太多,grep不过来。有没有更结构化、可聚合、带链路ID的方式?”

谢飞机(思考状):“……SkyWalking?或者…Jaeger?”

面试官赞许:“Jaeger+Zipkin是分布式追踪标配。那追踪到某个库存服务调用HikariCP连接池超时,你如何确认是不是连接泄漏?”

谢飞机(挠头):“看Druid监控页面?或者…配置leakDetectionThreshold?”

面试官追问:“不错!那最后一个问题——你们用GitHub Actions做CI/CD,如何保证每次发布的秒杀服务镜像,都包含本次修复的Sentinel规则和最新Kafka Topic配置?”

谢飞机(支吾):“Dockerfile里…COPY配置文件?或者…用ConfigMap挂载?”

💡 面试官总结:“这是Kubernetes ConfigMap + Spring Cloud Kubernetes的典型实践。把动态配置外置,镜像做到一次构建、处处运行。”


🚪 面试尾声

面试官合上笔记本,微笑道

“谢同学,基础框架认知扎实,对Redis/Kafka/Sentinel有动手意识,也暴露了在可观测性治理、配置中心落地、故障根因定位上的经验空白。这恰恰是我们团队新项目最需要补强的方向——欢迎加入我们的秒杀中台二期攻坚组。回去等HR电话吧。”

(谢飞机起身握手,饼干渣掉在面试官笔记本上,面试官低头看了一眼,没说话,默默用纸巾擦掉。)


📚 【附:全问题技术解析|小白也能看懂】

🔹 Q1:为什么秒杀要先查Redis再查DB?

业务场景:电商大促期间瞬时流量可达百万QPS,MySQL单机极限约3k TPS,无法承载。 技术点

  • Redis作为内存数据库,读写性能达10w+ QPS,天然适合作为“前置过滤器”;
  • 使用INCRBY/DECRBY命令实现库存原子扣减,避免并发超卖;
  • 配合SETNX设置空值缓存(如cache_null_1001)+ 过期时间,防御缓存穿透。

🔹 Q2:Sentinel如何防止雪崩?降级策略怎么写?

业务场景:库存服务依赖下游支付服务,若支付服务宕机,秒杀接口持续等待导致线程池耗尽。 技术点

  • Sentinel定义资源(如@SentinelResource("seckill-order")),配置规则:
    // RT > 800ms 或 异常比例 > 30%,触发降级,走fallback
    DegradeRule rule = new DegradeRule("seckill-order")
        .setGrade(RuleConstant.DEGRADE_GRADE_RT)
        .setCount(800).setTimeWindow(10);
    
  • fallback方法返回友好提示或兜底数据(如“排队中”页),保障用户体验不中断。

🔹 Q3:Kafka消息不丢失的三大保障

业务场景:秒杀成功必须100%触发短信通知,消息丢失=客诉+资损。 技术点

  • 生产者端acks=all(所有ISR副本写入成功才返回)、retries=Integer.MAX_VALUE(无限重试)、启用幂等性(enable.idempotence=true);
  • Broker端min.insync.replicas=2(至少2个副本同步成功);
  • 消费者端:手动提交offset(enable.auto.commit=false),业务处理成功后再commitSync()

🔹 Q4:分布式链路追踪为什么比日志更高效?

业务场景:跨3个微服务的请求,某环节超时,需5分钟内定位到是库存服务的JDBC连接池打满。 技术点

  • Jaeger通过注入traceId+spanId实现全链路标记;
  • 结合Micrometer暴露http.server.requests指标,接入Prometheus+Grafana绘制P99热力图;
  • HikariCP内置poolUsage指标,配合leakDetectionThreshold=60000(60秒)自动检测连接泄漏并告警。

🔹 Q5:如何让K8s中的Spring Boot服务动态加载配置?

业务场景:Sentinel规则、Kafka Topic名、Redis地址需随环境(dev/test/prod)切换,不可硬编码。 技术点

  • 使用Spring Cloud Kubernetes,自动将K8s ConfigMap映射为Spring Environment属性;
  • YAML示例:
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: seckill-config
    data:
      sentinel.flow-rules: '[{"resource":"seckill-order", "count":1000}]'
      spring.redis.host: redis-prod.default.svc.cluster.local
    
  • Java代码中直接@Value("${sentinel.flow-rules}")注入,无需重启应用。

学习建议:按“业务痛点→技术选型→配置要点→避坑指南”四步法理解每个组件,拒绝死记参数!


📌 关注我,下期带你看《谢飞机面AIGC岗:Spring WebFlux响应式编程+R2DBC+LangChain集成实战》

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐