Java 大厂面试:Spring Cloud+Redis+Kafka 智慧物流系统架构实战解析

📖 前言

大家好,今天给大家带来一篇互联网大厂 Java 面试实战文章。本文通过严肃面试官搞笑水货程序员谢飞机的趣味对话形式,深入解析智慧物流场景下的微服务架构设计。

谢飞机特点:简单问题对答如流,复杂问题含糊其辞,回答不清晰时面试官会引导。


🎯 面试场景:智慧物流系统

业务背景:某大型物流平台,日均订单量 500 万+,需要实现订单管理、智能调度、轨迹追踪、仓储管理等功能。


📝 第一轮:基础架构与服务治理

面试官:谢飞机你好,请先介绍一下你之前做的物流系统架构。

谢飞机:好的领导!我们用的是 Spring Boot + Spring Cloud 微服务架构,服务注册发现用 Nacos,网关用 Spring Cloud Gateway,配置中心也是 Nacos。数据库是 MySQL,缓存用 Redis,消息队列用 Kafka。

面试官:(点头)不错,基础架构清晰。那你们服务之间如何调用?

谢飞机:用 OpenFeign 啊!声明式接口,加个@FeignClient 注解就行,简单好用!

面试官:(微笑)回答正确。那如果下游服务响应慢或者宕机了怎么办?

谢飞机:呃...这个...我们配置了...那个熔断器...Resilience4j!对,就是它!可以设置超时时间和重试次数。

面试官:(引导)具体怎么配置的呢?比如超时时间、重试策略?

谢飞机:(擦汗)这个...配置文件里写嘛...resilience4j.timeout.timeout-duration=3000...重试的话...retry.max-attempts=3...大概这样?

面试官:(记录)还算可以。那数据库连接池用的什么?为什么选它?

谢飞机:HikariCP!性能最好,启动快,连接复用率高!比 C3P0、Druid 都强!

面试官:(满意)不错,有对比思考。最后一个问题,数据库版本管理怎么做?

谢飞机:Flyway!每次发布自动执行 SQL 脚本,保证数据库结构一致!


📝 第二轮:缓存与消息队列

面试官:好,基础部分过了。现在说缓存,物流轨迹查询量大,你们怎么优化?

谢飞机:Redis 缓存啊!热点数据放 Redis,查询速度提升 10 倍!

面试官:(追问)那缓存穿透、击穿、雪崩怎么解决?

谢飞机:(自信)穿透用布隆过滤器!击穿用互斥锁!雪崩...雪崩...加随机过期时间!

面试官:(点头)基本正确。具体代码怎么实现互斥锁?

谢飞机:(含糊)就是...Redis 的 setnx 嘛...或者 Redisson 的 RLock...具体代码...我回去查查...

面试官:(记录)行,继续。消息队列为什么选 Kafka 而不是 RabbitMQ?

谢飞机:Kafka 吞吐量高啊!适合物流这种大数据量场景!RabbitMQ 适合小数据量、复杂路由!

面试官:(引导)那消息可靠性怎么保证?比如消息丢失、重复消费?

谢飞机:(开始慌)丢失的话...ACK 机制!重复消费...幂等性!具体...具体实现...我们有个幂等表...记录消息 ID...

面试官:(追问)物流状态变更顺序很重要,怎么保证消息顺序?

谢飞机:(支吾)这个...Kafka 分区...同一个订单发到同一个分区...就能保证顺序...吧?

面试官:(记录)基本思路对。那物流轨迹数据存储用什么?

谢飞机:Elasticsearch!查询快,支持地理位置查询,适合轨迹追踪!


📝 第三轮:安全、事务与监控

面试官:好,最后一轮。系统安全怎么做的?

谢飞机:Spring Security + JWT!用户登录发 Token,后续请求带 Token 验证!

面试官:(追问)Token 过期了怎么办?

谢飞机:双 Token 机制!Access Token 短有效期,Refresh Token 长有效期,过期了用 Refresh Token 刷新!

面试官:(满意)不错。那分布式事务怎么解决?比如创建订单同时扣减库存?

谢飞机:(开始含糊)Seata!AT 模式!全局锁...回滚日志...具体原理...就是两阶段提交的优化版...

面试官:(引导)AT 模式有什么问题?

谢飞机:(擦汗)这个...全局锁可能有性能问题...高并发场景...可能要用 TCC...或者 Saga...

面试官:(追问)TCC 三个阶段分别是什么?

谢飞机:(支吾)Try...Confirm...Cancel...Try 预留资源,Confirm 确认,Cancel 取消...具体代码...我写过但忘了...

