缓存为什么会自动消失?
在开发日常中,你可能遇到过这种情况:用户刚提交的数据,刷新页面却发现还是旧的。查了一圈代码逻辑没问题,最后发现是缓存还没更新。其实,这背后很可能就是缓存的“被动删除”在起作用。
什么是被动删除?
和主动清除缓存(比如手动 del key)不同,被动删除指的是系统在特定条件下自动触发的清理行为。它不靠程序显式调用,而是依赖底层机制,在访问时判断是否该丢弃数据。
最常见的场景:TTL 过期检查
Redis 里设置一个缓存带过期时间,比如 10 分钟。这段时间内每次读取都正常返回值。但一旦超过 10 分钟,下次再 get 的时候,Redis 不会立刻返回旧数据,而是先检查这个 key 是否已过期。如果过期了,就从内存中移除,并返回 nil —— 这个过程就是典型的被动删除。
SET user:1001 \"{"name":"张三","age":28}\" EX 600
上面这行命令设置了用户信息,10 分钟后失效。在这之后第一次访问时,Redis 才真正执行删除动作。也就是说,哪怕已经超时 5 分钟,只要没人去读,那个 key 还占着内存。
懒惰删除的实际影响
这种模式也叫“惰性删除”,优点是节省 CPU 资源——不需要后台一直扫描过期 key。但副作用也很明显:内存可能长时间被无效数据占用。就像你家冰箱里的食物,标签写着保质期三天,可你不打开看,就算坏了也不会有人处理。
配合定期清理更稳妥
所以 Redis 实际上还加了个定时任务,默认每秒随机抽查一些设置了过期时间的 key,删掉其中已过期的。这样既能减轻单次请求的压力,又能避免内存浪费太严重。这个组合策略,让被动删除不至于完全“被动”。
应用层也能做被动控制
不只是数据库层面,应用代码里也可以模拟类似逻辑。比如某个配置项缓存在本地变量里,每次获取时不直接返回,而是先判断是否超过设定时间窗口:
private String cacheData;
private long cacheTime;
private static final long EXPIRE_INTERVAL = 5 * 60 * 1000; // 5分钟
public String getData() {
if (cacheData != null) {
if (System.currentTimeMillis() - cacheTime < EXPIRE_INTERVAL) {
return cacheData; // 未过期,正常使用
} else {
cacheData = null; // 标记为失效
}
}
// 触发重新加载
cacheData = fetchFromDatabase();
cacheTime = System.currentTimeMillis();
return cacheData;
}
这种方式把过期判断放在读操作里,相当于在应用层实现了被动删除。虽然简单,但在小型服务或工具类场景下足够好用。
别忽视边缘情况
想象一下促销活动开始前,大量用户同时刷首页。如果此时缓存刚好过期,所有请求瞬间打到数据库,很容易压垮服务。这就是常说的“缓存雪崩”。被动删除本身没错,但它放大了突发流量的风险。因此合理设置过期时间错峰、引入二级缓存或预热机制,都是必要的补充手段。