18.7.4 缓存穿透、击穿、雪崩解决方案
1. 缓存穿透问题与解决方案
1.1 缓存穿透原理
public class CachePenetrationSolution { /* * 缓存穿透问题: * * 1. 问题描述 * - 查询不存在的数据 * - 缓存和数据库都没有数据 * - 每次请求都会穿透到数据库 * * 2. 解决方案 * - 布隆过滤器 * - 缓存空值 * - 参数校验 */ public void demonstrateCachePenetration() { System.out.println("=== 缓存穿透解决方案演示 ==="); demonstrateBloomFilter(); demonstrateCacheNullValue(); } private void demonstrateBloomFilter() { System.out.println("--- 布隆过滤器解决方案 ---"); MockBloomFilter bloomFilter = new MockBloomFilter(); System.out.println("1. 初始化布隆过滤器:"); bloomFilter.add(1001); bloomFilter.add(1002); bloomFilter.add(1003); System.out.println("\n2. 查询测试:"); System.out.println("用户1001存在: " + bloomFilter.mightContain(1001)); System.out.println("用户9999存在: " + bloomFilter.mightContain(9999)); System.out.println("\n3. 布隆过滤器特点:"); System.out.println(" - 不存在的一定返回false"); System.out.println(" - 存在的可能返回true (有误判率)"); System.out.println(" - 内存占用小,查询速度快"); } private void demonstrateCacheNullValue() { System.out.println("\n--- 缓存空值解决方案 ---"); MockCacheService cacheService = new MockCacheService(); System.out.println("1. 第一次查询不存在的数据:"); String result1 = cacheService.getUser(8888); System.out.println("查询结果: " + result1); System.out.println("\n2. 第二次查询相同数据:"); String result2 = cacheService.getUser(8888); System.out.println("查询结果: " + result2 + " (从缓存获取)"); System.out.println("\n3. 空值缓存配置:"); System.out.println(" - 过期时间: 5分钟"); System.out.println(" - 避免长期占用内存"); } } // 模拟布隆过滤器 class MockBloomFilter { private java.util.Set<Integer> data = new java.util.HashSet<>(); public void add(int value) { data.add(value); System.out.println("添加到布隆过滤器: " + value); } public boolean mightContain(int value) { return data.contains(value); } } // 模拟缓存服务 class MockCacheService { private java.util.Map<String, String> cache = new java.util.HashMap<>(); private java.util.Set<Integer> existingUsers = java.util.Set.of(1001, 1002, 1003); public String getUser(int userId) { String cacheKey = "user:" + userId; // 检查缓存 if (cache.containsKey(cacheKey)) { System.out.println("从缓存获取: " + cacheKey); return cache.get(cacheKey); } // 查询数据库 System.out.println("查询数据库: " + userId); if (existingUsers.contains(userId)) { String userData = "用户" + userId + "的数据"; cache.put(cacheKey, userData); return userData; } else { // 缓存空值 cache.put(cacheKey, "NULL"); System.out.println("缓存空值: " + cacheKey); return null; } } }
2. 缓存击穿问题与解决方案
2.1 缓存击穿原理
public class CacheBreakdownSolution { /* * 缓存击穿问题: * * 1. 问题描述 * - 热点数据缓存过期 * - 大量并发请求同时访问 * - 瞬间压垮数据库 * * 2. 解决方案 * - 互斥锁 * - 热点数据永不过期 * - 提前刷新 */ public void demonstrateCacheBreakdown() { System.out.println("=== 缓存击穿解决方案演示 ==="); demonstrateMutexLock(); demonstrateNeverExpire(); demonstratePreRefresh(); } private void demonstrateMutexLock() { System.out.println("--- 互斥锁解决方案 ---"); MockMutexCacheService mutexCache = new MockMutexCacheService(); System.out.println("1. 模拟并发请求:"); // 模拟10个并发请求 for (int i = 1; i <= 10; i++) { final int requestId = i; new Thread(() -> { String result = mutexCache.getHotData("hot_key_001", requestId); System.out.println("请求" + requestId + "结果: " + result); }).start(); } try { Thread.sleep(2000); // 等待所有请求完成 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("\n2. 互斥锁特点:"); System.out.println(" - 只有一个线程查询数据库"); System.out.println(" - 其他线程等待或返回旧数据"); System.out.println(" - 避免数据库压力过大"); } private void demonstrateNeverExpire() { System.out.println("\n--- 热点数据永不过期 ---"); MockNeverExpireCache neverExpireCache = new MockNeverExpireCache(); System.out.println("1. 设置热点数据:"); neverExpireCache.setHotData("hot_product_001", "热门商品数据"); System.out.println("\n2. 后台异步刷新:"); neverExpireCache.startAsyncRefresh(); System.out.println("\n3. 永不过期策略:"); System.out.println(" - 逻辑过期时间"); System.out.println(" - 后台异步更新"); System.out.println(" - 保证数据可用性"); } private void demonstratePreRefresh() { System.out.println("\n--- 提前刷新解决方案 ---"); MockPreRefreshCache preRefreshCache = new MockPreRefreshCache(); System.out.println("1. 检查缓存过期时间:"); preRefreshCache.checkAndRefresh("product_001"); System.out.println("\n2. 提前刷新策略:"); System.out.println(" - 过期前30秒开始刷新"); System.out.println(" - 异步更新缓存"); System.out.println(" - 用户无感知更新"); } } // 模拟互斥锁缓存服务 class MockMutexCacheService { private java.util.Map<String, String> cache = new java.util.H
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经