Spring Cloud微服务架构在电商场景下的Java面试实战
面试现场
面试官:严肃的架构师老李,10年大厂经验
面试者:王德发,号称3年Java开发经验的"资深"工程师
第一轮:基础微服务架构
面试官:王德发是吧,简历上写着熟悉Spring Cloud微服务架构。我们公司是做电商的,先问几个基础问题。你能说说Spring Cloud中的核心组件有哪些吗?
王德发:啊,这个我知道!Spring Cloud主要有Eureka做服务注册发现,Gateway做网关,Config做配置管理,还有Feign做服务调用。
面试官:不错,基础概念还是清楚的。那你在项目中是如何使用Eureka进行服务注册的?
王德发:就是在启动类上加个@EnableEurekaClient注解,然后在配置文件里配置eureka.client.service-url.defaultZone指向Eureka服务器地址。
面试官:很好!那假设我们电商系统有用户服务、订单服务、商品服务,你觉得应该如何划分这些微服务?
王德发:嗯...按照业务领域划分吧,用户相关的放用户服务,订单的放订单服务,商品的放商品服务...
面试官:思路正确,DDD领域驱动设计的思想。那服务间调用你一般用什么方式?
王德发:用Feign啊,声明式的HTTP客户端,很方便的。就是定义个接口,加上@FeignClient注解就行了。
面试官:基础掌握得不错。那如果订单服务调用用户服务时,用户服务挂了怎么办?
王德发:这个...用Hystrix做熔断?不过好像Hystrix已经不维护了...现在用什么来着...Resilience4j?
第二轮:深入技术实现
面试官:对,现在确实推荐用Resilience4j。看得出来你对新技术还是有关注的。那我问个具体场景,电商系统中,用户下单时需要:1.检查商品库存,2.创建订单,3.扣减库存,4.发送消息通知。这是个典型的分布式事务场景,你会怎么处理?
王德发:分布式事务...这个...可以用Seata?或者...TCC模式?具体怎么实现我...我觉得需要根据具体业务场景来设计。
面试官:概念知道,但实现细节不太清楚是吧。那我换个问题,如果商品服务需要支持高并发查询,你会怎么优化?
王德发:加缓存!用Redis!还可以用CDN,数据库读写分离,分库分表...
面试官:思路对,但你能具体说说Redis在这个场景下的使用策略吗?比如缓存更新策略?
王德发:缓存更新...旁路缓存模式?先查缓存,没有再查数据库,然后把数据放到缓存里。更新的话...先更新数据库再删缓存?还是先删缓存再更新数据库?我记得有个什么双删策略...
面试官:看得出来有了解,但细节还需要深入。那我问最后一个技术问题,微服务架构中如何实现链路追踪?
王德发:链路追踪...用Sleuth?配合Zipkin?在每个请求上加个TraceId,然后在各个服务间传递...具体实现我...我觉得Spring Boot应该有自动配置。
第三轮:架构设计与实践
面试官:我看你对技术栈都有一定了解,但实践经验还需要提升。现在给你个综合场景:我们要设计一个秒杀系统,预计QPS达到10万,你会如何设计整体架构?
王德发:秒杀系统...这个难度很大啊。需要...需要限流,用网关限流。然后用消息队列削峰填谷,把请求先放到队列里慢慢处理。缓存肯定要用,预热缓存。数据库...分库分表?还有就是...防止超卖,要用分布式锁?
面试官:方向是对的,但你能说说具体用什么技术实现限流吗?
王德发:限流...令牌桶算法?滑动窗口?具体用什么组件...Sentinel?还是网关自带的限流?我...我觉得需要结合具体情况选择。
面试官:那消息队列你会选择哪种?为什么?
王德发:Kafka?因为性能好,吞吐量大。或者RabbitMQ也行,功能比较全面。选择的话...看业务需求吧,如果要求性能就Kafka,如果要求功能丰富就RabbitMQ。
面试官:最后一个问题,如何保证整个秒杀流程的数据一致性?
王德发:数据一致性...这个真的很复杂。可能需要用分布式事务,或者设计补偿机制,最终一致性?具体怎么实现...我觉得需要根据业务容错性来设计。
面试官:好的,今天的面试就到这里。你的基础概念掌握得还不错,但在实践经验和深入理解方面还需要加强。我们会在一周内给你答复,你先回去等通知吧。
王德发:好的,谢谢面试官!
技术知识点详解
第一轮知识点解析
1. Spring Cloud核心组件
- Eureka: 服务注册与发现中心,提供服务实例的注册、续约、下线等功能
- Gateway: 微服务网关,提供路由、过滤、限流等功能,是Spring Cloud官方推荐的网关解决方案
- Config: 配置管理中心,支持Git、SVN等多种配置源
- OpenFeign: 声明式HTTP客户端,简化服务间调用
// Eureka客户端配置示例
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// application.yml配置
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
2. 微服务划分原则
基于DDD(领域驱动设计)进行服务划分:
- 用户服务: 用户注册、登录、个人信息管理
- 商品服务: 商品信息管理、库存管理、价格管理
- 订单服务: 订单创建、支付、状态管理
- 优惠服务: 优惠券、促销活动管理
3. Resilience4j容错处理
@Component
public class UserService {
@CircuitBreaker(name = "userService", fallbackMethod = "fallbackUser")
@Retry(name = "userService")
@TimeLimiter(name = "userService")
public CompletableFuture<User> getUserById(Long id) {
return CompletableFuture.supplyAsync(() -> userClient.getUser(id));
}
public CompletableFuture<User> fallbackUser(Long id, Exception ex) {
return CompletableFuture.completedFuture(new User(id, "默认用户"));
}
}
第二轮知识点解析
1. 分布式事务解决方案
Saga模式在电商订单场景的应用:
@SagaOrchestrationStart
public class OrderSaga {
@SagaOrchestrationTask
public void checkInventory(OrderCreatedEvent event) {
inventoryService.reserveInventory(event.getProductId(), event.getQuantity());
}
@SagaOrchestrationTask
public void createOrder(InventoryReservedEvent event) {
orderService.createOrder(event.getOrderInfo());
}
@SagaOrchestrationTask
public void processPayment(OrderCreatedEvent event) {
paymentService.processPayment(event.getPaymentInfo());
}
}
2. Redis缓存策略
Cache-Aside(旁路缓存)模式:
@Service
public class ProductService {
@Autowired
private RedisTemplate<String, Product> redisTemplate;
public Product getProduct(Long productId) {
String key = "product:" + productId;
// 先查缓存
Product product = redisTemplate.opsForValue().get(key);
if (product == null) {
// 缓存未命中,查数据库
product = productRepository.findById(productId);
if (product != null) {
// 写入缓存,设置过期时间
redisTemplate.opsForValue().set(key, product, Duration.ofMinutes(30));
}
}
return product;
}
public void updateProduct(Product product) {
// 先更新数据库
productRepository.save(product);
// 删除缓存
redisTemplate.delete("product:" + product.getId());
}
}
3. 链路追踪实现
// pom.xml依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
// application.yml配置
spring:
sleuth:
sampler:
probability: 1.0 # 采样率
zipkin:
base-url: http://localhost:9411
第三轮知识点解析
1. 秒杀系统架构设计
整体架构图:
用户请求 → CDN → 负载均衡 → API网关(限流) → 秒杀服务 → 消息队列 → 订单服务
↓
Redis缓存
↓
数据库集群
核心技术实现:
// 1. 网关限流配置
@Component
public class RateLimitGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimitGatewayFilterFactory.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String key = getClientId(exchange);
return redisRateLimiter.isAllowed(config.getRouteId(), key)
.flatMap(response -> {
if (response.isAllowed()) {
return chain.filter(exchange);
} else {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
});
};
}
}
// 2. 秒杀业务逻辑
@Service
public class SeckillService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
public SeckillResult seckill(Long userId, Long productId) {
String stockKey = "seckill:stock:" + productId;
String userKey = "seckill:user:" + productId + ":" + userId;
// 检查用户是否已经参与过秒杀
if (redisTemplate.hasKey(userKey)) {
return SeckillResult.fail("用户已参与过秒杀");
}
// 原子性扣减库存
Long stock = redisTemplate.opsForValue().decrement(stockKey);
if (stock < 0) {
return SeckillResult.fail("商品已售完");
}
// 标记用户已参与
redisTemplate.opsForValue().set(userKey, "1", Duration.ofDays(1));
// 异步处理订单
SeckillMessage message = new SeckillMessage(userId, productId);
rabbitTemplate.convertAndSend("seckill.order", message);
return SeckillResult.success("秒杀成功,请稍后查看订单");
}
}
// 3. 消息队列处理
@RabbitListener(queues = "seckill.order")
public class SeckillOrderHandler {
public void handleSeckillOrder(SeckillMessage message) {
try {
// 创建订单
Order order = orderService.createSeckillOrder(message.getUserId(), message.getProductId());
// 发送订单创建成功消息
notificationService.sendOrderNotification(order);
} catch (Exception e) {
// 订单创建失败,恢复库存
String stockKey = "seckill:stock:" + message.getProductId();
redisTemplate.opsForValue().increment(stockKey);
// 清除用户参与标记
String userKey = "seckill:user:" + message.getProductId() + ":" + message.getUserId();
redisTemplate.delete(userKey);
}
}
}
2. 分布式锁防止超卖
@Component
public class RedisDistributedLock {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofMillis(expireTime));
return result != null && result;
}
public void unlock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), value);
}
}
3. 消息队列选型对比
| 特性 | Kafka | RabbitMQ | ActiveMQ |
|---|---|---|---|
| 吞吐量 | 极高(100万+/秒) | 高(10万/秒) | 中等(5万/秒) |
| 延迟 | 低 | 极低 | 中等 |
| 持久化 | 优秀 | 优秀 | 良好 |
| 可用性 | 高 | 高 | 中等 |
| 消息顺序 | 分区内有序 | 队列有序 | 队列有序 |
| 适用场景 | 大数据处理、日志收集 | 业务消息、任务队列 | 传统企业应用 |
秒杀场景推荐使用Kafka,因为需要处理大量并发请求,Kafka的高吞吐量特性非常适合。
4. 数据一致性保证
在秒杀场景中,采用最终一致性策略:
- 订单创建阶段: 使用Redis分布式锁保证库存扣减的原子性
- 支付阶段: 使用本地消息表+定时任务保证支付状态同步
- 库存同步: 使用消息队列异步同步缓存和数据库库存
- 补偿机制: 定时任务检查并修复不一致数据
// 本地消息表实现
@Transactional
public void createOrderWithMessage(Order order) {
// 1. 创建订单
orderRepository.save(order);
// 2. 创建本地消息记录
LocalMessage message = new LocalMessage();
message.setContent(JsonUtils.toJson(order));
message.setTopic("order.created");
message.setStatus(MessageStatus.CREATED);
localMessageRepository.save(message);
}
// 定时任务发送消息
@Scheduled(fixedDelay = 5000)
public void sendPendingMessages() {
List<LocalMessage> pendingMessages = localMessageRepository.findByStatus(MessageStatus.CREATED);
for (LocalMessage message : pendingMessages) {
try {
rabbitTemplate.convertAndSend(message.getTopic(), message.getContent());
message.setStatus(MessageStatus.SENT);
localMessageRepository.save(message);
} catch (Exception e) {
message.setRetryCount(message.getRetryCount() + 1);
if (message.getRetryCount() > 3) {
message.setStatus(MessageStatus.FAILED);
}
localMessageRepository.save(message);
}
}
}
总结
这次面试涵盖了Spring Cloud微服务架构在电商场景下的核心技术点:
- 微服务基础: Eureka服务注册发现、Gateway网关、OpenFeign服务调用
- 容错处理: Resilience4j熔断限流、分布式事务处理
- 性能优化: Redis缓存策略、消息队列削峰填谷
- 架构设计: 秒杀系统设计、分布式锁、数据一致性保证
掌握这些知识点,对于Java后端开发特别是微服务架构开发非常重要。建议深入学习每个技术点的原理和最佳实践,并通过实际项目加深理解。
更多推荐


所有评论(0)