面试官:(记录)行。最后,系统监控怎么做?

谢飞机:Prometheus + Grafana!指标采集、可视化大屏!链路追踪用 SkyWalking!日志用 ELK!

面试官:(满意)技术栈挺全。JVM 调优做过吗?

谢飞机:(自信)做过!-Xms-Xmx 设一样,避免动态扩容!GC 用 G1!参数 -XX:+UseG1GC -XX:MaxGCPauseMillis=200!

面试官:(微笑)可以。今天面试就到这里,回去等通知吧,HR 会联系你。

谢飞机:(松口气)好的领导!感谢感谢!


📚 详细答案解析

第一轮答案:基础架构与服务治理

1. Spring Cloud 微服务架构

业务场景:物流系统包含订单服务、仓储服务、运输服务、配送服务等多个微服务。

技术方案

# application.yml
spring:
  application:
    name: logistics-order-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml

技术点

  • Nacos:服务注册发现 + 配置中心
  • Spring Cloud Gateway:统一网关,路由转发、鉴权、限流
  • OpenFeign:声明式服务调用
2. OpenFeign 服务调用

代码示例

@FeignClient(name = "logistics-warehouse-service")
public interface WarehouseClient {
    
    @GetMapping("/api/warehouse/inventory/{skuId}")
    Result<Integer> getInventory(@PathVariable("skuId") Long skuId);
    
    @PostMapping("/api/warehouse/deduct")
    Result<Boolean> deductInventory(@RequestBody DeductRequest request);
}

配置

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 10000
  compression:
    request:
      enabled: true
    response:
      enabled: true
3. Resilience4j 熔断降级

配置

resilience4j:
  circuitbreaker:
    instances:
      warehouseService:
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10000
        permittedNumberOfCallsInHalfOpenState: 5
  timelimiter:
    instances:
      warehouseService:
        timeoutDuration: 3s
  retry:
    instances:
      warehouseService:
        maxAttempts: 3
        waitDuration: 1s

代码使用

@Service
public class OrderService {
    
    @CircuitBreaker(name = "warehouseService", fallbackMethod = "fallback")
    @TimeLimiter(name = "warehouseService")
    @Retry(name = "warehouseService")
    public CompletableFuture<Result<Boolean>> deductInventory(DeductRequest request) {
        return CompletableFuture.supplyAsync(() -> 
            warehouseClient.deductInventory(request)
        );
    }
    
    public CompletableFuture<Result<Boolean>> fallback(DeductRequest request, Exception e) {
        // 降级逻辑:记录日志,返回默认值
        return CompletableFuture.completedFuture(Result.fail("服务繁忙,请稍后重试"));
    }
}
4. HikariCP 连接池

配置

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 30000
      max-lifetime: 1800000

优势

  • 性能最优(基准测试第一)
  • 启动速度快
  • 连接复用率高
  • 代码量少,维护简单
5. Flyway 数据库版本管理

配置

spring:
  flyway:
    enabled: true
    locations: classpath:db/migration
    baseline-on-migrate: true
    validate-on-migrate: true

SQL 脚本示例

-- V1.0.0__create_order_table.sql
CREATE TABLE logistics_order (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64) NOT NULL,
    customer_id BIGINT NOT NULL,
    status INT DEFAULT 0,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_order_no (order_no),
    INDEX idx_customer_id (customer_id)
);

-- V1.0.1__add_tracking_column.sql
ALTER TABLE logistics_order ADD COLUMN tracking_no VARCHAR(64);

第二轮答案:缓存与消息队列

1. Redis 缓存优化

三级缓存架构

  • L1:Caffeine(本地缓存,毫秒级)
  • L2:Redis(分布式缓存,毫秒级)
  • L3:MySQL(持久化存储,秒级)

缓存穿透解决方案

// 布隆过滤器
@Component
public class BloomFilterUtil {
    
    @Autowired
    private RedissonClient redissonClient;
    
    public RBloomFilter<String> createBloomFilter(String key) {
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(key);
        bloomFilter.tryInit(1000000L, 0.03); // 预期 100 万数据,3% 误判率
        return bloomFilter;
    }
    
    public boolean mightExist(RBloomFilter<String> bloomFilter, String value) {
        return bloomFilter.contains(value);
    }
}

缓存击穿解决方案(互斥锁)

