互联网大厂Java面试实录:从SpringBoot到分布式秒杀系统

面试场景介绍

某互联网大厂后端开发岗位面试现场,面试官张工(资深架构师),候选人谢飞机(自称"全栈开发工程师")。


第一轮:基础框架与数据库(共4题)

张工:你好,先简单介绍一下你自己,重点说说最熟悉的技术栈。

谢飞机:咳咳,我是谢飞机,江湖人称"谢半桶水",主要精通Java、Python、Go...啊不,主要是Java!SpringBoot用得贼溜,数据库也会一点点MySQL...

张工:好,那我们从基础开始。你简历上写熟练使用SpringBoot,请解释一下@SpringBootApplication注解包含了哪些核心注解?

谢飞机:这个简单!@SpringBootApplication就是三个注解的组合嘛——@Configuration、@EnableAutoConfiguration、@ComponentScan,相当于告诉Spring"这里有个配置类,自动扫描组件,自己找配置文件"!

张工:不错,回答正确。那如果是电商秒杀场景,如何保证库存数据的准确性?

谢飞机:嗯...可以用数据库的乐观锁或者悲观锁呗,在update的时候加个where版本号...哦对,还有Redis预减库存!

张工:很好,知道Redis了。那Redis的持久化机制有哪几种?各自优缺点是什么?

谢飞机:这个...好像是RDB和AOF吧?RDB是快照,AOF是日志记录...哪个快我不太记得了,反正都用过...

张工:基本概念对了,但细节还需要加强。最后一个问题,MyBatis的一级缓存和二级缓存有什么区别?

谢飞机:一级缓存是SqlSession级别的,用完就没了;二级缓存是Mapper级别的,可以共享...具体怎么配置我想想...有点模糊了...

张工:好,基础部分就先这样,我们进入下一轮。


第二轮:微服务与中间件(共4题)

张工:假设你的秒杀系统部署在Kubernetes集群中,请说明服务注册与发现的工作原理。

谢飞机:这个...就是用Eureka或者Nacos对吧?服务启动时注册中心,消费者通过注册中心获取提供者列表...

张工:没错。如果某个商品秒完单后,订单系统需要异步处理物流信息,你会选择什么方案?

谢飞机:消息队列嘛!用Kafka或者RabbitMQ,生产者发消息,消费者消费,解耦...

张工:很好。那如果消息消费失败了怎么办?如何保证消息的可靠性投递?

谢飞机:失败的话就重试呗...手动ack还是自动ack...这个记不太清了,反正有重试机制...

张工:再问一个实际的,Spring Cloud中OpenFeign和RestTemplate的区别是什么?

谢飞机:这个我知道!OpenFeign是基于动态代理的声明式调用,RestTemplate是编程式的...OpenFeign更优雅一些...

张工:回答准确。最后一个,分布式事务如何解决?你了解Seata吗?

谢飞机:呃...Seata好像是阿里巴巴开源的?TCC模式两阶段提交...具体原理我研究得不多...

张工:好,微服务部分到此为止,我们聊聊高并发场景。


第三轮:实战场景与系统设计(共4题)

张工:如果现在要你设计一个支持百万并发的秒杀系统,请画出整体架构图并说明关键技术点。

谢飞机:额...前端静态资源CDN加速,接口层做限流熔断,Redis预扣库存,MQ异步下单,数据库最终一致性...大概是这样...

张工:思路是对的。那具体来说,如何防止超卖?请详细说明你的实现方案。

谢飞机:这个...Redis原子操作decrement,数据库乐观锁version字段,还有Lua脚本保证原子性...应该够了吧...

张工:考虑比较全面。如果秒杀过程中出现热点商品,如何优化缓存策略?

谢飞机:本地缓存Caffeine配合分布式缓存Redis,多级缓存架构...不过热点key击穿的问题怎么处理我有点忘了...

张工:监控体系呢?如何快速定位线上故障?

