1. 缓存三大问题概述

缓存是提升系统性能的关键技术,但在高并发场景下,缓存系统面临着三大核心问题:缓存雪崩、缓存击穿和缓存穿透。这些问题如果不妥善处理,会导致系统性能急剧下降甚至服务不可用。本文将从架构师的角度深入分析这三大问题的成因、影响和解决方案。

1.1 缓存三大问题对比

1
2
3
4
5
6
7
8
9
10
11
12
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ 缓存雪崩 │ │ 缓存击穿 │ │ 缓存穿透 │
│ │ │ │ │ │
│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │
│ │ 大量失效 │ │ │ │ 热点失效 │ │ │ │ 查询空值 │ │
│ │ 同时发生 │ │ │ │ 瞬间并发 │ │ │ │ 绕过缓存 │ │
│ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │
│ │ │ │ │ │
│ • 影响范围大 │ │ • 热点数据 │ │ • 恶意攻击 │
│ • 系统压力大 │ │ • 瞬间高并发 │ │ • 数据库压力 │
│ • 恢复时间长 │ │ • 单点故障 │ │ • 资源浪费 │
└─────────────────┘ └─────────────────┘ └─────────────────┘

1.2 问题影响分析

  1. 缓存雪崩: 大量缓存同时失效,导致数据库压力激增
  2. 缓存击穿: 热点数据失效,瞬间大量请求直接访问数据库
  3. 缓存穿透: 查询不存在的数据,绕过缓存直接访问数据库

2. 缓存雪崩深度解析

2.1 缓存雪崩成因分析

