面试现场:谢飞机勇闯互联网大厂
面试官(严肃脸):请进。
谢飞机(推门撞到墙,扶了扶并不存在的眼镜):报、抱歉!电梯太滑......我是来面试Java开发的!
面试官:好,我们开始。你在简历上写了熟悉Spring Boot,能说说它是怎么实现自动配置的吗?
谢飞机 :这个我知道!是靠@SpringBootApplication注解,它里面有个@EnableAutoConfiguration,会去读META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,把一堆自动配置类加载进来!
面试官(微微点头):不错,那如果我想自定义一个Starter,该怎么做?
谢飞机 :呃......建个Maven项目,写个配置类,再注册到spring.factories里......啊不是,现在是.imports!然后别人引入依赖就能用了!
面试官:还行。那假设我们现在做一个秒杀系统,用户下单前要判断库存,你会怎么设计?
谢飞机 :用数据库啊!查一下stock > 0就扣减,简单明了!
面试官:高并发下呢?10万人同时抢100件商品?
谢飞机 :那......那我加个synchronized?或者用Redis先减库存!对,Redis原子操作DECR!
面试官:有点思路了。如果Redis扣成功了,但数据库没扣成,怎么办?
谢飞机:呃......让老板赔钱?开玩笑的!可以用消息队列,比如Kafka,发个消息异步处理,失败就重试!
面试官:继续。如果订单创建后,要通知库存、物流、积分服务,你怎么保证最终一致性?
谢飞机:用Spring Cloud Alibaba的Dubbo?哦不对......用Spring Cloud Stream + Kafka,发事件!每个服务监听自己关心的topic!
面试官:如果消息丢了呢?
谢飞机:我......我让它多发几遍?或者消费者手动ACK?
面试官:还可以。最后一个问题:如何防止用户恶意刷单?
谢飞机 :加验证码!登录限制!IP限流!用Redis记录访问次数,比如INCR login:1.1.1.1,超过5次就封!
面试官(终于露出一丝微笑):回答得还算可以。这样吧,你先回去,等我们的通知。
谢飞机(激动):有戏!有戏!我一定在家等电话,24小时开机,连洗澡都带着手机!
真题解析:电商秒杀系统的架构设计
业务场景
电商平台在大促期间面临高并发请求,如"双11"秒杀活动。核心需求包括:
- 高性能响应
- 库存准确性
- 订单最终一致性
- 防刷与安全控制
技术点详解
1. Spring Boot 自动配置原理
@SpringBootApplication=@Configuration+@ComponentScan+@EnableAutoConfiguration- 自动配置类通过
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports注册 - 条件化装配:
@ConditionalOnClass,@ConditionalOnMissingBean等确保环境适配
应用场景 :简化第三方组件集成,如
spring-boot-starter-data-redis自动配置LettuceConnectionFactory。
2. 秒杀库存超卖问题
直接数据库扣减在高并发下会导致:
- 数据库锁争抢(行锁、表锁)
- 响应慢、连接池耗尽
解决方案:
- Redis预减库存 :利用
DECR原子性,快速拦截无效请求 - 内存标记:本地缓存标识商品是否已售罄,避免重复查Redis
- RabbitMQ/Kafka削峰:异步处理订单,保护数据库
java
// 示例:Redis扣库存
Long result = redisTemplate.execute((RedisCallback<Long>) connection ->
connection.decr(stockKey.getBytes())
);
if (result >= 0) {
// 进入下单流程
} else {
// 库存不足
}
3. 分布式事务与最终一致性
使用事件驱动架构(EDA):
- 订单服务发布
OrderCreatedEvent - 库存、物流、积分服务作为消费者订阅对应Topic
- 消息中间件保障至少一次投递
补偿机制:
- 消费失败时重试(Kafka重试队列)
- 定时对账任务修复不一致状态
4. 防刷限流策略
- 接口级限流:使用Resilience4j或Sentinel,限制QPS
- 用户维度限频 :Redis中以
user_id为key计数,TTL=60s - 设备/IP识别:结合前端埋点与风控系统
- 验证码挑战:高风险行为触发图形/短信验证码
java
// 示例:Redis限流
String key = "limit:login:" + ip;
Long count = stringRedisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
stringRedisTemplate.expire(key, 1, TimeUnit.MINUTES);
}
if (count > 5) {
throw new RuntimeException("请求过于频繁");
}
5. 微服务协同(Spring Cloud 实践)
- 服务发现:Nacos/Eureka 注册订单、库存服务
- 远程调用:OpenFeign 声明式调用
- 熔断降级:Resilience4j 避免雪崩
- 链路追踪:Jaeger + OpenTelemetry 记录全流程
架构图简析
用户请求 → API网关(鉴权+限流)
↓
Redis(库存预减)
↓
Kafka(订单消息队列)
↓
订单服务 → 发布事件 → [库存|物流|积分]服务消费
↓
MySQL持久化
总结
本场景综合考察了Java程序员对Spring生态、缓存、消息队列、分布式一致性、安全防护 的掌握程度。实际大厂面试中,不仅要求说出技术名词,更要能讲清为什么选这个方案、有没有替代方案、边界情况如何处理。
建议学习路径:
- 掌握Spring Boot源码启动流程
- 动手搭建Kafka + Redis + MySQL的订单demo
- 使用JMeter压测并优化性能
- 学习Seata等分布式事务框架作为扩展
谢飞机虽然答得磕绊,但抓住了关键点。真正的高手,是在混乱中也能拎出主线的人。