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圣经

查看7道真题和解析