当前位置:首页 > 问答 > 正文

Redis数据刷新到底咋搞才算有效,别光知道清缓存还得讲技巧

别急着删,先搞清楚“为什么”要刷新

盲目删缓存是最大的浪费,在动手之前,你得先明确刷新的触发点是什么,根据美团技术团队的文章(《缓存穿透、缓存击穿、缓存雪崩》)里提到的思路,我们得先分情况:

  1. 主动更新:比如后台管理员修改了商品价格,这时候,你知道数据一定变了,刷新的目标是保证用户立刻看到新数据,这是最需要技巧的场景。
  2. 被动失效:数据是自然过期,刷新的目标是平滑地重新加载数据,避免所有请求都砸到数据库上
  3. 异常清理:比如缓存服务重启,或者因为内存不足被强制清理,这种情况下的刷新更像是一种“灾后重建”,目标是把缓存尽快恢复到正常状态。

第二招:对付主动更新——“双写”不是同时写,顺序是关键

Redis数据刷新到底咋搞才算有效,别光知道清缓存还得讲技巧

当你更新数据库的同时,也需要更新缓存,这里最大的坑就是“先更数据库还是先删缓存”?顺序选错,脏数据就来了。

  • 先删缓存,再更新数据库(更推荐)

    • 操作:1. 把缓存里的旧数据删掉,2. 再去更新数据库。
    • 风险:在1和2的极短间隙,如果另一个线程来查询,发现缓存没了,就会去数据库读到更新前的旧数据,并把这个旧数据重新塞回缓存,这样之后所有查询读到的都是脏数据,直到下次刷新。
    • 怎么破? 可以用一个“延迟双删”的技巧,就是在线程A完成数据库更新后,先sleep一小会儿(比如几百毫秒,具体时间取决于业务读写耗时),然后再删一次缓存,这样目的是为了清除掉在A更新数据库期间,其他线程塞进去的脏数据,虽然不完美,但能极大降低脏数据概率。
  • 《阿里巴巴Java开发手册》中提到,缓存数据更新可以采用删除缓存模式,其核心思想是避免复杂的缓存更新逻辑,直接删除,让下一次请求来重建,但这背后隐含了对并发情况下数据一致性的考量,而“延迟双删”就是在这种模式下的一种实践补充。

    Redis数据刷新到底咋搞才算有效,别光知道清缓存还得讲技巧

  • 先更新数据库,再删缓存(最常用)

    • 操作:1. 更新数据库,2. 删缓存。
    • 风险:在1完成之后、2执行之前,如果有查询过来,还是会读到缓存里的旧数据,但因为这个时间窗口非常短,读到旧数据的概率相对较低,一旦2执行完,后续请求就都能拿到新数据了,这个方案简单有效,是很多团队的首选。
    • 注意:如果第二步删除缓存失败了,那就意味着缓存里一直是脏数据,所以最好要有重试机制,比如把删除任务丢到一个消息队列里,确保最终能删掉。

第三招:对付被动失效——别让“缓存击穿”捅了数据库

如果一份热点数据突然过期,恰巧这时有大量请求同时涌来,会发现缓存失效,于是全部请求都会直接打到数据库上,数据库压力陡增,这就是“缓存击穿”。

Redis数据刷新到底咋搞才算有效,别光知道清缓存还得讲技巧

  • 技巧:用“锁”控制只有一个线程去重建 当多个线程同时发现缓存失效时,不要让它们都去数据库查,可以用Redis的SETNX命令(或分布式锁)让其中一个线程“抢”到重建缓存的资格,抢到的线程去数据库加载数据并塞回缓存,其他没抢到的线程就稍微等一会儿,然后直接去缓存里取新数据,这样数据库面前始终只有一个查询请求。
    • 进阶技巧:对于永远不会变的“静态”热点数据(比如城市列表),其实可以设置成永不过期,然后通过上面提到的“主动更新”策略,在数据变更时同时更新缓存和数据库,这样就完全避免了失效带来的问题。

第四招:刷新不是一个人的战斗——考虑用消息队列

在复杂的系统里,数据更新可能来自不同的服务,如果每个服务都直接去删缓存,逻辑会散落各处,不好管理,这时候可以引入消息队列。

  • 操作:任何一个服务更新了数据库后,只做一件事:发一条消息到消息队列,说“某个key的数据变了”,然后由一个专门的“缓存刷新服务”来消费这个消息,负责删除对应的缓存。
  • 好处
    1. 解耦:更新数据库的服务不需要关心缓存刷新的细节和失败重试。
    2. 保证最终一致性:即使某次删除失败,消息还会在队列里,可以反复重试,直到成功。
    3. 削峰填谷:如果短时间内有大量更新,消息队列可以起到缓冲作用,让缓存刷新服务按自己的能力处理,避免被冲垮。

有效的Redis数据刷新技巧:

  1. 心中有数:先判断刷新类型,是主动、被动还是异常。
  2. 主动更新讲顺序:优先“先更新数据库,再删缓存”;想更稳妥,考虑“延迟双删”。
  3. 被动失效防击穿:用分布式锁让只有一个线程重建热点数据,甚至对极热数据考虑永不过期。
  4. 复杂系统靠工具:用消息队列来解耦和保证刷新操作的最终成功。

别再简单粗暴地del key了,结合你的业务场景,选对组合拳,才能让Redis真正成为性能利器,而不是故障的导火索。