@Service
public class LogisticsCacheService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private OrderMapper orderMapper;
    
    public OrderDTO getOrderDetail(Long orderId) {
        String cacheKey = "order:" + orderId;
        
        // 1. 查询缓存
        OrderDTO order = redisTemplate.opsForValue().get(cacheKey);
        if (order != null) {
            return order;
        }
        
        // 2. 获取互斥锁
        RLock lock = redissonClient.getLock("lock:order:" + orderId);
        try {
            if (lock.tryLock(1, 10, TimeUnit.SECONDS)) {
                try {
                    // 3. 双重检查缓存
                    order = redisTemplate.opsForValue().get(cacheKey);
                    if (order != null) {
                        return order;
                    }
                    
                    // 4. 查询数据库
                    order = orderMapper.selectById(orderId);
                    
                    // 5. 写入缓存(随机过期时间防雪崩)
                    int expireTime = 3600 + new Random().nextInt(1800);
                    redisTemplate.opsForValue().set(cacheKey, order, expireTime, TimeUnit.SECONDS);
                    
                    return order;
                } finally {
                    lock.unlock();
                }
            } else {
                // 6. 获取锁失败,休眠重试
                Thread.sleep(50);
                return getOrderDetail(orderId);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
    }
}

缓存雪崩解决方案

// 随机过期时间
public void setWithRandomExpire(String key, Object value) {
    int baseExpire = 3600; // 基础 1 小时
    int randomExpire = new Random().nextInt(1800); // 随机 0-30 分钟
    int expireTime = baseExpire + randomExpire;
    redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
}

// 热点数据永不过期 + 异步更新
@Scheduled(fixedRate = 300000) // 每 5 分钟更新
public void refreshHotData() {
    List<Long> hotOrderIds = orderMapper.selectHotOrderIds();
    for (Long orderId : hotOrderIds) {
        OrderDTO order = orderMapper.selectById(orderId);
        redisTemplate.opsForValue().set("order:" + orderId, order, 24, TimeUnit.HOURS);
    }
}
2. Kafka 消息可靠性

生产者配置

spring:
  kafka:
    producer:
      bootstrap-servers: 127.0.0.1:9092
      acks: all  # 所有副本确认
      retries: 3  # 重试次数
      batch-size: 16384
      buffer-memory: 33554432
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      properties:
        enable.idempotence: true  # 幂等性
        max.in.flight.requests.per.connection: 5

消费者配置

spring:
  kafka:
    consumer:
      bootstrap-servers: 127.0.0.1:9092
      group-id: logistics-order-group
      auto-offset-reset: earliest
      enable-auto-commit: false  # 手动提交
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      properties:
        isolation.level: read_committed  # 只读已提交消息

消息发送代码

@Service
public class KafkaProducerService {
    
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    public void sendOrderMessage(String topic, String key, String message) {
        ListenableFuture<SendResult<String, String>> future = 
            kafkaTemplate.send(topic, key, message);
        
        future.addCallback(
            result -> {
                // 发送成功
                log.info("消息发送成功:topic={}, key={}, offset={}", 
                    result.getRecordMetadata().topic(),
                    key,
                    result.getRecordMetadata().offset());
            },
            ex -> {
                // 发送失败,记录日志或存入死信队列
                log.error("消息发送失败:topic={}, key={}", topic, key, ex);
                saveToDeadLetterQueue(topic, key, message);
            }
        );
    }
}

幂等性消费实现

@Service
public class OrderConsumer {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @KafkaListener(topics = "logistics-order-topic", groupId = "logistics-order-group")
    public void consumeOrderMessage(ConsumerRecord<String, String> record) {
        String messageId = record.key();
        String messageKey = "kafka:message:id:" + messageId;
        
        // 1. 检查是否已消费
        Boolean exists = redisTemplate.opsForValue().setIfAbsent(messageKey, "1", 24, TimeUnit.HOURS);
        if (Boolean.FALSE.equals(exists)) {
            log.warn("消息已消费,跳过:messageId={}", messageId);
            return;
        }
        
        try {
            // 2. 业务处理
            OrderMessage orderMessage = JSON.parseObject(record.value(), OrderMessage.class);
            processOrder(orderMessage);
            
            // 3. 手动提交 offset
            // (使用@KafkaListener 自动提交时确保业务处理成功)
        } catch (Exception e) {
            log.error("消息处理失败:messageId={}", messageId, e);
            // 删除幂等标记,允许重试
            redisTemplate.delete(messageKey);
            throw e; // 触发 Kafka 重试
        }
    }
}

消息顺序保证

// 发送时:同一个订单 ID 发送到同一个分区
public void sendOrderMessage(Long orderId, String message) {
    String key = String.valueOf(orderId); // 用订单 ID 作为 key
    kafkaTemplate.send("logistics-order-topic", key, message);
}

// Kafka 保证:相同 key 的消息进入同一分区,分区内有序
3. Elasticsearch 轨迹存储

索引 Mapping

{
  "mappings": {
    "properties": {
      "order_id": { "type": "long" },
      "tracking_no": { "type": "keyword" },
      "location": {
        "type": "geo_point"
      },
      "address": { "type": "text" },
      "status": { "type": "integer" },
      "operator": { "type": "keyword" },
      "operate_time": { "type": "date" }
    }
  }
}

地理位置查询

@Service
public class LogisticsTrackService {
    
    @Autowired
    private RestHighLevelClient esClient;
    
    public List<TrackDTO> searchNearbyTracks(double lat, double lon, double distance) {
        SearchRequest request = new SearchRequest("logistics_track");
        
        GeoDistanceQueryBuilder geoQuery = QueryBuilders.geoDistanceQuery("location")
            .point(lat, lon)
            .distance(distance, DistanceUnit.KILOMETERS);
        
        request.source().query(geoQuery);
        
        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
        // 解析结果...
    }
}

第三轮答案:安全、事务与监控

1. Spring Security + JWT 认证

JWT Token 生成

@Component
public class JwtTokenProvider {
    
    @Value("${jwt.secret}")
    private String secretKey;
    
    @Value("${jwt.expiration}")
    private long expiration;
    
    public String generateToken(UserDetails userDetails) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);
        
        return Jwts.builder()
            .setSubject(userDetails.getUsername())
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(SignatureAlgorithm.HS512, secretKey)
            .compact();
    }
    
    public String generateRefreshToken(UserDetails userDetails) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration * 7); // 7 天
        
        return Jwts.builder()
            .setSubject(userDetails.getUsername())
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(SignatureAlgorithm.HS512, secretKey)
            .compact();
    }
    
    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
            .setSigningKey(secretKey)
            .parseClaimsJws(token)
            .getBody();
        return claims.getSubject();
    }
    
    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }
}