缓存雪崩是指缓存中大量数据同时过期失效,导致大量请求直接访问数据库,造成数据库压力激增甚至崩溃的现象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// 缓存雪崩场景模拟
@Component
@Slf4j
public class CacheAvalancheSimulator {

private final RedisTemplate<String, Object> redisTemplate;
private final JdbcTemplate jdbcTemplate;
private final MeterRegistry meterRegistry;

public CacheAvalancheSimulator(RedisTemplate<String, Object> redisTemplate,
JdbcTemplate jdbcTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.jdbcTemplate = jdbcTemplate;
this.meterRegistry = meterRegistry;
}

// 模拟缓存雪崩场景
public void simulateCacheAvalanche() {
log.info("Starting cache avalanche simulation");

try {
// 设置大量缓存数据,同时过期
setCacheDataWithSameExpiration();

// 等待缓存过期
Thread.sleep(1000);

// 模拟大量并发请求
simulateConcurrentRequests();

} catch (Exception e) {
log.error("Error during cache avalanche simulation", e);
}
}

// 设置相同过期时间的缓存数据
private void setCacheDataWithSameExpiration() {
log.info("Setting cache data with same expiration time");

for (int i = 1; i <= 1000; i++) {
String key = "user:" + i;
String value = "user_data_" + i;

// 所有数据设置相同的过期时间(5秒)
redisTemplate.opsForValue().set(key, value, Duration.ofSeconds(5));
}

log.info("Cache data set with same expiration time");
}

// 模拟并发请求
private void simulateConcurrentRequests() {
log.info("Simulating concurrent requests");

ExecutorService executor = Executors.newFixedThreadPool(100);
CountDownLatch latch = new CountDownLatch(1000);

for (int i = 0; i < 1000; i++) {
final int userId = i + 1;
executor.submit(() -> {
try {
getUserData(userId);
} finally {
latch.countDown();
}
});
}

try {
latch.await();
executor.shutdown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 获取用户数据(模拟业务逻辑)
private String getUserData(int userId) {
String key = "user:" + userId;

try {
// 先从缓存获取
String cachedData = (String) redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.hit").increment();
return cachedData;
}

// 缓存未命中,从数据库获取
meterRegistry.counter("cache.miss").increment();
String dbData = getDataFromDatabase(userId);

// 重新设置缓存
redisTemplate.opsForValue().set(key, dbData, Duration.ofSeconds(300));

return dbData;

} catch (Exception e) {
log.error("Error getting user data for ID: {}", userId, e);
meterRegistry.counter("cache.error").increment();
return null;
}
}

// 从数据库获取数据
private String getDataFromDatabase(int userId) {
try {
// 模拟数据库查询
Thread.sleep(10); // 模拟数据库延迟
return "user_data_from_db_" + userId;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
}

2.2 缓存雪崩解决方案

2.2.1 随机过期时间策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 随机过期时间缓存管理器
@Component
@Slf4j
public class RandomExpirationCacheManager {

private final RedisTemplate<String, Object> redisTemplate;
private final Random random = new Random();

public RandomExpirationCacheManager(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

// 设置带随机过期时间的缓存
public void setWithRandomExpiration(String key, Object value, Duration baseExpiration) {
// 在基础过期时间基础上增加随机时间(±20%)
long baseSeconds = baseExpiration.getSeconds();
long randomOffset = (long) (baseSeconds * 0.2 * (random.nextDouble() - 0.5));
long finalSeconds = baseSeconds + randomOffset;

Duration randomExpiration = Duration.ofSeconds(Math.max(1, finalSeconds));

redisTemplate.opsForValue().set(key, value, randomExpiration);

log.debug("Set cache with random expiration: key={}, expiration={}s",
key, randomExpiration.getSeconds());
}

// 批量设置带随机过期时间的缓存
public void batchSetWithRandomExpiration(Map<String, Object> data, Duration baseExpiration) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
setWithRandomExpiration(entry.getKey(), entry.getValue(), baseExpiration);
}
}

// 获取随机过期时间
public Duration getRandomExpiration(Duration baseExpiration) {
long baseSeconds = baseExpiration.getSeconds();
long randomOffset = (long) (baseSeconds * 0.2 * (random.nextDouble() - 0.5));
long finalSeconds = baseSeconds + randomOffset;

return Duration.ofSeconds(Math.max(1, finalSeconds));
}
}

2.2.2 缓存预热策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// 缓存预热管理器
@Service
@Slf4j
public class CacheWarmupManager {

private final RedisTemplate<String, Object> redisTemplate;
private final RandomExpirationCacheManager randomExpirationManager;
private final UserService userService;

public CacheWarmupManager(RedisTemplate<String, Object> redisTemplate,
RandomExpirationCacheManager randomExpirationManager,
UserService userService) {
this.redisTemplate = redisTemplate;
this.randomExpirationManager = randomExpirationManager;
this.userService = userService;
}

// 系统启动时预热缓存
@EventListener(ApplicationReadyEvent.class)
public void warmupCacheOnStartup() {
log.info("Starting cache warmup on application startup");

CompletableFuture.runAsync(() -> {
try {
// 预热用户数据
warmupUserCache();

// 预热商品数据
warmupProductCache();

// 预热配置数据
warmupConfigCache();

log.info("Cache warmup completed successfully");

} catch (Exception e) {
log.error("Error during cache warmup", e);
}
});
}

// 预热用户缓存
private void warmupUserCache() {
log.info("Warming up user cache");

try {
// 获取活跃用户列表
List<User> activeUsers = userService.getActiveUsers();

Map<String, Object> userCacheData = new HashMap<>();
for (User user : activeUsers) {
String key = "user:" + user.getId();
userCacheData.put(key, user);
}

// 批量设置缓存,使用随机过期时间
randomExpirationManager.batchSetWithRandomExpiration(
userCacheData, Duration.ofHours(2));

log.info("User cache warmup completed: {} users", activeUsers.size());

} catch (Exception e) {
log.error("Error warming up user cache", e);
}
}

// 预热商品缓存
private void warmupProductCache() {
log.info("Warming up product cache");

try {
// 获取热门商品列表
List<Product> hotProducts = userService.getHotProducts();

Map<String, Object> productCacheData = new HashMap<>();
for (Product product : hotProducts) {
String key = "product:" + product.getId();
productCacheData.put(key, product);
}

// 批量设置缓存,使用随机过期时间
randomExpirationManager.batchSetWithRandomExpiration(
productCacheData, Duration.ofHours(1));

log.info("Product cache warmup completed: {} products", hotProducts.size());

} catch (Exception e) {
log.error("Error warming up product cache", e);
}
}

// 预热配置缓存
private void warmupConfigCache() {
log.info("Warming up config cache");

try {
// 获取系统配置
Map<String, Object> configs = userService.getSystemConfigs();

// 批量设置缓存,使用随机过期时间
randomExpirationManager.batchSetWithRandomExpiration(
configs, Duration.ofMinutes(30));

log.info("Config cache warmup completed: {} configs", configs.size());

} catch (Exception e) {
log.error("Error warming up config cache", e);
}
}

// 定时预热缓存
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
public void scheduledCacheWarmup() {
log.info("Starting scheduled cache warmup");

try {
// 预热热点数据
warmupHotData();

log.info("Scheduled cache warmup completed");

} catch (Exception e) {
log.error("Error during scheduled cache warmup", e);
}
}

// 预热热点数据
private void warmupHotData() {
log.info("Warming up hot data");

try {
// 获取今日热点数据
List<String> hotKeys = userService.getTodayHotKeys();

for (String key : hotKeys) {
Object data = userService.getDataByKey(key);
if (data != null) {
randomExpirationManager.setWithRandomExpiration(
key, data, Duration.ofHours(1));
}
}

log.info("Hot data warmup completed: {} keys", hotKeys.size());

} catch (Exception e) {
log.error("Error warming up hot data", e);
}
}
}

2.2.3 熔断降级策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 缓存熔断降级管理器
@Component
@Slf4j
public class CacheCircuitBreakerManager {

private final RedisTemplate<String, Object> redisTemplate;
private final CircuitBreaker circuitBreaker;
private final MeterRegistry meterRegistry;

public CacheCircuitBreakerManager(RedisTemplate<String, Object> redisTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.meterRegistry = meterRegistry;

// 配置熔断器
this.circuitBreaker = CircuitBreaker.ofDefaults("cache-circuit-breaker")
.toBuilder()
.failureRateThreshold(50) // 失败率阈值50%
.waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断30秒
.slidingWindowSize(10) // 滑动窗口大小
.minimumNumberOfCalls(5) // 最小调用次数
.build();
}

// 带熔断保护的缓存获取
public <T> T getWithCircuitBreaker(String key, Class<T> type, Supplier<T> fallback) {
return circuitBreaker.executeSupplier(() -> {
try {
// 尝试从缓存获取
Object cachedData = redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.circuit_breaker.hit").increment();
return type.cast(cachedData);
}

// 缓存未命中,执行降级逻辑
meterRegistry.counter("cache.circuit_breaker.miss").increment();
return fallback.get();

} catch (Exception e) {
log.error("Error in circuit breaker cache get", e);
meterRegistry.counter("cache.circuit_breaker.error").increment();
throw e;
}
});
}

// 带熔断保护的缓存设置
public void setWithCircuitBreaker(String key, Object value, Duration expiration) {
circuitBreaker.executeRunnable(() -> {
try {
redisTemplate.opsForValue().set(key, value, expiration);
meterRegistry.counter("cache.circuit_breaker.set_success").increment();

} catch (Exception e) {
log.error("Error in circuit breaker cache set", e);
meterRegistry.counter("cache.circuit_breaker.set_error").increment();
throw e;
}
});
}

// 获取熔断器状态
public CircuitBreaker.State getCircuitBreakerState() {
return circuitBreaker.getState();
}

// 重置熔断器
public void resetCircuitBreaker() {
circuitBreaker.reset();
log.info("Circuit breaker reset");
}

// 获取熔断器指标
public CircuitBreakerMetrics getCircuitBreakerMetrics() {
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();

return CircuitBreakerMetrics.builder()
.failureRate(metrics.getFailureRate())
.numberOfBufferedCalls(metrics.getNumberOfBufferedCalls())
.numberOfFailedCalls(metrics.getNumberOfFailedCalls())
.numberOfSuccessfulCalls(metrics.getNumberOfSuccessfulCalls())
.numberOfNotPermittedCalls(metrics.getNumberOfNotPermittedCalls())
.build();
}
}

3. 缓存击穿深度解析

3.1 缓存击穿成因分析

缓存击穿是指热点数据在缓存中过期失效的瞬间,大量并发请求直接访问数据库,造成数据库压力激增的现象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// 缓存击穿场景模拟
@Component
@Slf4j
public class CacheBreakdownSimulator {

private final RedisTemplate<String, Object> redisTemplate;
private final JdbcTemplate jdbcTemplate;
private final MeterRegistry meterRegistry;

public CacheBreakdownSimulator(RedisTemplate<String, Object> redisTemplate,
JdbcTemplate jdbcTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.jdbcTemplate = jdbcTemplate;
this.meterRegistry = meterRegistry;
}

// 模拟缓存击穿场景
public void simulateCacheBreakdown() {
log.info("Starting cache breakdown simulation");

try {
// 设置热点数据缓存
String hotKey = "hot:product:1001";
redisTemplate.opsForValue().set(hotKey, "hot_product_data", Duration.ofSeconds(5));

// 等待缓存过期
Thread.sleep(6000);

// 模拟大量并发请求访问热点数据
simulateConcurrentHotDataRequests(hotKey);

} catch (Exception e) {
log.error("Error during cache breakdown simulation", e);
}
}

// 模拟并发访问热点数据
private void simulateConcurrentHotDataRequests(String hotKey) {
log.info("Simulating concurrent hot data requests");

ExecutorService executor = Executors.newFixedThreadPool(50);
CountDownLatch latch = new CountDownLatch(100);

for (int i = 0; i < 100; i++) {
executor.submit(() -> {
try {
getHotData(hotKey);
} finally {
latch.countDown();
}
});
}

try {
latch.await();
executor.shutdown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 获取热点数据
private String getHotData(String key) {
try {
// 先从缓存获取
String cachedData = (String) redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.hot.hit").increment();
return cachedData;
}

// 缓存未命中,从数据库获取
meterRegistry.counter("cache.hot.miss").increment();
String dbData = getHotDataFromDatabase(key);

// 重新设置缓存
redisTemplate.opsForValue().set(key, dbData, Duration.ofSeconds(300));

return dbData;

} catch (Exception e) {
log.error("Error getting hot data for key: {}", key, e);
meterRegistry.counter("cache.hot.error").increment();
return null;
}
}

// 从数据库获取热点数据
private String getHotDataFromDatabase(String key) {
try {
// 模拟数据库查询
Thread.sleep(50); // 模拟数据库延迟
return "hot_data_from_db_" + key;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
}

3.2 缓存击穿解决方案

3.2.1 分布式锁策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// 分布式锁缓存管理器
@Component
@Slf4j
public class DistributedLockCacheManager {

private final RedisTemplate<String, Object> redisTemplate;
private final RedissonClient redissonClient;
private final MeterRegistry meterRegistry;

public DistributedLockCacheManager(RedisTemplate<String, Object> redisTemplate,
RedissonClient redissonClient,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.redissonClient = redissonClient;
this.meterRegistry = meterRegistry;
}

// 使用分布式锁防止缓存击穿
public <T> T getWithDistributedLock(String key, Class<T> type, Supplier<T> dataLoader) {
// 先尝试从缓存获取
Object cachedData = redisTemplate.opsForValue().get(key);
if (cachedData != null) {
meterRegistry.counter("cache.distributed_lock.hit").increment();
return type.cast(cachedData);
}

// 缓存未命中,使用分布式锁
String lockKey = "lock:" + key;
RLock lock = redissonClient.getLock(lockKey);

try {
// 尝试获取锁,最多等待10秒
boolean acquired = lock.tryLock(10, 30, TimeUnit.SECONDS);

if (acquired) {
try {
// 再次检查缓存(双重检查)
cachedData = redisTemplate.opsForValue().get(key);
if (cachedData != null) {
meterRegistry.counter("cache.distributed_lock.double_check_hit").increment();
return type.cast(cachedData);
}

// 从数据源加载数据
meterRegistry.counter("cache.distributed_lock.load_from_source").increment();
T data = dataLoader.get();

if (data != null) {
// 设置缓存
redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));
}

return data;

} finally {
lock.unlock();
}
} else {
// 获取锁失败,等待一段时间后重试
meterRegistry.counter("cache.distributed_lock.lock_failed").increment();
Thread.sleep(100);

// 重试从缓存获取
cachedData = redisTemplate.opsForValue().get(key);
if (cachedData != null) {
return type.cast(cachedData);
}

// 如果仍然没有数据,返回默认值或抛出异常
throw new RuntimeException("Failed to acquire lock and no cached data available");
}

} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Interrupted while waiting for lock", e);
} catch (Exception e) {
log.error("Error in distributed lock cache get", e);
meterRegistry.counter("cache.distributed_lock.error").increment();
throw new RuntimeException("Error in distributed lock cache operation", e);
}
}

// 批量获取带分布式锁的缓存
public <T> Map<String, T> batchGetWithDistributedLock(List<String> keys, Class<T> type,
Function<String, T> dataLoader) {
Map<String, T> result = new HashMap<>();

for (String key : keys) {
try {
T data = getWithDistributedLock(key, type, () -> dataLoader.apply(key));
result.put(key, data);
} catch (Exception e) {
log.error("Error getting data for key: {}", key, e);
}
}

return result;
}

// 异步刷新缓存
public void asyncRefreshCache(String key, Supplier<Object> dataLoader) {
CompletableFuture.runAsync(() -> {
String lockKey = "refresh:" + key;
RLock lock = redissonClient.getLock(lockKey);

try {
boolean acquired = lock.tryLock(5, 10, TimeUnit.SECONDS);

if (acquired) {
try {
Object data = dataLoader.get();
if (data != null) {
redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));
meterRegistry.counter("cache.async_refresh.success").increment();
}
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("Error in async cache refresh", e);
meterRegistry.counter("cache.async_refresh.error").increment();
}
});
}
}

3.2.2 热点数据预加载策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// 热点数据预加载管理器
@Service
@Slf4j
public class HotDataPreloadManager {

private final RedisTemplate<String, Object> redisTemplate;
private final DistributedLockCacheManager lockCacheManager;
private final MeterRegistry meterRegistry;

public HotDataPreloadManager(RedisTemplate<String, Object> redisTemplate,
DistributedLockCacheManager lockCacheManager,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.lockCacheManager = lockCacheManager;
this.meterRegistry = meterRegistry;
}

// 定时预加载热点数据
@Scheduled(fixedDelay = 300000) // 每5分钟执行一次
public void preloadHotData() {
log.info("Starting hot data preload");

try {
// 获取热点数据列表
List<String> hotKeys = getHotDataKeys();

for (String key : hotKeys) {
// 检查缓存是否即将过期
if (isCacheExpiringSoon(key)) {
// 异步预加载数据
asyncPreloadData(key);
}
}

log.info("Hot data preload completed: {} keys processed", hotKeys.size());

} catch (Exception e) {
log.error("Error during hot data preload", e);
}
}

// 获取热点数据键列表
private List<String> getHotDataKeys() {
// 这里可以从业务系统获取热点数据标识
// 或者基于访问频率统计
return Arrays.asList(
"hot:product:1001",
"hot:product:1002",
"hot:user:2001",
"hot:config:system"
);
}

// 检查缓存是否即将过期
private boolean isCacheExpiringSoon(String key) {
try {
Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
return ttl != null && ttl > 0 && ttl < 60; // 60秒内过期
} catch (Exception e) {
log.error("Error checking cache TTL for key: {}", key, e);
return false;
}
}

// 异步预加载数据
private void asyncPreloadData(String key) {
CompletableFuture.runAsync(() -> {
try {
// 使用分布式锁预加载数据
String dataType = extractDataTypeFromKey(key);
Object data = loadDataFromSource(key, dataType);

if (data != null) {
// 设置新的缓存,延长过期时间
redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));
meterRegistry.counter("cache.hot_data_preload.success").increment();

log.debug("Hot data preloaded successfully: {}", key);
}

} catch (Exception e) {
log.error("Error preloading hot data for key: {}", key, e);
meterRegistry.counter("cache.hot_data_preload.error").increment();
}
});
}

