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    │
           └────────────┘ └───────────┘ └───────────┘

关键设计要点

  1. 服务拆分原则:按业务领域拆分,单一职责
  2. API网关:统一入口,认证、限流、路由
  3. 服务注册发现:Eureka/Nacos实现服务治理
  4. 配置中心:统一配置管理,动态刷新
  5. 熔断降级:Hystrix/Sentinel保证系统稳定性
  6. 链路追踪:SkyWalking/Pinpoint监控调用链

技术要点总结

核心技术栈

  • 数据库:MySQL + 分库分表 + 读写分离
  • 缓存:Redis集群 + 多级缓存架构
  • 消息队列:RocketMQ/Kafka保证消息可靠性
  • 搜索引擎:Elasticsearch商品搜索
  • 分布式事务:Seata/TCC模式

性能优化策略

  1. 数据库优化:索引优化、SQL调优、连接池配置
  2. 缓存策略:多级缓存、缓存预热、热点数据分离
  3. 异步处理:消息队列解耦、异步任务处理
  4. 限流降级:令牌桶算法、熔断器模式

学习建议

  1. 基础扎实:深入理解Java并发、JVM、数据结构
  2. 框架熟练:Spring全家桶、MyBatis、Dubbo
  3. 中间件掌握:Redis、MQ、Elasticsearch
  4. 架构思维:微服务、分布式、高可用设计

谢飞机总结:面试官,虽然我有时候会飞得有点偏,但这些技术点我可是认真研究过的!希望有机会加入贵公司,和大家一起飞得更高!

面试官:表现不错,技术深度和广度都很好。期待你的加入!

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