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

Redis缓存更新那些事儿,怎么才能让数据访问更快更顺畅

说到用Redis提升网站或应用的访问速度,最关键也最让人头疼的就是缓存更新,用对了,用户体验丝滑流畅;用错了,轻则看到旧数据,重则数据库都可能被压垮,今天我们就来聊聊几种常见的缓存更新套路,看看怎么才能让数据访问又快又稳。

最常见的玩法:Cache-Aside Pattern(旁路缓存策略)

这个策略的名字听起来有点唬人,但其实道理很简单,可以概括为“用时检查,失效重载”。(此策略在《Designing Data-Intensive Applications》等众多技术书籍和博客中均有详细描述)

具体操作分两步:

  1. 读数据时:你的程序在接到请求后,首先会屁颠屁颠地去Redis里查有没有需要的数据,如果有(我们称之为“缓存命中”),太棒了,直接返回给用户,又快又省力,如果没有(“缓存未命中”),那就只能老老实实去数据库里把数据捞出来,这还没完,捞出来之后,程序会顺手把这份数据塞进Redis里,并且设置一个过期时间,比如5分钟,这样,下一个请求来的时候,就能直接从缓存里拿到了。
  2. 写数据时:当用户修改了某个数据(比如更新了昵称),你的程序会直接去数据库里完成更新,紧接着,它会把Redis里对应的那条旧缓存数据给删掉(这步叫“失效缓存”)。

这么做的妙处在于,它把更新的压力完全交给了数据库,Redis只负责读,分工明确,通过设置过期时间,即使删除缓存这一步失败了,最坏的情况也就是用户多看几分钟旧数据,等缓存自动过期后,新的正确数据又会被加载进来,起到了一个兜底的作用,这是目前用得最多、也最稳妥的一种策略。

追求极致速度的玩法:Write-Behind Pattern(写穿透)

我们连“缓存未命中”时去数据库查的那一下都觉得慢,想做到所有读请求都能在Redis里解决,这时候可以试试更激进一点的策略。(此模式在技术社区如阿里云开发者社区等有相关讨论)

Redis缓存更新那些事儿,怎么才能让数据访问更快更顺畅

这个策略的核心是“写操作也绕道缓存”,当要更新数据时,你的程序不再直接写数据库,而是先更新Redis里的缓存数据(这样后续的读请求立刻就能拿到最新值),程序会把这个更新任务丢到一个队列或者记下一笔账,再由另一个后台线程慢悠悠地、分批分次地把这些更新同步到数据库里去。

这样做的好处是所有的读操作都快得飞起,因为数据永远在缓存里并且是最新的,但风险也很大,万一在后台同步到数据库之前,Redis服务器突然宕机了,那部分最新数据就可能永久丢失了,所以这种策略通常只用在对读取速度要求极高,且能容忍极小概率数据丢失的场景。

不太推荐的玩法:Write-Through Pattern(直写策略)

这个策略和Write-Behind有点像,但更“较真”。(此模式在微软等公司的架构文档中常有提及)

Redis缓存更新那些事儿,怎么才能让数据访问更快更顺畅

它要求每次更新数据时,必须同时成功更新缓存和数据库,这两个操作在一个事务里完成,保证要么都成功,要么都失败,这样确实能保证缓存和数据库的强一致性。

但问题也很明显:每次写操作都要同时写缓存和数据库,相当于一次操作干了两次活的力气,写的延迟会变高,有些频繁修改但很少被读取的数据(比如文章的点击量),你也一次次地往缓存里写,很可能费了很大劲更新的缓存数据,根本没人来读,白白浪费了资源,所以这种策略在实际中用得相对较少。

总结一下怎么选

想让数据访问更快更顺畅,没有一刀切的最好方法,关键看你的业务场景:

  • 对于绝大多数普通应用,老老实实用Cache-Aside(旁路缓存) 策略,再给缓存设个合理的过期时间,就已经能解决90%的问题了,简单有效,容错性好。
  • 如果你做的是交易系统、库存系统这类对数据一致性要求非常高的场景,可以考虑加强版的Cache-Aside,比如在更新数据库(注意是后)再删缓存,或者用一些分布式锁来保证更精准的清除,但这会增加复杂度。
  • 如果是社交媒体的点赞数、热点新闻的阅读量这种允许短暂不一致、但要求读性能极高的场景,可以评估一下Write-Behind(写穿透) 的风险和收益。
  • 过期时间是个好东西,它就像个安全阀,无论你用哪种策略,都应该给缓存设置一个,防止脏数据永远存在。

别忘了监控,要时刻关注你的缓存命中率,如果命中率很高,比如95%以上,说明缓存用得其所,数据库压力很小,如果命中率很低,那就要看看是不是缓存的数据不对,或者过期时间设得太短了,得及时调整策略,归根结底,用好缓存的目标就是:让用户尽可能快地拿到他想要的数据,同时让你的数据库能“偷懒”。