// 从键名提取数据类型
private String extractDataTypeFromKey(String key) {
if (key.startsWith("hot:product:")) {
return "product";
} else if (key.startsWith("hot:user:")) {
return "user";
} else if (key.startsWith("hot:config:")) {
return "config";
}
return "unknown";
}

// 从数据源加载数据
private Object loadDataFromSource(String key, String dataType) {
try {
// 模拟从不同数据源加载数据
switch (dataType) {
case "product":
return loadProductData(key);
case "user":
return loadUserData(key);
case "config":
return loadConfigData(key);
default:
return null;
}
} catch (Exception e) {
log.error("Error loading data from source for key: {}", key, e);
return null;
}
}

// 加载商品数据
private Object loadProductData(String key) {
// 模拟数据库查询
try {
Thread.sleep(50);
return "product_data_" + key;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}

// 加载用户数据
private Object loadUserData(String key) {
// 模拟数据库查询
try {
Thread.sleep(30);
return "user_data_" + key;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}

// 加载配置数据
private Object loadConfigData(String key) {
// 模拟配置查询
try {
Thread.sleep(20);
return "config_data_" + key;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}

// 手动触发热点数据预加载
public void manualPreloadHotData(String key) {
log.info("Manual preload triggered for key: {}", key);

try {
asyncPreloadData(key);
} catch (Exception e) {
log.error("Error in manual preload for key: {}", key, e);
}
}
}

4. 缓存穿透深度解析

4.1 缓存穿透成因分析

缓存穿透是指查询不存在的数据,由于缓存中没有该数据,请求直接访问数据库,如果大量这样的请求会导致数据库压力过大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// 缓存穿透场景模拟
@Component
@Slf4j
public class CachePenetrationSimulator {

private final RedisTemplate<String, Object> redisTemplate;
private final JdbcTemplate jdbcTemplate;
private final MeterRegistry meterRegistry;

public CachePenetrationSimulator(RedisTemplate<String, Object> redisTemplate,
JdbcTemplate jdbcTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.jdbcTemplate = jdbcTemplate;
this.meterRegistry = meterRegistry;
}

// 模拟缓存穿透场景
public void simulateCachePenetration() {
log.info("Starting cache penetration simulation");

try {
// 模拟恶意请求,查询不存在的数据
simulateMaliciousRequests();

} catch (Exception e) {
log.error("Error during cache penetration simulation", e);
}
}

// 模拟恶意请求
private void simulateMaliciousRequests() {
log.info("Simulating malicious requests");

ExecutorService executor = Executors.newFixedThreadPool(20);
CountDownLatch latch = new CountDownLatch(100);

for (int i = 0; i < 100; i++) {
final int nonExistentId = 999999 + i; // 不存在的ID
executor.submit(() -> {
try {
getNonExistentData(nonExistentId);
} finally {
latch.countDown();
}
});
}

try {
latch.await();
executor.shutdown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 获取不存在的数据
private String getNonExistentData(int id) {
String key = "user:" + id;

try {
// 先从缓存获取
String cachedData = (String) redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.penetration.hit").increment();
return cachedData;
}

// 缓存未命中,从数据库查询
meterRegistry.counter("cache.penetration.miss").increment();
String dbData = queryNonExistentDataFromDatabase(id);

// 即使数据不存在,也要设置缓存(防止缓存穿透)
if (dbData == null) {
// 设置空值缓存,短时间过期
redisTemplate.opsForValue().set(key, "", Duration.ofMinutes(5));
meterRegistry.counter("cache.penetration.null_cached").increment();
} else {
redisTemplate.opsForValue().set(key, dbData, Duration.ofMinutes(30));
}

return dbData;

} catch (Exception e) {
log.error("Error getting non-existent data for ID: {}", id, e);
meterRegistry.counter("cache.penetration.error").increment();
return null;
}
}

// 从数据库查询不存在的数据
private String queryNonExistentDataFromDatabase(int id) {
try {
// 模拟数据库查询
Thread.sleep(100); // 模拟数据库延迟
// 返回null表示数据不存在
return null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
}

4.2 缓存穿透解决方案

4.2.1 布隆过滤器策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 布隆过滤器缓存管理器
@Component
@Slf4j
public class BloomFilterCacheManager {

private final RedisTemplate<String, Object> redisTemplate;
private final BloomFilter<String> bloomFilter;
private final MeterRegistry meterRegistry;

public BloomFilterCacheManager(RedisTemplate<String, Object> redisTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.meterRegistry = meterRegistry;

// 初始化布隆过滤器
this.bloomFilter = BloomFilter.create(
Funnels.stringFunnel(Charset.defaultCharset()),
1000000, // 预期插入数量
0.01 // 误判率
);

// 初始化布隆过滤器数据
initializeBloomFilter();
}

// 初始化布隆过滤器
private void initializeBloomFilter() {
log.info("Initializing bloom filter");

try {
// 从数据库加载所有有效的数据键
List<String> validKeys = loadValidKeysFromDatabase();

for (String key : validKeys) {
bloomFilter.put(key);
}

log.info("Bloom filter initialized with {} keys", validKeys.size());

} catch (Exception e) {
log.error("Error initializing bloom filter", e);
}
}

// 从数据库加载有效键
private List<String> loadValidKeysFromDatabase() {
// 模拟从数据库加载有效键
List<String> keys = new ArrayList<>();

// 模拟用户ID
for (int i = 1; i <= 100000; i++) {
keys.add("user:" + i);
}

// 模拟商品ID
for (int i = 1; i <= 50000; i++) {
keys.add("product:" + i);
}

return keys;
}

// 使用布隆过滤器检查数据是否存在
public <T> T getWithBloomFilter(String key, Class<T> type, Supplier<T> dataLoader) {
try {
// 先检查布隆过滤器
if (!bloomFilter.mightContain(key)) {
meterRegistry.counter("cache.bloom_filter.rejected").increment();
log.debug("Key rejected by bloom filter: {}", key);
return null; // 数据肯定不存在
}

// 布隆过滤器认为可能存在,检查缓存
Object cachedData = redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.bloom_filter.cache_hit").increment();
return type.cast(cachedData);
}

// 缓存未命中,从数据源加载
meterRegistry.counter("cache.bloom_filter.cache_miss").increment();
T data = dataLoader.get();

if (data != null) {
// 数据存在,设置缓存
redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));
meterRegistry.counter("cache.bloom_filter.data_found").increment();
} else {
// 数据不存在,设置空值缓存
redisTemplate.opsForValue().set(key, "", Duration.ofMinutes(5));
meterRegistry.counter("cache.bloom_filter.data_not_found").increment();
}

return data;

} catch (Exception e) {
log.error("Error in bloom filter cache get", e);
meterRegistry.counter("cache.bloom_filter.error").increment();
return null;
}
}

// 添加键到布隆过滤器
public void addKeyToBloomFilter(String key) {
try {
bloomFilter.put(key);
meterRegistry.counter("cache.bloom_filter.key_added").increment();
} catch (Exception e) {
log.error("Error adding key to bloom filter", e);
}
}

// 批量添加键到布隆过滤器
public void batchAddKeysToBloomFilter(List<String> keys) {
try {
for (String key : keys) {
bloomFilter.put(key);
}
meterRegistry.counter("cache.bloom_filter.keys_added", keys.size()).increment();
} catch (Exception e) {
log.error("Error batch adding keys to bloom filter", e);
}
}

// 获取布隆过滤器统计信息
public BloomFilterStats getBloomFilterStats() {
return BloomFilterStats.builder()
.expectedInsertions(1000000)
.falsePositiveRate(0.01)
.approximateElementCount(bloomFilter.approximateElementCount())
.build();
}
}

4.2.2 空值缓存策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 空值缓存管理器
@Component
@Slf4j
public class NullValueCacheManager {

private final RedisTemplate<String, Object> redisTemplate;
private final MeterRegistry meterRegistry;

public NullValueCacheManager(RedisTemplate<String, Object> redisTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.meterRegistry = meterRegistry;
}

// 带空值缓存的获取方法
public <T> T getWithNullValueCache(String key, Class<T> type, Supplier<T> dataLoader) {
try {
// 先从缓存获取
Object cachedData = redisTemplate.opsForValue().get(key);

if (cachedData != null) {
// 检查是否为空值标记
if (isNullValueMarker(cachedData)) {
meterRegistry.counter("cache.null_value.hit").increment();
return null; // 返回null表示数据不存在
}

meterRegistry.counter("cache.null_value.data_hit").increment();
return type.cast(cachedData);
}

// 缓存未命中,从数据源加载
meterRegistry.counter("cache.null_value.miss").increment();
T data = dataLoader.get();

if (data != null) {
// 数据存在,设置正常缓存
redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));
meterRegistry.counter("cache.null_value.data_cached").increment();
} else {
// 数据不存在,设置空值缓存
setNullValueCache(key);
meterRegistry.counter("cache.null_value.null_cached").increment();
}

return data;

} catch (Exception e) {
log.error("Error in null value cache get", e);
meterRegistry.counter("cache.null_value.error").increment();
return null;
}
}

// 检查是否为空值标记
private boolean isNullValueMarker(Object data) {
return data instanceof String && "NULL_VALUE_MARKER".equals(data);
}

// 设置空值缓存
private void setNullValueCache(String key) {
try {
// 使用特殊标记表示空值
redisTemplate.opsForValue().set(key, "NULL_VALUE_MARKER", Duration.ofMinutes(5));
} catch (Exception e) {
log.error("Error setting null value cache", e);
}
}

// 批量设置空值缓存
public void batchSetNullValueCache(List<String> keys) {
try {
for (String key : keys) {
setNullValueCache(key);
}
meterRegistry.counter("cache.null_value.batch_null_cached", keys.size()).increment();
} catch (Exception e) {
log.error("Error batch setting null value cache", e);
}
}

// 清理空值缓存
public void clearNullValueCache(String key) {
try {
redisTemplate.delete(key);
meterRegistry.counter("cache.null_value.cleared").increment();
} catch (Exception e) {
log.error("Error clearing null value cache", e);
}
}

// 批量清理空值缓存
public void batchClearNullValueCache(List<String> keys) {
try {
redisTemplate.delete(keys);
meterRegistry.counter("cache.null_value.batch_cleared", keys.size()).increment();
} catch (Exception e) {
log.error("Error batch clearing null value cache", e);
}
}

// 获取空值缓存统计
public NullValueCacheStats getNullValueCacheStats() {
return NullValueCacheStats.builder()
.nullValueHits(meterRegistry.counter("cache.null_value.hit").count())
.dataHits(meterRegistry.counter("cache.null_value.data_hit").count())
.misses(meterRegistry.counter("cache.null_value.miss").count())
.nullValuesCached(meterRegistry.counter("cache.null_value.null_cached").count())
.dataCached(meterRegistry.counter("cache.null_value.data_cached").count())
.errors(meterRegistry.counter("cache.null_value.error").count())
.build();
}
}

