互联网大厂Java面试实录面试官与谢飞机的技术博弈本文以情景剧形式呈现一场真实的Java技术面试通过幽默对话展现技术深度适合Java开发者学习参考。人物介绍面试官某互联网大厂技术专家严肃认真技术功底深厚谢飞机求职者自称有5年经验实际水平参差不齐回答简单问题头头是道遇到复杂问题就开始打太极面试场景电商平台秒杀系统设计与实现第一轮基础架构与缓存设计面试官谢飞机你好欢迎来到我们公司。我看你简历上写着有电商秒杀系统经验那我们先从基础开始。第一个问题秒杀系统中为什么要用Redis做缓存不用MySQL直接查询行不行谢飞机自信满满这个简单Redis是内存数据库速度比MySQL快多了。MySQL是磁盘存储要读写磁盘慢Redis在内存里纳秒级响应。秒杀场景QPS高必须用Redis面试官微微点头回答得不错确实如此。那第二个问题Redis缓存穿透、缓存击穿、缓存雪崩分别是什么怎么解决谢飞机稍微迟疑呃...穿透就是...缓存里没有数据库也没有一直查数据库。击穿是...热点key过期了大量请求打到数据库。雪崩是...很多key同时过期。擦汗解决方案...穿透用布隆过滤器击穿用互斥锁雪崩...加随机时间面试官记录笔记基本概念知道了但解决方案说得不够详细。第三个问题秒杀系统中如何保证Redis和MySQL的数据一致性谢飞机眼神飘忽这个...一致性嘛...可以用双写先写Redis再写MySQL...或者用消息队列异步同步...具体实现...看业务场景...面试官皱眉好先记下来。我们进入第二轮。第二轮高并发与消息队列面试官刚才说到秒杀那第四个问题当10万用户同时点击秒杀按钮你的系统如何抗住这么高的并发谢飞机来精神了这个我熟分层架构第一层Nginx负载均衡第二层网关限流第三层服务降级第四层...消息队列削峰填谷把同步请求变成异步处理面试官眼睛一亮不错思路对。那第五个问题你提到消息队列Kafka和RabbitMQ怎么选在秒杀场景中用哪个更合适谢飞机Kafka...吞吐量高适合大数据场景。RabbitMQ...功能丰富延迟低。秒杀的话...犹豫应该用Kafka吧毕竟量大...面试官其实两者都可以要看具体需求。第六个问题消息队列如何保证消息不丢失谢飞机开始含糊这个...有ACK机制...生产者确认...消费者确认...持久化...具体配置...看文档...面试官叹气好最后一轮。第三轮分布式事务与系统监控面试官第七个问题秒杀成功后订单创建、库存扣减、优惠券核销涉及多个服务如何保证分布式事务的一致性谢飞机额头冒汗分布式事务...有Seata...有TCC模式...有Saga...还有...本地消息表...声音越来越小具体选哪个...看情况...面试官那第八个问题系统上线后如何监控服务健康状态出现慢查询怎么定位谢飞机监控...用Prometheus...Grafana看面板...慢查询...看日志...ELK...眼神游离面试官最后一个问题如果秒杀过程中发现超卖了怎么紧急处理谢飞机彻底慌了超卖...这个...紧急...降级...熔断...限流...语无伦次面试官合上简历好了今天的面试就到这里。我们会综合评估请你回家等通知吧。谢飞机如释重负好的好的谢谢面试官技术详解与标准答案一、Redis缓存核心问题1. 为什么用Redis不用MySQL// MySQL查询 - 慢 Transactional public SeckillResult queryFromDB(Long userId, Long productId) { Product product productMapper.selectById(productId); // 磁盘IO约10ms // 高并发下数据库连接池容易耗尽 } // Redis查询 - 快 public SeckillResult queryFromRedis(Long userId, Long productId) { String key seckill:product: productId; Product product redisTemplate.opsForValue().get(key); // 内存操作1ms return product; }核心差异MySQL磁盘IO单次查询10-100msQPS约1000-3000Redis内存操作单次查询1msQPS可达10万2. 缓存三大问题解决方案缓存穿透查询不存在的数据// 方案1布隆过滤器 Bean public BloomFilter bloomFilter() { return BloomFilter.create(Funnels.longFunnel(), 1000000, 0.01); } public Product getProduct(Long productId) { if (!bloomFilter.mightContain(productId)) { return null; // 直接返回不查数据库 } // 继续查缓存和数据库 } // 方案2缓存空值 public Product getProduct(Long productId) { String key product: productId; Product product redisTemplate.get(key); if (product NULL_OBJECT) { // 特殊标记 return null; } if (product null) { product productMapper.selectById(productId); if (product null) { redisTemplate.setex(key, 300, NULL_OBJECT); // 缓存5分钟 return null; } redisTemplate.setex(key, 3600, product); } return product; }缓存击穿热点key过期// 互斥锁方案 public Product getHotProduct(Long productId) { String key product: productId; Product product redisTemplate.get(key); if (product ! null) { return product; } // 获取分布式锁 String lockKey lock:product: productId; boolean locked redisTemplate.setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS); if (locked) { try { // 双重检查 product redisTemplate.get(key); if (product ! null) { return product; } product productMapper.selectById(productId); redisTemplate.setex(key, 3600, product); } finally { redisTemplate.delete(lockKey); } } else { // 等待后重试 Thread.sleep(100); return getHotProduct(productId); } return product; }缓存雪崩大量key同时过期// 方案随机过期时间 public void cacheProduct(Product product) { String key product: product.getId(); int expireTime 3600 new Random().nextInt(600); // 3600-4200秒随机 redisTemplate.setex(key, expireTime, product); } // 方案多级缓存 Component public class MultiLevelCache { Autowired private CaffeineCache localCache; Autowired private RedisCache redisCache; public Product get(Long id) { Product p localCache.get(id); if (p ! null) return p; p redisCache.get(id); if (p ! null) { localCache.put(id, p); return p; } return loadFromDB(id); } }3. Redis与MySQL一致性方案// 方案1延时双删推荐 Transactional public void updateProduct(Product product) { // 1. 先删缓存 redisTemplate.delete(product: product.getId()); // 2. 更新数据库 productMapper.update(product); // 3. 延时再删缓存避免主从同步延迟 CompletableFuture.runAsync(() - { try { Thread.sleep(500); redisTemplate.delete(product: product.getId()); } catch (Exception e) { log.error(二次删除失败, e); } }); } // 方案2Canal监听binlog异步更新 Component public class CanalListener { StreamListener(canal:product) public void handleProductChange(ProductChangeEvent event) { if (event.getEventType() UPDATE) { redisTemplate.setex(product: event.getId(), 3600, event.getData()); } else if (event.getEventType() DELETE) { redisTemplate.delete(product: event.getId()); } } }二、高并发与消息队列4. 高并发架构设计// 网关层限流 Configuration public class RateLimitConfig { Bean public KeyResolver userKeyResolver() { return exchange - Mono.just( exchange.getRequest().getHeaders().getFirst(user-id) ); } } // 服务层降级 Service public class SeckillService { HystrixCommand(fallbackMethod seckillFallback) public SeckillResult seckill(Long userId, Long productId) { // 正常逻辑 } public SeckillResult seckillFallback(Long userId, Long productId) { return SeckillResult.fail(系统繁忙请稍后再试); } } // 消息队列削峰 Component public class SeckillProducer { Autowired private KafkaTemplateString, String kafkaTemplate; public void sendSeckillRequest(SeckillRequest request) { kafkaTemplate.send(seckill-topic, JSON.toJSONString(request)); } } Component public class SeckillConsumer { KafkaListener(topics seckill-topic) public void consume(String message) { SeckillRequest request JSON.parseObject(message, SeckillRequest.class); // 异步处理秒杀逻辑 processSeckill(request); } }5. Kafka vs RabbitMQ选型| 维度 | Kafka | RabbitMQ | |------|-------|----------| | 吞吐量 | 10万/s | 1-2万/s | | 延迟 | ms级 | 微秒级 | | 可靠性 | 高 | 非常高 | | 适用场景 | 日志、大数据 | 订单、支付 |秒杀场景建议请求量极大 → Kafka需要精确投递 → RabbitMQ6. 消息不丢失保障// Kafka生产者配置 Configuration public class KafkaConfig { Bean public ProducerFactoryString, String producerFactory() { MapString, Object config new HashMap(); config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka:9092); config.put(ProducerConfig.ACKS_CONFIG, all); // 所有副本确认 config.put(ProducerConfig.RETRIES_CONFIG, 3); // 重试3次 config.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // 幂等 return new DefaultKafkaProducerFactory(config); } } // 消费者手动ACK Component public class ReliableConsumer { KafkaListener(topics seckill-topic, containerFactory manualAckContainer) public void consume(ConsumerRecordString, String record, Acknowledgment ack) { try { processSeckill(record.value()); ack.acknowledge(); // 处理成功后确认 } catch (Exception e) { // 记录失败消息人工处理 log.error(消息处理失败, e); } } }三、分布式事务与监控7. 分布式事务解决方案// 方案1Seata AT模式 GlobalTransactional public SeckillResult seckillWithSeata(Long userId, Long productId) { // 1. 扣减库存 inventoryService.decrease(productId, 1); // 2. 创建订单 Order order orderService.create(userId, productId); // 3. 核销优惠券 couponService.use(userId, couponId); return SeckillResult.success(order); } // 方案2TCC模式 Service public class SeckillTCCService { TwoPhaseBusinessAction(name seckillTCC, commitMethod commit, rollbackMethod rollback) public boolean trySeckill(SeckillRequest request) { // 预留资源 inventoryService.freeze(request.getProductId(), 1); return true; } public boolean commit(SeckillRequest request) { // 确认扣减 inventoryService.confirmFreeze(request.getProductId(), 1); return true; } public boolean rollback(SeckillRequest request) { // 释放预留 inventoryService.releaseFreeze(request.getProductId(), 1); return true; } } // 方案3本地消息表最终一致性 Service public class LocalMessageService { Transactional public void sendOrderMessage(Order order) { // 1. 创建订单 orderMapper.insert(order); // 2. 记录消息 Message msg new Message(); msg.setOrderId(order.getId()); msg.setStatus(PENDING); messageMapper.insert(msg); } // 定时任务扫描发送 Scheduled(fixedRate 5000) public void scanAndSend() { ListMessage messages messageMapper.findPending(); for (Message msg : messages) { kafkaTemplate.send(order-topic, msg); msg.setStatus(SENT); messageMapper.update(msg); } } }8. 系统监控与慢查询定位# Prometheus配置 prometheus: scrape_interval: 15s scrape_configs: - job_name: spring-boot static_configs: - targets: [localhost:8080]// Micrometer监控埋点 Service public class MonitoredSeckillService { Autowired private MeterRegistry meterRegistry; private final Timer seckillTimer; public MonitoredSeckillService(MeterRegistry meterRegistry) { this.meterRegistry meterRegistry; this.seckillTimer meterRegistry.timer(seckill.duration); } public SeckillResult seckill(Long userId, Long productId) { return seckillTimer.record(() - { // 业务逻辑 return doSeckill(userId, productId); }); } } // 慢查询日志 Configuration public class MybatisConfig { Bean public Interceptor slowQueryInterceptor() { return new Interceptor() { Override public Object intercept(Invocation invocation) throws Throwable { long start System.currentTimeMillis(); Object result invocation.proceed(); long cost System.currentTimeMillis() - start; if (cost 1000) { log.warn(慢查询: {}ms, SQL: {}, cost, invocation.toString()); } return result; } }; } }9. 超卖紧急处理方案// 预防超卖数据库乐观锁 public int decreaseStock(Long productId, Integer quantity) { return inventoryMapper.updateStock( productId, quantity, quantity // WHERE stock quantity ); } // Redis原子操作防超卖 Component public class RedisSeckillService { public boolean trySeckill(Long productId) { String key seckill:stock: productId; Long stock redisTemplate.opsForValue().decrement(key); if (stock 0) { redisTemplate.opsForValue().increment(key); // 回滚 return false; } return true; } } // 紧急降级预案 Component public class EmergencyHandler { Autowired private CircuitBreakerRegistry circuitBreakerRegistry; public void enableEmergencyMode() { // 1. 开启熔断 circuitBreakerRegistry.circuitBreaker(seckill).transitionToOpenState(); // 2. 切换静态页面 redisTemplate.set(seckill:status, EMERGENCY); // 3. 发送告警 alertService.send(秒杀系统异常已开启降级模式); } }总结与学习建议技术栈全景图用户请求 → Nginx负载均衡 → 网关限流 → Spring Cloud微服务 ↓ Redis缓存 Kafka消息队列 ↓ MySQL分库分表 Elasticsearch搜索 ↓ Prometheus监控 ELK日志 Sky链路追踪核心知识点缓存设计穿透/击穿/雪崩解决方案、一致性保障高并发限流、降级、熔断、削峰填谷消息队列选型对比、可靠性保障、顺序消息分布式事务Seata、TCC、本地消息表监控运维Prometheus、Grafana、链路追踪给初学者的建议先掌握Spring Boot Redis MySQL基础组合理解缓存三大问题的本质和解决方案动手搭建一个完整的秒杀系统demo学习使用Docker Kubernetes部署微服务关注生产环境的监控和告警体系建设面试官的话技术面试不仅考察知识点记忆更看重解决问题的思路和系统架构能力。希望各位开发者能够理论结合实践在实际项目中不断成长谢飞机的话下次面试前一定要好好复习啊捂脸本文技术内容仅供参考实际生产环境需要根据具体业务场景调整优化。