10.3 缓存架构设计

面试重要程度:⭐⭐⭐⭐⭐

常见提问方式:如何设计多级缓存体系?如何保证缓存一致性?缓存穿透、击穿、雪崩如何解决?

预计阅读时间:40分钟

🎯 多级缓存体系设计

缓存层次架构

/**
 * 多级缓存架构设计
 */
@Component
public class MultiLevelCacheArchitecture {
    
    /**
     * 缓存层级定义
     */
    public enum CacheLevel {
        L1_LOCAL_CACHE(1, "本地缓存", "JVM内存"),
        L2_DISTRIBUTED_CACHE(2, "分布式缓存", "Redis集群"),
        L3_DATABASE_CACHE(3, "数据库缓存", "MySQL查询缓存"),
        L4_CDN_CACHE(4, "CDN缓存", "边缘节点缓存");
        
        private final int level;
        private final String name;
        private final String description;
    }
    
    /**
     * 多级缓存管理器
     */
    @Component
    public static class MultiLevelCacheManager {
        
        @Autowired
        private LocalCacheManager localCacheManager;
        
        @Autowired
        private DistributedCacheManager distributedCacheManager;
        
        /**
         * 多级缓存查询
         */
        public <T> T get(String key, Class<T> type, Supplier<T> dataLoader) {
            // L1: 本地缓存查询
            T value = localCacheManager.get(key, type);
            if (value != null) {
                return value;
            }
            
            // L2: 分布式缓存查询
            value = distributedCacheManager.get(key, type);
            if (value != null) {
                // 回写到本地缓存
                localCacheManager.put(key, value, Duration.ofMinutes(5));
                return value;
            }
            
            // L3: 数据源查询
            value = dataLoader.get();
            if (value != null) {
                // 写入各级缓存
                distributedCacheManager.put(key, value, Duration.ofHours(1));
                localCacheManager.put(key, value, Duration.ofMinutes(5));
            }
            
            return value;
        }
        
        /**
         * 多级缓存更新
         */
        public <T> void put(String key, T value, Duration ttl) {
            localCacheManager.put(key, value, ttl);
            distributedCacheManager.put(key, value, ttl);
        }
        
        /**
         * 多级缓存删除
         */
        public void evict(String key) {
            localCacheManager.evict(key);
            distributedCacheManager.evict(key);
        }
    }
    
    /**
     * 本地缓存管理器
     */
    @Component
    public static class LocalCacheManager {
        
        private final Cache<String, Object> cache;
        
        public LocalCacheManager() {
            this.cache = Caffeine.newBuilder()
                .maximumSize(10000)                    // 最大条目数
                .expireAfterWrite(Duration.ofMinutes(30)) // 写入后30分钟过期
                .expireAfterAccess(Duration.ofMinutes(10)) // 访问后10分钟过期
                .refreshAfterWrite(Duration.ofMinutes(5))  // 写入后5分钟刷新
                .recordStats()                         // 记录统计信息
                .build();
        }
        
        @SuppressWarnings("unchecked")
        public <T> T get(String key, Class<T> type) {
            Object value = cache.getIfPresent(key);
            return value != null ? (T) value : null;
        }
        
        public <T> void put(String key, T value, Duration ttl) {
            cache.put(key, value);
        }
        
        public void evict(String key) {
            cache.invalidate(key);
        }
        
        /**
         * 获取缓存统计信息
         */
        public CacheStats getStats() {
            return cache.stats();
        }
    }
}

缓存预热与更新策略

/**
 * 缓存预热与更新策略
 */
@Component
public class CacheWarmupAndUpdateStrategy {
    
    /**
     * 缓存预热服务
     */
    @Component
    public static class CacheWarmupService {
        
        @Autowired
        private MultiLevelCacheManager cacheManager;
        
        /**
         * 应用启动时预热缓存
         */
        @EventListener(ApplicationReadyEvent.class)
        public void warmupOnStartup() {
            log.info("Starting cache warmup...");
            
            CompletableFuture.allOf(
                CompletableFuture.runAsync(this::warmupHotUsers),
                CompletableFuture.runAsync(this::warmupHotProducts),
                CompletableFuture.runAsync(this::warmupSystemConfig)
            ).thenRun(() -> {
                log.info("Cache warmup completed");
            });
        }
        
        /**
         * 预热热点用户数据
         */
        private void warmupHotUsers() {
            try {
                List<Long> hotUserIds = userService.getHotUserIds(1000);
                
                hotUserIds.parallelStream().forEach(userId -> {
                    try {
                        String cacheKey = "user:profile:" + userId;
                        UserProfile profile = userService.getUserProfile(userId);
                        cacheManager.put(cacheKey, profile, Duration.ofHours(2));
                    } catch (Exception e) {
                        log.warn("Failed to warmup user: {}", userId, e);
                    }
                });
                
                log.info("Warmed up {} hot users", hotUserIds.size());
            } catch (Exception e) {
                log.error("Failed to warmup hot users", e);
            }
        }
        
        /**
         * 预热热点商品数据
         */
        private void warmupHotProducts() {
            try {
                List<Long> hotProductIds = productService.getHotProductIds(5000);
                
                // 分批处理,避免内存压力
                int batchSize = 100;
                for (int i = 0; i < hotProductIds.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, hotProductIds.size());
                    List<Long> batch = hotProductIds.subList(i, endIndex);
                    
                    batch.parallelStream().forEach(productId -> {
                        try {
                            String cacheKey = "product:detail:" + productId;
                            ProductDetail detail = productService.getProductDetail(productId);
                            cacheManager.put(cacheKey, detail, Duration.ofHours(6));
                        } catch (Exception e) {
                            log.warn("Failed to warmup product: {}", productId, e);
                        }
                    });
                    
                    // 避免过快的请求
                    Thread.sleep(100);
                }
                
                log.info("Warmed up {} hot products", hotProductIds.size());
            } catch (Exception e) {
                log.error("Failed to warmup hot products", e);
            }
        }
    }
}

🔒 缓存一致性保证

缓存一致性策略

/**
 * 缓存一致性保证机制
 */
@Component
public class CacheConsistencyGuarantee {
    
    /**
     * 旁路缓存模式实现
     */
    @Component
    public static class CacheAsidePattern {
        
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
        
        @Autowired
        private UserRepository userRepository;
        
        /**
         * 查询用户信息(Cache Aside模式)
         */
        public UserInfo getUserInfo(Long userId) {
            String cacheKey = "user:info:" + userId;
            
            // 1. 先查缓存
            UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(cacheKey);
            if (userInfo != null) {
                return userInfo;
            }
            
            // 2. 缓存未命中,查数据库
            userInfo = userRepository.findById(userId);
  

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论
欢迎讨论
点赞 回复 分享
发布于 09-06 11:26 江西

相关推荐

昨天 16:33
已编辑
微软_sde(实习员工)
点赞 评论 收藏
分享
双尔:反手回一个很抱歉,经过慎重考虑,您与我的预期暂不匹配,感谢您的投递
点赞 评论 收藏
分享
顺利毕业的鸽子:这个不一定,找hr跟进一下
点赞 评论 收藏
分享
评论
点赞
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务