5. 综合解决方案架构

5.1 统一缓存管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// 统一缓存管理器
@Service
@Slf4j
public class UnifiedCacheManager {

private final RedisTemplate<String, Object> redisTemplate;
private final RandomExpirationCacheManager randomExpirationManager;
private final DistributedLockCacheManager lockCacheManager;
private final BloomFilterCacheManager bloomFilterManager;
private final NullValueCacheManager nullValueManager;
private final CircuitBreakerManager circuitBreakerManager;
private final MeterRegistry meterRegistry;

public UnifiedCacheManager(RedisTemplate<String, Object> redisTemplate,
RandomExpirationCacheManager randomExpirationManager,
DistributedLockCacheManager lockCacheManager,
BloomFilterCacheManager bloomFilterManager,
NullValueCacheManager nullValueManager,
CircuitBreakerManager circuitBreakerManager,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.randomExpirationManager = randomExpirationManager;
this.lockCacheManager = lockCacheManager;
this.bloomFilterManager = bloomFilterManager;
this.nullValueManager = nullValueManager;
this.circuitBreakerManager = circuitBreakerManager;
this.meterRegistry = meterRegistry;
}

// 智能缓存获取
public <T> T get(String key, Class<T> type, Supplier<T> dataLoader, CacheStrategy strategy) {
try {
switch (strategy) {
case NORMAL:
return getNormal(key, type, dataLoader);
case HOT_DATA:
return getHotData(key, type, dataLoader);
case BLOOM_FILTER:
return getWithBloomFilter(key, type, dataLoader);
case CIRCUIT_BREAKER:
return getWithCircuitBreaker(key, type, dataLoader);
default:
return getNormal(key, type, dataLoader);
}
} catch (Exception e) {
log.error("Error in unified cache get", e);
meterRegistry.counter("cache.unified.error").increment();
return null;
}
}

// 普通缓存获取
private <T> T getNormal(String key, Class<T> type, Supplier<T> dataLoader) {
try {
Object cachedData = redisTemplate.opsForValue().get(key);

if (cachedData != null) {
meterRegistry.counter("cache.unified.normal.hit").increment();
return type.cast(cachedData);
}

// 缓存未命中,从数据源加载
meterRegistry.counter("cache.unified.normal.miss").increment();
T data = dataLoader.get();

if (data != null) {
// 使用随机过期时间设置缓存
randomExpirationManager.setWithRandomExpiration(key, data, Duration.ofMinutes(30));
} else {
// 设置空值缓存
nullValueManager.setNullValueCache(key);
}

return data;

} catch (Exception e) {
log.error("Error in normal cache get", e);
return null;
}
}

// 热点数据获取
private <T> T getHotData(String key, Class<T> type, Supplier<T> dataLoader) {
return lockCacheManager.getWithDistributedLock(key, type, dataLoader);
}

// 布隆过滤器获取
private <T> T getWithBloomFilter(String key, Class<T> type, Supplier<T> dataLoader) {
return bloomFilterManager.getWithBloomFilter(key, type, dataLoader);
}

// 熔断器获取
private <T> T getWithCircuitBreaker(String key, Class<T> type, Supplier<T> dataLoader) {
return circuitBreakerManager.getWithCircuitBreaker(key, type, fallback);
}

// 智能缓存设置
public void set(String key, Object value, Duration expiration, CacheStrategy strategy) {
try {
switch (strategy) {
case NORMAL:
randomExpirationManager.setWithRandomExpiration(key, value, expiration);
break;
case HOT_DATA:
redisTemplate.opsForValue().set(key, value, expiration);
break;
case CIRCUIT_BREAKER:
circuitBreakerManager.setWithCircuitBreaker(key, value, expiration);
break;
default:
randomExpirationManager.setWithRandomExpiration(key, value, expiration);
}

meterRegistry.counter("cache.unified.set.success").increment();

} catch (Exception e) {
log.error("Error in unified cache set", e);
meterRegistry.counter("cache.unified.set.error").increment();
}
}

// 批量获取
public <T> Map<String, T> batchGet(List<String> keys, Class<T> type,
Function<String, T> dataLoader, CacheStrategy strategy) {
Map<String, T> result = new HashMap<>();

for (String key : keys) {
try {
T data = get(key, type, () -> dataLoader.apply(key), strategy);
result.put(key, data);
} catch (Exception e) {
log.error("Error getting data for key: {}", key, e);
}
}

return result;
}

// 获取缓存统计信息
public CacheStats getCacheStats() {
return CacheStats.builder()
.normalHits(meterRegistry.counter("cache.unified.normal.hit").count())
.normalMisses(meterRegistry.counter("cache.unified.normal.miss").count())
.hotDataHits(meterRegistry.counter("cache.distributed_lock.hit").count())
.hotDataMisses(meterRegistry.counter("cache.distributed_lock.miss").count())
.bloomFilterRejected(meterRegistry.counter("cache.bloom_filter.rejected").count())
.bloomFilterCacheHits(meterRegistry.counter("cache.bloom_filter.cache_hit").count())
.nullValueHits(meterRegistry.counter("cache.null_value.hit").count())
.circuitBreakerHits(meterRegistry.counter("cache.circuit_breaker.hit").count())
.circuitBreakerMisses(meterRegistry.counter("cache.circuit_breaker.miss").count())
.errors(meterRegistry.counter("cache.unified.error").count())
.build();
}
}