谢飞机:Prometheus收集指标,Grafana展示,ELK分析日志,Jaeger链路追踪...这些我都用过...

张工:好的,技术方面就聊到这里。你觉得还有什么想补充的吗?

谢飞机:那个...我还会一点前端Vue和React,算不算加分项?

张工:哈哈,全栈确实有优势。今天的面试就到这里,结果会在3个工作日内通过邮件通知你,谢谢。

谢飞机:谢谢张工!希望能收到好消息!


面试答案解析与技术详解

一、SpringBoot核心注解详解

| 注解 | 功能说明 | |------|----------| | @SpringBootApplication | 组合注解入口 | | @Configuration | 标识配置类 | | @EnableAutoConfiguration | 开启自动装配 | | @ComponentScan | 组件扫描 |

二、库存数据准确性保障方案

// 方案1:数据库乐观锁
UPDATE product_stock 
SET stock = stock - 1, version = version + 1 
WHERE id = 1 AND stock > 0 AND version = ?;

// 方案2:Redis预扣库存
redis.decr("stock:1001"); // 原子操作

// 方案3:分布式锁
RLock lock = redissonClient.getLock("lock:product:1001");
lock.lock(10, TimeUnit.SECONDS);
try {
    // 执行扣减逻辑
} finally {
    lock.unlock();
}

三、Redis持久化机制对比

| 特性 | RDB | AOF | |------|-----|-----| | 存储方式 | 二进制快照 | 命令日志 | | 恢复速度 | 快 | 慢 | | 数据完整性 | 可能丢失 | 完整 | | 文件大小 | 小 | 大 |

四、MyBatis缓存机制

  • 一级缓存:SqlSession级别,默认开启,同一会话内有效
  • 二级缓存:Namespace级别,需手动配置,跨会话共享

五、秒杀系统完整架构图

用户请求 → CDN静态资源
         ↓
    Nginx负载均衡
         ↓
   API网关(限流/鉴权)
         ↓
   ┌──────────────────────┐
   │  前置过滤层           │
   │  - 黑名单IP           │
   │  - 频率限制           │
   │  - 验证码             │
   └──────────────────────┘
         ↓
   ┌──────────────────────┐
   │  库存预扣层           │
   │  - Redis原子操作      │
   │  - Lua脚本            │
   │  - 布隆过滤器防穿透   │
   └──────────────────────┘
         ↓
   ┌──────────────────────┐
   │  消息队列缓冲         │
   │  - Kafka/RocketMQ     │
   │  - 削峰填谷           │
   └──────────────────────┘
         ↓
   ┌──────────────────────┐
   │  订单服务             │
   │  - 创建订单           │
   │  - 库存落库           │
   └──────────────────────┘
         ↓
   ┌──────────────────────┐
   │  后续业务             │
   │  - 支付               │
   │  - 物流               │
   │  - 通知               │
   └──────────────────────┘

六、防止超卖的三道防线

  1. 第一道:Redis预扣 - 原子操作,快速拦截
  2. 第二道:数据库乐观锁 - 版本号校验,最终兜底
  3. 第三道:业务层幂等 - 防止重复下单

七、监控告警体系

| 层级 | 工具 | 作用 | |------|------|------| | 基础设施 | Prometheus | CPU、内存、磁盘 | | 应用性能 | SkyWalking/Jaeger | 链路追踪 | | 日志分析 | ELK Stack | 错误排查 | | 可视化 | Grafana | 仪表盘展示 |


给求职者的建议

  1. 基础知识要扎实:框架底层原理必须理解透彻
  2. 实战经验是关键:多参与真实项目,积累踩坑经验
  3. 系统化思维:能够画出架构图,理解各组件协作关系
  4. 持续学习:新技术层出不穷,保持学习能力
  5. 沟通表达能力:清晰表达技术方案,展现思考过程

本文基于真实面试场景改编,仅供学习交流,如有雷同纯属巧合

更多推荐