Security 配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .antMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthenticationFilter, 
                UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
}
2. Seata 分布式事务

AT 模式配置

seata:
  enabled: true
  application-id: logistics-order-service
  tx-service-group: default_tx_group
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  store:
    mode: db
    db:
      datasource: druid
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata
      user: seata
      password: seata

AT 模式使用

@Service
public class OrderCreateService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private InventoryClient inventoryClient;
    
    @Autowired
    private AccountClient accountClient;
    
    @GlobalTransactional(timeoutMills = 300000, name = "create-order-tx")
    public OrderResult createOrder(CreateOrderRequest request) {
        // 1. 创建订单
        Order order = new Order();
        order.setOrderNo(generateOrderNo());
        order.setCustomerId(request.getCustomerId());
        order.setAmount(request.getAmount());
        order.setStatus(OrderStatus.CREATED);
        orderMapper.insert(order);
        
        // 2. 扣减库存(远程调用)
        inventoryClient.deduct(request.getSkuId(), request.getQuantity());
        
        // 3. 扣减账户余额(远程调用)
        accountClient.deduct(request.getCustomerId(), request.getAmount());
        
        return OrderResult.success(order.getOrderNo());
    }
}

TCC 模式实现

@LocalTCC
public interface InventoryTCCService {
    
    @TCCBusinessMethod(startMethod = "try", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(TccContext context, Long skuId, Integer quantity);
    
    boolean try(TccContext context, Long skuId, Integer quantity);
    
    boolean confirm(TccContext context, Long skuId, Integer quantity);
    
    boolean cancel(TccContext context, Long skuId, Integer quantity);
}

@Service
public class InventoryTCCServiceImpl implements InventoryTCCService {
    
    @Override
    public boolean try(TccContext context, Long skuId, Integer quantity) {
        // 1. 检查库存
        Inventory inventory = inventoryMapper.selectBySkuId(skuId);
        if (inventory.getQuantity() < quantity) {
            return false;
        }
        
        // 2. 冻结库存
        inventoryMapper.freeze(skuId, quantity);
        
        // 3. 记录 TCC 日志
        context.setVariable("skuId", skuId);
        context.setVariable("quantity", quantity);
        
        return true;
    }
    
    @Override
    public boolean confirm(TccContext context, Long skuId, Integer quantity) {
        // 确认扣减:冻结 -> 实际扣减
        inventoryMapper.confirmDeduct(skuId, quantity);
        return true;
    }
    