5.2 缓存策略枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 缓存策略枚举
public enum CacheStrategy {
NORMAL("普通缓存", "适用于一般数据,使用随机过期时间"),
HOT_DATA("热点数据", "适用于热点数据,使用分布式锁防止击穿"),
BLOOM_FILTER("布隆过滤", "适用于防穿透场景,使用布隆过滤器"),
CIRCUIT_BREAKER("熔断降级", "适用于高并发场景,使用熔断器保护");

private final String name;
private final String description;

CacheStrategy(String name, String description) {
this.name = name;
this.description = description;
}

public String getName() {
return name;
}

public String getDescription() {
return description;
}
}

6. 监控与告警

6.1 缓存监控配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 缓存监控配置
@Configuration
public class CacheMonitoringConfig {

@Bean
public AlertRule cacheAvalancheAlertRule() {
return AlertRule.builder()
.name("Cache Avalanche Detected")
.description("Cache avalanche detected - high cache miss rate")
.condition("cache.unified.normal.miss > 1000 per minute")
.severity(AlertSeverity.CRITICAL)
.enabled(true)
.build();
}

@Bean
public AlertRule cacheBreakdownAlertRule() {
return AlertRule.builder()
.name("Cache Breakdown Detected")
.description("Cache breakdown detected - hot data cache miss")
.condition("cache.distributed_lock.miss > 100 per minute")
.severity(AlertSeverity.WARNING)
.enabled(true)
.build();
}

@Bean
public AlertRule cachePenetrationAlertRule() {
return AlertRule.builder()
.name("Cache Penetration Detected")
.description("Cache penetration detected - high bloom filter rejections")
.condition("cache.bloom_filter.rejected > 500 per minute")
.severity(AlertSeverity.WARNING)
.enabled(true)
.build();
}

@Bean
public AlertRule circuitBreakerOpenAlertRule() {
return AlertRule.builder()
.name("Cache Circuit Breaker Open")
.description("Cache circuit breaker is open")
.condition("cache.circuit_breaker.state == 'OPEN'")
.severity(AlertSeverity.CRITICAL)
.enabled(true)
.build();
}

@Bean
public AlertRule highCacheErrorRateAlertRule() {
return AlertRule.builder()
.name("High Cache Error Rate")
.description("Cache error rate is too high")
.condition("cache.unified.error > 50 per minute")
.severity(AlertSeverity.WARNING)
.enabled(true)
.build();
}
}

