核心思想:应用代码直接管理缓存与数据的同步,分为读写两个流程:
// 伪代码示例
public Data getData(String key) {
// 1. 查本地缓存
Data data = localCache.getIfPresent(key);
if (data != null) return data;
// 2. 查 Redis
data = redis.get(key);
if (data != null) {
// 回填本地缓存
localCache.put(key, data);
return data;
}
// 3. 从数据库加载
data = db.load(key);
if (data != null) {
localCache.put(key, data);
redis.set(key, data);
}
return data;
}
public void updateData(String key, Data newData) {
// 1. 更新数据库
db.update(newData);
// 2. 删除缓存(本地 + Redis)
localCache.invalidate(key);
redis.delete(key);
}
优点:实现简单,适用于读多写少的场景。
缺点:存在短暂不一致窗口(如写入后需等待缓存过期)。
适用场景:分布式系统中,多个应用实例需要同步缓存状态。
方案:
// 发布消息示例(更新数据时)
public void updateData(String key, Data newData) {
db.update(newData);
// 删除 Redis 缓存
redis.delete(key);
// 发布失效事件
redis.publish("cache-invalidation", key);
}
// 订阅消息示例(各实例启动时订阅)
redis.subscribe("cache-invalidation", (channel, message) -> {
localCache.invalidate(message); // 删除本地缓存
});
优点:解耦缓存失效逻辑,适合分布式系统。
缺点:消息可能丢失或延迟,需处理幂等性。
核心思想:为缓存设置合理的 TTL(Time-To-Live),依赖自动过期减少不一致时间窗口。
适用场景:对实时一致性要求不高,允许最终一致性的场景。
优化点:
// 本地缓存设置 TTL
Cache cache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES) // 本地缓存 5 分钟过期
.build();
// Redis 设置 TTL
redis.setex(key, 300, data); // Redis 缓存 5 分钟过期
适用场景:高并发写操作场景,减少缓存脏数据。
流程:
public void updateData(String key, Data newData) {
// 第一步:删除缓存
localCache.invalidate(key);
redis.delete(key);
// 更新数据库
db.update(newData);
// 第二步:延迟删除(如通过异步线程)
scheduleDelete(key, 1000); // 1 秒后再次删除
}
核心思想:通过锁机制保证读写操作的原子性。
方案:
// 使用 Redis 分布式锁(示例)
public void updateDataWithLock(String key, Data newData) {
String lockKey = "lock:" + key;
boolean locked = redis.setnx(lockKey, "locked", 10, TimeUnit.SECONDS);
if (locked) {
try {
// 更新数据库
db.update(newData);
// 删除缓存
localCache.invalidate(key);
redis.delete(key);
} finally {
redis.del(lockKey);
}
} else {
// 获取锁失败,重试或返回错误
}
}
cache.stats()
)监控命中率、延迟等指标。场景 | 推荐方案 |
---|---|
单机应用,低并发 | Cache Aside + TTL |
分布式系统,多实例 | Pub/Sub + Cache Aside |
高并发写操作 | 双删策略 + 分布式锁 |
允许最终一致性 | TTL 过期 + 异步更新 |
通过结合业务需求,灵活采用上述策略,可以有效降低本地缓存与 Redis 的不一致风险。