Java大厂面试实战:电商场景下的分布式架构与高并发处理
·
Java大厂面试实战:电商场景下的分布式架构与高并发处理
面试场景:严肃面试官 vs 搞笑程序员谢飞机
面试官:你好,我是本次面试的技术面试官,我们主要考察你在电商场景下的技术能力。
谢飞机:面试官好!我是谢飞机,一个热爱技术的程序员,虽然有时候会飞得有点偏,但技术绝对靠谱!
第一轮:基础技术面试
问题1:电商库存扣减的原子性如何保证?
面试官:在电商秒杀场景下,如何保证库存扣减的原子性?
谢飞机:这个问题太常见了!我给大家展示几种方案:
// 方案1:数据库乐观锁
@Service
public class InventoryService {
@Transactional
public boolean deductInventory(Long productId, Integer quantity) {
Product product = productMapper.selectById(productId);
if (product.getStock() < quantity) {
return false;
}
// 乐观锁更新
int result = productMapper.updateStock(productId, quantity, product.getVersion());
return result > 0;
}
}
// 方案2:Redis原子操作
@Service
public class RedisInventoryService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean deductInventory(String productId, int quantity) {
String key = "inventory:" + productId;
// Lua脚本保证原子性
String script = "if redis.call('get', KEYS[1]) >= tonumber(ARGV[1]) then " +
"return redis.call('decrby', KEYS[1], tonumber(ARGV[1])) " +
"else return -1 end";
Long result = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
String.valueOf(quantity)
);
return result != null && result >= 0;
}
}
面试官:不错,两种方案都说到了。那如果扣减失败,如何保证数据一致性?
问题2:分布式事务如何处理?
谢飞机:分布式事务可是个大坑!我推荐使用TCC模式:
// TCC模式实现
@Service
public class OrderTccService {
@Transactional
public void createOrder(OrderDTO orderDTO) {
// Try阶段
boolean tryResult = tryPhase(orderDTO);
if (!tryResult) {
throw new RuntimeException("Try阶段失败");
}
try {
// Confirm阶段
confirmPhase(orderDTO);
} catch (Exception e) {
// Cancel阶段
cancelPhase(orderDTO);
throw e;
}
}
private boolean tryPhase(OrderDTO orderDTO) {
// 预扣库存
inventoryService.freezeStock(orderDTO.getProductId(), orderDTO.getQuantity());
// 生成预订单
orderService.createTemporaryOrder(orderDTO);
return true;
}
private void confirmPhase(OrderDTO orderDTO) {
// 确认扣减库存
inventoryService.confirmDeduct(orderDTO.getProductId(), orderDTO.getQuantity());
// 确认订单
orderService.confirmOrder(orderDTO.getOrderId());
}
private void cancelPhase(OrderDTO orderDTO) {
// 回滚库存
inventoryService.cancelFreeze(orderDTO.getProductId(), orderDTO.getQuantity());
// 取消预订单
orderService.cancelTemporaryOrder(orderDTO.getOrderId());
}
}
第二轮:高并发优化面试
问题3:如何设计缓存策略防止缓存穿透、击穿和雪崩?
面试官:在高并发场景下,缓存策略很关键,说说你的方案。
谢飞机:这可是我的强项!看我设计的缓存策略:
@Service
public class CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 防止缓存穿透:布隆过滤器 + 空值缓存
public Object getWithBloomFilter(String key, Class<?> clazz) {
// 1. 先检查布隆过滤器
if (!bloomFilter.mightContain(key)) {
return null;
}
// 2. 查询缓存
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
// 空值标记
if ("NULL".equals(value)) {
return null;
}
return JSON.parseObject((String) value, clazz);
}
// 3. 查询数据库
Object dbValue = getFromDB(key);
if (dbValue == null) {
// 缓存空值,防止穿透
redisTemplate.opsForValue().set(key, "NULL", 5, TimeUnit.MINUTES);
} else {
redisTemplate.opsForValue().set(key, JSON.toJSONString(dbValue), 30, TimeUnit.MINUTES);
}
return dbValue;
}
// 防止缓存击穿:互斥锁
public Object getWithMutexLock(String key, Class<?> clazz) {
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return JSON.parseObject((String) value, clazz);
}
// 获取分布式锁
String lockKey = "lock:" + key;
boolean locked = false;
try {
locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (locked) {
// 再次检查缓存(双重检查)
value = redisTemplate.opsForValue().get(key);
if (value != null) {
return JSON.parseObject((String) value, clazz);
}
// 查询数据库
value = getFromDB(key);
if (value != null) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(value), 30, TimeUnit.MINUTES);
}
return value;
} else {
// 未获取到锁,短暂等待后重试
Thread.sleep(50);
return getWithMutexLock(key, clazz);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} finally {
if (locked) {
redisTemplate.delete(lockKey);
}
}
}
// 防止缓存雪崩:随机过期时间
private long getRandomExpireTime() {
Random random = new Random();
return 1800 + random.nextInt(600); // 30-40分钟随机
}
}
问题4:消息队列在电商系统中的应用
谢飞机:消息队列可是系统解耦的神器!看我设计的订单处理流程:
// 订单创建事件
@Component
public class OrderCreatedEvent {
private String orderId;
private Long userId;
private BigDecimal amount;
private LocalDateTime createTime;
// 构造方法、getter、setter
}
// 事件发布者
@Service
public class EventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishOrderCreated(Order order) {
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getOrderId());
event.setUserId(order.getUserId());
event.setAmount(order.getAmount());
event.setCreateTime(order.getCreateTime());
eventPublisher.publishEvent(event);
}
}
// 库存扣减监听器
@Component
public class InventoryDeductListener {
@Autowired
private InventoryService inventoryService;
@EventListener
@Async
public void handleOrderCreated(OrderCreatedEvent event) {
// 异步扣减库存
inventoryService.asyncDeductInventory(event.getOrderId());
}
}
// 积分增加监听器
@Component
public class PointsAddListener {
@Autowired
private PointsService pointsService;
@EventListener
@Async
public void handleOrderCreated(OrderCreatedEvent event) {
// 异步增加积分
pointsService.addPoints(event.getUserId(), event.getAmount());
}
}
第三轮:架构设计面试
问题5:如何设计一个可扩展的微服务架构?
面试官:从单体架构迁移到微服务,你会如何设计?
谢飞机:这可是架构设计的精髓!看我画的架构图:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ API网关 │ │ 配置中心 │ │ 注册中心 │
│ Gateway │ │ Config │ │ Registry │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└────────────────────────┼───────────────────────┘
│
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ │ │ │ │
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│用户服务│ │订单服务│ │商品服务│ │库存服务│ │支付服务│
│User │ │Order │ │Product│ │Stock │ │Pay │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘
│ │ │ │ │
└─────────────┼─────────────┼─────────────┼─────────────┘
│ │ │
┌──────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ 消息队列 │ │ 缓存层 │ │ 数据库 │
│ MQ │ │ Redis │ │ MySQL │
└────────────┘ └───────────┘ └───────────┘
关键设计要点:
- 服务拆分原则:按业务领域拆分,单一职责
- API网关:统一入口,认证、限流、路由
- 服务注册发现:Eureka/Nacos实现服务治理
- 配置中心:统一配置管理,动态刷新
- 熔断降级:Hystrix/Sentinel保证系统稳定性
- 链路追踪:SkyWalking/Pinpoint监控调用链
技术要点总结
核心技术栈
- 数据库:MySQL + 分库分表 + 读写分离
- 缓存:Redis集群 + 多级缓存架构
- 消息队列:RocketMQ/Kafka保证消息可靠性
- 搜索引擎:Elasticsearch商品搜索
- 分布式事务:Seata/TCC模式
性能优化策略
- 数据库优化:索引优化、SQL调优、连接池配置
- 缓存策略:多级缓存、缓存预热、热点数据分离
- 异步处理:消息队列解耦、异步任务处理
- 限流降级:令牌桶算法、熔断器模式
学习建议
- 基础扎实:深入理解Java并发、JVM、数据结构
- 框架熟练:Spring全家桶、MyBatis、Dubbo
- 中间件掌握:Redis、MQ、Elasticsearch
- 架构思维:微服务、分布式、高可用设计
谢飞机总结:面试官,虽然我有时候会飞得有点偏,但这些技术点我可是认真研究过的!希望有机会加入贵公司,和大家一起飞得更高!
面试官:表现不错,技术深度和广度都很好。期待你的加入!
更多推荐



所有评论(0)