6.2 缓存健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 缓存健康检查器
@Component
@Slf4j
public class CacheHealthChecker implements HealthIndicator {

private final UnifiedCacheManager cacheManager;
private final RedisTemplate<String, Object> redisTemplate;

public CacheHealthChecker(UnifiedCacheManager cacheManager,
RedisTemplate<String, Object> redisTemplate) {
this.cacheManager = cacheManager;
this.redisTemplate = redisTemplate;
}

@Override
public Health health() {
Health.Builder builder = new Health.Builder();

try {
// 检查Redis连接
if (isRedisHealthy()) {
builder.withDetail("redis", "UP");
} else {
builder.withDetail("redis", "DOWN");
builder.down();
}

// 检查缓存统计
CacheStats stats = cacheManager.getCacheStats();
builder.withDetail("cache_stats", stats);

// 检查缓存命中率
double hitRate = calculateHitRate(stats);
builder.withDetail("hit_rate", hitRate);

if (hitRate < 0.8) {
builder.withDetail("hit_rate_status", "LOW");
builder.down();
} else {
builder.withDetail("hit_rate_status", "GOOD");
}

// 检查错误率
long totalRequests = stats.getNormalHits() + stats.getNormalMisses() +
stats.getHotDataHits() + stats.getHotDataMisses();
double errorRate = (double) stats.getErrors() / Math.max(totalRequests, 1);

builder.withDetail("error_rate", errorRate);

if (errorRate > 0.01) {
builder.withDetail("error_rate_status", "HIGH");
builder.down();
} else {
builder.withDetail("error_rate_status", "NORMAL");
}

} catch (Exception e) {
log.error("Error checking cache health", e);
builder.down().withDetail("error", e.getMessage());
}

return builder.build();
}

// 检查Redis健康状态
private boolean isRedisHealthy() {
try {
redisTemplate.opsForValue().get("health_check");
return true;
} catch (Exception e) {
log.error("Redis health check failed", e);
return false;
}
}

// 计算缓存命中率
private double calculateHitRate(CacheStats stats) {
long totalHits = stats.getNormalHits() + stats.getHotDataHits() +
stats.getBloomFilterCacheHits() + stats.getNullValueHits() +
stats.getCircuitBreakerHits();

long totalRequests = totalHits + stats.getNormalMisses() +
stats.getHotDataMisses() + stats.getCircuitBreakerMisses();

return totalRequests > 0 ? (double) totalHits / totalRequests : 0.0;
}
}

