Redis缓存数据到底该从哪儿拿,怎么取才靠谱呢?
- 问答
- 2026-01-02 13:12:16
- 1
关于Redis缓存数据到底该从哪儿拿,怎么取才靠谱,这个问题在实际开发中非常关键,处理不好就容易出现数据不一致、系统负载过高甚至服务崩溃的情况,下面我们就来详细聊聊这件事。
核心原则:缓存是数据库的“帮手”,不是“替代品”
首先心里要有个底,Redis这类缓存,它的主要作用是提升读取速度,降低数据库的压力,绝大多数情况下,数据的“唯一真相”或者说最终的数据来源,应该是MySQL这类数据库,缓存里的数据是数据库的一个拷贝,这个拷贝可能不是最新的(允许短暂不一致),但读取速度极快,明确了这层主从关系,后面的策略就好理解了。
数据从哪儿拿?—— 经典的读写策略
数据怎么进入缓存,决定了缓存数据的来源和时效性,主要有两种常见的策略,你可以根据业务场景选择。
旁路缓存模式(Cache-Aside Pattern) 这是最常用、最直观的一种模式,它的逻辑完全由应用程序来控制。
- 读数据时(这是重点):
- 步骤1: 你的程序首先去Redis里查,看看有没有需要的数据。
- 步骤2: 如果Redis里有(我们称之为“缓存命中”),太好了,直接拿来用。
- 步骤3: 如果Redis里没有(称之为“缓存未命中”),程序就老老实实地去数据库里查询。
- 步骤4: 从数据库拿到数据后,做两件事:一是返回给前端,二是把这个数据写到Redis里,这样下次再读就能命中了。
- 写数据时(更新或删除):
- 步骤1: 程序直接去更新数据库。
- 步骤2: 把Redis里对应的旧缓存数据删除掉(注意,是删除而不是直接更新)。
为什么写的时候是删除缓存而不是更新缓存? 这是一个关键点,主要是为了避免脏数据和性能浪费,比如两个连续的写请求,第一个写请求A把数据库更新成了值1,但可能因为网络延迟,它更新缓存的操作慢了点,这时第二个写请求B把数据库更新成了值2,并且顺利地把缓存也更新成了值2,然后请求A的更新缓存操作才到,又把缓存覆盖成了旧的值1,这就导致了数据长时间不一致,直接删除缓存,下次读请求自然会从数据库加载最新值,虽然这次读会慢一点,但能保证最终一致性,如果某个数据写得多读得少,频繁更新缓存就是浪费资源,不如等真正要读的时候再加载。
读写穿透模式(Read-Through / Write-Through) 这种模式里,应用程序不用再操心缓存了,它把任务交给一个专门的缓存组件(或库),应用程序只知道一个统一的入口,它认为这个入口背后既管着缓存也管着数据库。
- 读数据时: 程序向这个缓存组件要数据,如果缓存有,组件直接返回;如果缓存没有,组件自己负责去数据库加载,填满缓存后再返回给程序,这个过程是“穿透”缓存直达数据源的。
- 写数据时: 程序调用这个缓存组件的写接口,组件会先更新数据库,然后更新缓存(注意,这里是更新缓存),保证缓存和数据库的强一致性。
这种模式简化了应用程序的逻辑,但对缓存组件的要求很高,很多缓存中间件(如阿里云的Tair)支持这种模式,自己实现起来比旁路缓存模式要复杂。
怎么取才靠谱?—— 必须考虑的异常情况
光知道正常流程还不够,要想“靠谱”,必须处理各种幺蛾子。
缓存穿透:查一个根本不存在的数据
- 问题: 比如有人恶意攻击,频繁请求一个数据库里根本不存在的用户ID,每次请求都查不到缓存,就会直接打到数据库上,可能把数据库压垮。
- 靠谱解法:
- 缓存空值: 即使从数据库没查到,也在Redis里缓存一个空值(比如
null),并设置一个较短的过期时间(比如1分钟),这样后续同样的请求在过期时间内就会命中这个空值,不会访问数据库。 - 使用布隆过滤器: 在缓存之前,加一层布隆过滤器,它能够以极小的空间代价,快速判断一个数据“一定不存在”或“可能存在”于数据库中,对于“一定不存在”的请求,直接拦截返回,保护数据库。
- 缓存空值: 即使从数据库没查到,也在Redis里缓存一个空值(比如
缓存击穿:某个热点key过期时,大量请求涌向数据库
- 问题: 一个热点key(比如爆款商品信息)一直在被访问,突然它过期失效了,这时海量的请求同时发现缓存失效,会像子弹一样同时打向数据库,造成瞬间压力巨大。
- 靠谱解法:
- 设置热点数据永不过期: 对于极热点数据,可以从业务上设定为永不过期,由程序在更新数据库时主动去刷新缓存。
- 加互斥锁: 这是更常见的做法,当第一个发现缓存失效的请求到来时,它先去获得一个分布式锁,然后才去数据库加载数据,在这个过程中,其他请求如果也发现缓存失效,会尝试获取锁但失败,于是它们可以选择等待一小段时间,然后重新查询缓存,这样就只有第一个请求会去访问数据库。
缓存雪崩:大量key在同一时间点过期
- 问题: 这和击穿类似,但范围更大,如果缓存系统中有大量的key设置了相同的过期时间,比如在凌晨集中失效,那么失效瞬间所有对这些数据的请求都会转向数据库,可能导致数据库崩溃。
- 靠谱解法:
- 错开过期时间: 在给缓存数据设置过期时间时,增加一个随机值,比如基础过期时间是1小时,再加上一个1-5分钟的随机数,这样就能保证key不会在同一时间点大面积失效。
- 构建高可用缓存集群: 即使部分缓存节点宕机,整个缓存系统还能正常工作,避免所有压力直达数据库。
数据从哪里拿?首选“旁路缓存模式”,因为它简单可控,符合大多数业务场景,读的时候先查缓存,没有就查库再回填;写的时候先更新数据库,再删除缓存。
怎么取才靠谱?关键在于预防三种异常情况,用“缓存空值”和“布隆过滤器”防穿透;用“互斥锁”和“永不过期”防击穿;用“随机过期时间”防雪崩,把这些策略融入到你的代码中,你的缓存使用方式就相当靠谱了。
(综合参考了业界常见的缓存实践模式,如《凤凰架构》等技术书籍中关于缓存的论述,以及众多技术社区如Stack Overflow、InfoQ上的相关讨论和解决方案。)

本文由度秀梅于2026-01-02发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/73095.html