    @Override
    public boolean cancel(TccContext context, Long skuId, Integer quantity) {
        // 取消:解冻库存
        inventoryMapper.cancelFreeze(skuId, quantity);
        return true;
    }
}
3. Prometheus + Grafana 监控

Micrometer 指标埋点

@Component
public class LogisticsMetrics {
    
    private final Counter orderCounter;
    private final Timer orderTimer;
    private final Gauge inventoryGauge;
    
    public LogisticsMetrics(MeterRegistry meterRegistry) {
        this.orderCounter = meterRegistry.counter("logistics.order.created");
        this.orderTimer = meterRegistry.timer("logistics.order.process.time");
        this.inventoryGauge = Gauge.builder("logistics.inventory.total",
            this, LogisticsMetrics::getInventoryTotal)
            .register(meterRegistry);
    }
    
    public void recordOrderCreated() {
        orderCounter.increment();
    }
    
    public <T> T recordOrderProcess(Supplier<T> supplier) {
        return orderTimer.record(supplier);
    }
    
    private double getInventoryTotal() {
        return inventoryMapper.selectTotalQuantity();
    }
}

Prometheus 配置

scrape_configs:
  - job_name: 'logistics-service'
    static_configs:
      - targets: ['127.0.0.1:8080']
    metrics_path: '/actuator/prometheus'

Grafana Dashboard 示例

  • 订单创建量(QPS)
  • 订单处理耗时(P95/P99)
  • 库存总量趋势
  • 服务可用性
  • JVM 内存/GC 指标
4. SkyWalking 链路追踪

Agent 配置

# agent.service.name=logistics-order-service
# collector.backend_service=127.0.0.1:11800

plugin.spring.interceptor=true
plugin.tomcat.ignore_collector=true

启动参数

-javaagent:/path/to/skywalking-agent.jar 
-Dskywalking.agent.service_name=logistics-order-service 
-Dskywalking.collector.backend_service=127.0.0.1:11800
5. JVM 调优参数

生产环境配置

# 堆内存设置
-Xms4g -Xmx4g  # 最小最大堆内存一致,避免动态扩容

# GC 选择
-XX:+UseG1GC  # G1 垃圾收集器
-XX:MaxGCPauseMillis=200  # 最大 GC 停顿时间
-XX:G1HeapRegionSize=16m  # G1 区域大小

# 元空间
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m

# 日志
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/var/log/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M

# OOM 处理
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/heapdump.hprof

# 其他优化
-XX:+UseCompressedOops  # 压缩指针(64 位 JVM)
-XX:ReservedCodeCacheSize=256m
-Dfile.encoding=UTF-8

GC 问题排查步骤

  1. jstat -gcutil <pid> 1000 - 查看 GC 统计
  2. jmap -heap <pid> - 查看堆内存分布
  3. jmap -histo:live <pid> - 查看对象分布
  4. jstack <pid> - 查看线程栈
  5. 分析 GC 日志,定位问题

🎓 学习路线建议

| 阶段 | 时间 | 学习内容 | |------|------|----------| | 🌱 初级 | 0-2 年 | Spring Boot 基础、Redis 操作、RESTful API、MySQL 优化 | | 🌿 中级 | 2-5 年 | 微服务架构、消息队列、分布式缓存、JVM 调优 | | 🌳 高级 | 5 年 + | 高可用设计、分布式事务、全链路监控、架构规划 |


📖 推荐资源

  1. 书籍:《Spring Cloud 微服务实战》《深入理解 Java 虚拟机》
  2. 文档:Spring 官方文档、Redis 官方文档、Kafka 官方文档
  3. 视频:B 站尚硅谷、黑马程序员微服务课程
  4. 实战:GitHub 开源项目、公司内部项目实践

✅ 总结

本文通过趣味面试对话形式,系统讲解了智慧物流场景下的 Java 微服务架构设计,涵盖:

  • ✅ 服务治理(Nacos + OpenFeign + Resilience4j)
  • ✅ 缓存优化(Redis 三级缓存 + 穿透/击穿/雪崩解决)
  • ✅ 消息队列(Kafka 可靠性 + 顺序消息 + 幂等消费)
  • ✅ 安全认证(Spring Security + JWT 双 Token)
  • ✅ 分布式事务(Seata AT/TCC 模式)
  • ✅ 监控运维(Prometheus + Grafana + SkyWalking)
  • ✅ JVM 调优(G1 GC + 参数配置 + 问题排查)

希望这篇文章能帮助大家在面试中脱颖而出!如有疑问,欢迎评论区交流!


👍 觉得有用请点赞收藏,关注我获取更多 Java 面试干货!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