7. 总结

缓存雪崩、缓存击穿和缓存穿透是分布式系统中常见的三大缓存问题。通过深入分析问题成因和影响,本文提供了完整的架构级解决方案。

7.1 问题对比总结

问题类型 成因 影响范围 解决方案
缓存雪崩 大量缓存同时失效 系统整体 随机过期时间、缓存预热、熔断降级
缓存击穿 热点数据失效 热点数据 分布式锁、热点预加载
缓存穿透 查询不存在数据 数据库 布隆过滤器、空值缓存

7.2 技术优势

  1. 全面覆盖: 解决缓存三大核心问题
  2. 架构级设计: 提供完整的架构解决方案
  3. 性能优化: 通过多种策略优化缓存性能
  4. 监控完善: 全面的监控和告警机制
  5. 可扩展性: 支持不同场景的缓存策略

7.3 实施要点

  1. 策略选择: 根据业务场景选择合适的缓存策略
  2. 参数调优: 根据实际负载调整缓存参数
  3. 监控告警: 建立完善的监控和告警体系
  4. 测试验证: 定期进行缓存问题模拟测试
  5. 持续优化: 基于监控数据进行持续优化

7.4 最佳实践

  1. 预防为主: 通过合理设计预防缓存问题
  2. 多层防护: 使用多种策略组合防护
  3. 监控驱动: 基于监控数据优化缓存策略
  4. 故障演练: 定期进行缓存故障演练
  5. 文档完善: 维护完整的缓存架构文档

通过本文的学习,您应该已经掌握了缓存三大问题的核心技术和解决方案,能够设计和实现高可用的缓存架构,为企业的系统性能提供可靠的技术保障。