Java大厂面试实战:Spring Cloud微服务+Redis缓存+Kafka消息队列场景题解析
本文以面试官与程序员谢飞机的面试对话形式,涵盖Spring Cloud微服务、Redis缓存、Kafka消息队列等核心技术栈,结合电商业务场景,附带详细答案解析,适合Java求职者学习参考。
互联网大厂Java面试实录:谢飞机的闯关之旅
面试背景
某知名互联网大厂技术部面试间,面试官李工正襟危坐,求职者谢飞机略显紧张地坐在对面。本次面试聚焦电商业务场景,考察候选人的技术深度与业务理解能力。
第一轮:基础架构与缓存设计
面试官:谢飞机你好,欢迎参加今天的面试。我们先从电商场景入手。假设你负责一个电商平台的商品详情页,日PV达到千万级,你会如何设计缓存方案?
谢飞机:(自信满满)这个简单!用Redis做缓存啊,商品数据放Redis里,查询的时候先查缓存,没有再查数据库。
面试官:(点头)方向正确。那缓存穿透、缓存击穿、缓存雪崩这三个问题,你如何区分和解决?
谢飞机:(挠头)呃...穿透是缓存里没有,击穿是...雪崩是大量缓存同时失效?解决方案...可以用布隆过滤器?加锁?随机过期时间?
面试官:(微笑)基本概念知道,但不够清晰。继续,商品库存扣减场景,如何保证Redis和数据库的数据一致性?
谢飞机:(眼神飘忽)这个...先更新数据库再删缓存?或者用Canal监听binlog?具体实现...看业务场景吧...
面试官:(记录)好,我们进入下一轮。
第二轮:微服务架构与消息队列
面试官:电商订单系统通常采用微服务架构。如果让你用Spring Cloud设计订单服务,你会选择哪些核心组件?
谢飞机:(来精神了)Spring Cloud Alibaba!Nacos做注册配置中心,OpenFeign做服务调用,Sentinel做限流熔断,Gateway做网关!
面试官:(赞许)不错。那订单创建后需要通知库存服务、物流服务、积分服务,如何保证这些服务的最终一致性?
谢飞机:(犹豫)用...消息队列?Kafka?保证消息不丢失...ack机制?重复消费...幂等性?
面试官:具体说说Kafka如何保证消息不丢失?
谢飞机:(含糊)producer端ack=1,broker端多副本,consumer端手动提交offset...大概这样?
面试官:(追问)如果消息消费失败了,你的重试策略是什么?死信队列如何处理?
谢飞机:(擦汗)重试...可以配置重试次数?死信队列...单独一个topic存起来?人工处理?
面试官:(点头)思路有,细节需要加强。最后一个问题,分布式事务了解哪些方案?
谢飞机:(如释重负)2PC、3PC、TCC、Saga、本地消息表、最大努力通知...Seata框架也用过!
第三轮:高并发与系统监控
面试官:大促期间,系统QPS飙升10倍,你如何提前做容量评估和压测?
谢飞机:(思考)用JMeter压测?看CPU、内存、GC情况?数据库连接池?
面试官:具体指标呢?如何确定系统瓶颈?
谢飞机:(不太确定)TPS、响应时间、错误率...瓶颈可能在数据库?或者网络?
面试官:线上问题如何快速定位?你用过哪些监控工具?
谢飞机:(稍微自信)Prometheus+Grafana看指标,ELK查日志,SkyWalking或Zipkin做链路追踪!
面试官:如果某个接口响应时间突然从50ms涨到500ms,你的排查思路是什么?
谢飞机:(认真)先看监控指标,CPU、内存、GC是否正常;再看链路追踪,哪个环节慢;然后查慢SQL、外部依赖、锁竞争...
面试官:(满意)这个思路不错。最后一个问题,JVM调优做过吗?如何分析GC日志?
谢飞机:(心虚)调优...看过一些参数,-Xms、-Xmx、新生代老年代比例...GC日志用GCEasy分析?
面试官:(合上笔记本)好的,今天的面试就到这里。
谢飞机:(紧张)请问...结果什么时候出来?
面试官:(微笑)3个工作日内HR会通知你,回家等通知吧。
谢飞机:(起身)谢谢面试官!
详细答案解析
第一轮答案:缓存设计
1. 电商商品详情页缓存方案
业务场景:商品详情页是电商系统读多写少的典型场景,日PV千万级意味着每秒可能有数千次请求。
技术方案:
// 多级缓存架构
// 1. 本地缓存(Caffeine) - 热点商品
// 2. 分布式缓存(Redis) - 全量商品
// 3. 数据库 - 持久化存储
@Service
public class ProductService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Cacheable(value = "product", key = "#productId",
unless = "#result == null")
public ProductDTO getProductDetail(Long productId) {
// 1. 查本地缓存
// 2. 查Redis缓存
// 3. 查数据库并回写缓存
return productMapper.selectById(productId);
}
}
2. 缓存三大问题解决方案
| 问题 | 原因 | 解决方案 | |------|------|----------| | 缓存穿透 | 查询不存在的数据,缓存和数据库都没有 | 布隆过滤器、缓存空对象 | | 缓存击穿 | 热点key过期,大量请求直达数据库 | 互斥锁、逻辑过期 | | 缓存雪崩 | 大量key同时过期 | 随机过期时间、高可用集群 |
代码示例 - 布隆过滤器防穿透:
@Component
public class BloomFilterUtil {
@Autowired
private RedissonClient redissonClient;
public boolean mayExist(String key) {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("productBloom");
return bloomFilter.contains(key);
}
}
3. 缓存与数据库一致性
推荐方案:延迟双删 + Canal监听
// 方案1:先删缓存再更新数据库
public void updateProduct(Product product) {
redisTemplate.delete("product:" + product.getId());
productMapper.updateById(product);
// 延迟500ms再次删除
CompletableFuture.runAsync(() -> {
try { Thread.sleep(500); } catch (Exception e) {}
redisTemplate.delete("product:" + product.getId());
});
}
// 方案2:Canal监听binlog异步删除缓存
// MySQL binlog -> Canal -> Kafka -> 消费服务删除Redis
第二轮答案:微服务与消息队列
1. Spring Cloud核心组件选型
| 功能 | 组件 | 说明 | |------|------|------| | 服务注册发现 | Nacos | 支持AP/CP模式 | | 配置中心 | Nacos Config | 动态配置刷新 | | 服务调用 | OpenFeign | 声明式HTTP客户端 | | 限流熔断 | Sentinel | 流量控制、熔断降级 | | 网关 | Spring Cloud Gateway | 路由、过滤、限流 | | 链路追踪 | SkyWalking | 无侵入式APM |
2. Kafka消息可靠性保证
Producer端:
# 配置文件
acks=all # 所有副本确认
retries=3 # 重试次数
enable.idempotence=true # 幂等性
Broker端:
min.insync.replicas=2 # 最小同步副本
unclean.leader.election.enable=false # 禁止非ISR选举
Consumer端:
// 手动提交offset
@KafkaListener(topics = "order-topic")
public void consume(ConsumerRecord<String, String> record) {
try {
// 业务处理
processOrder(record);
// 处理成功后提交
ack.acknowledge();
} catch (Exception e) {
// 记录日志,触发重试
log.error("消费失败", e);
throw e; // 触发重试机制
}
}
3. 消息重试与死信队列
@Configuration
public class KafkaConfig {
@Bean
public KafkaListenerContainerFactory<?> factory(
ConsumerFactory<String, String> consumerFactory) {
ContainerProperties props = new ContainerProperties();
// 重试配置
props.setAckMode(ContainerProperties.AckMode.MANUAL);
DefaultErrorHandler errorHandler =
new DefaultErrorHandler((record, e) -> {
// 发送到死信队列
sendToDeadLetterQueue(record);
}, new FixedBackOff(1000L, 3L)); // 重试3次
return new ConcurrentKafkaListenerContainerFactory<>(consumerFactory);
}
}
4. 分布式事务方案对比
| 方案 | 一致性 | 性能 | 适用场景 | |------|--------|------|----------| | 2PC | 强一致 | 低 | 金融核心 | | TCC | 最终一致 | 中 | 业务可补偿 | | Saga | 最终一致 | 高 | 长流程 | | 本地消息表 | 最终一致 | 高 | 异步场景 | | Seata AT | 最终一致 | 中 | 通用场景 |
第三轮答案:高并发与监控
1. 容量评估与压测
评估公式:
所需实例数 = (峰值QPS × 平均响应时间) / (单实例最大QPS × 安全系数)
压测流程:
- 基准测试:单接口性能基线
- 负载测试:逐步增加压力找瓶颈
- 压力测试:极限压力测系统稳定性
- 稳定性测试:长时间运行测内存泄漏
2. 监控体系搭建
# Prometheus配置示例
scrape_configs:
- job_name: 'spring-boot'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
核心监控指标:
- JVM:堆内存、GC次数、线程数
- 应用:QPS、响应时间、错误率
- 中间件:Redis连接数、Kafka Lag
- 系统:CPU、内存、磁盘、网络
3. 接口慢排查思路
1. 查看APM链路追踪 → 定位慢的环节
2. 检查数据库慢查询 → EXPLAIN分析SQL
3. 查看外部依赖响应 → 第三方接口超时
4. 分析锁竞争 → jstack查看线程状态
5. 检查GC情况 → 是否Full GC导致STW
4. JVM调优参数参考
# 生产环境推荐配置
java -Xms4g -Xmx4g \
-XX:NewRatio=2 \
-XX:SurvivorRatio=8 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/heapdump.hprof \
-Xlog:gc*:file=/logs/gc.log:time,uptime:filecount=5,filesize=10M
GC日志分析工具:
- GCEasy.io(在线分析)
- GCViewer(本地工具)
- Prometheus+Grafana(实时监控)
面试总结
本次面试覆盖了Java工程师核心能力维度:
- 基础扎实度:缓存、数据库一致性
- 架构设计能力:微服务组件选型、消息队列可靠性
- 问题解决能力:监控排查、性能调优
- 业务理解能力:电商场景的技术落地
给求职者的建议:
- 技术原理要深入,不能只停留在使用层面
- 业务场景要结合,说明技术选型的理由
- 问题分析要有方法论,体现系统性思维
- 实战经验要总结,准备好项目难点案例
祝各位Java求职者面试顺利,拿到心仪的Offer!
本文基于真实面试场景整理,技术点仅供参考,实际面试请以具体公司要求为准。
更多推荐
所有评论(0)