ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【Redis 进阶】缓存实战:从更新策略到三大经典问题全解析

【Redis 进阶】缓存实战:从更新策略到三大经典问题全解析 草莓熊Lotso个人主页❄️个人专栏:《C知识分享》 《Linux 入门到实践零基础也能懂》✨生活是默默的坚持毅力是永久的享受 博主简介前言在后端开发的技术栈里Redis 最核心的应用场景从来不是纯内存数据库而是缓存。 我们都知道 MySQL 这类关系型数据库扛不住高并发于是在前面加一层 Redis 做缓冲把绝大多数读请求挡在数据库之外是业界最通用的性能优化手段。但很多开发者用缓存只停留在「查之前先查 Redis查到就返回查不到就查库再写回」的简单逻辑。对缓存怎么更新、满了怎么淘汰、常见的穿透 / 雪崩 / 击穿问题一知半解线上一出问题就是数据库打挂、服务雪崩。本文就从缓存的基本原理讲起系统梳理缓存的更新策略、Redis 内置的内存淘汰机制以及缓存三大经典问题的成因与解法帮你把缓存从「能用」用到「好用」。一. 缓存的本质1.1 什么是缓存用一个很生活化的例子就能讲透 出门旅行身份证放在行李箱里容量大但存取麻烦每次安检都要开箱翻找。于是我们会提前把身份证放到上衣口袋里口袋容量小但取放极快每次直接掏出来就行。 这里的「口袋」就是「行李箱」的缓存。速度快的小容量存储给速度慢的大容量存储做缓冲用空间换时间这就是缓存的核心思想。计算机体系里随处可见这个逻辑硬件访问速度天然存在金字塔CPU 寄存器 内存 硬盘 网络上层高速设备天然可以作为下层低速设备的缓存内存是硬盘的缓存这也正是 Redis 的定位硬盘是网络的缓存比如浏览器的本地缓存把静态资源存在本地硬盘不用每次都从网络拉取。1.2 缓存成立的基础二八定律缓存的空间永远远小于后端存储为什么能起到这么大的作用 核心支撑是业务访问的二八定律通常 20% 的数据支撑了 80% 的业务请求。 只要把这 20% 的热点数据放在高速缓存里就能挡住绝大多数请求。剩下 80% 的冷数据就算访问慢一点对整体的影响也非常有限。 这是所有缓存系统成立的前提也是缓存设计的核心逻辑。二. 用 Redis 做数据库缓存2.1 为什么数据库需要缓存关系型数据库以 MySQL 为例性能上天然存在瓶颈原因是多方面的数据持久化在硬盘硬盘 IO 本身速度有限尤其是随机读写场景查询没命中索引就要执行全表扫描磁盘 IO 会指数级上升SQL 执行要经过解析、校验、优化一系列步骤本身就有固定的 CPU 开销复杂联表、聚合查询还会产生笛卡尔积运算性能下降非常明显。也正因此数据库的并发承载能力非常有限流量一高很容易被打穿甚至直接宕机。提升数据库承载能力无非两个思路开源上数据库集群、做分库分表成本高、架构复杂度大节流加一层缓存把热点请求拦在数据库外面。这是成本最低、见效最快的方案也是业界最主流的做法。2.2 标准缓存读写流程最经典的Cache Aside旁路缓存模式是业界的标准用法读请求先查 Redis命中了直接返回数据没命中就去查 MySQL查到数据后顺便写入 Redis再返回给客户端。写请求先更新数据库再删除缓存里对应的 key避免产生脏数据。这样运行一段时间后Redis 里自然就聚集了最常访问的热点数据绝大多数读请求都会被缓存承接数据库的压力会非常小。三. 缓存更新策略缓存里的数据不是一成不变的怎么更新、怎么淘汰直接决定了缓存的命中率和稳定性。常见的更新思路有两种。3.1 定期生成策略也叫离线预热模式。 思路是先通过访问日志统计一段时间内所有 key 的访问频率按热度排序取出 Top N 的热点数据离线批量同步到缓存中。可以按天、按周定期滚动更新。优点过程可控逻辑简单方便排查问题缓存内容稳定对数据库冲击小。缺点实时性差突发的热点事件产生的新热词没法及时进入缓存可能直接打穿数据库。适合业务平稳、热点相对固定的场景比如商品分类、基础配置这类变动少的数据。3.2 实时生成策略也就是上面说的 Cache Aside 模式访问的时候再判断缓存有没有没有就查库并写回。 但这样有个很现实的问题持续写入会让 Redis 内存越来越大总有占满的时候。这时候就需要内存淘汰机制自动删掉相对不热的数据腾出空间存放新数据。Redis 的内存淘汰机制这是面试超高频考点。Redis 提供了完整的淘汰策略体系可以拆解为「四类基础算法 × 两个淘汰范围」。四类基础淘汰算法FIFO先进先出按写入缓存的时间排序最早进来的最早淘汰。实现最简单但完全不考虑访问频率很可能把刚访问的热点数据也淘汰掉实际生产用得很少。LRU最近最少使用记录每个 key 的最近访问时间淘汰最久没有被访问的 key。这是缓存领域最经典的算法核心假设是「最近用过的接下来大概率还会用」。工程实现上 Redis 用的是近似 LRU不是维护完整的双向链表而是随机采样若干 key淘汰其中最久未访问的。精度略有下降但性能开销小很多性价比极高。LFU最不经常使用记录每个 key 的访问次数淘汰访问频次最低的 key。相比 LRU 看「最后访问时间」LFU 看「访问频次」更能精准识别真正的热点数据。 缺点是需要维护计数而且对突发流量不友好 —— 突然火起来的新 key因为累计次数低很容易被淘汰掉。Redis 4.0 之后正式支持该策略。Random随机淘汰完全随机选择 key 淘汰。实现简单、性能最好但效果最差只适合数据冷热完全均匀、无明显热点的场景。两个淘汰范围维度Redis 还按淘汰的 key 范围分成两个维度allkeys从所有 key 里挑选淘汰不管有没有设置过期时间volatile只从设置了过期时间的 key 里挑选淘汰。八种组合策略策略淘汰范围核心算法适用场景allkeys-lru所有 keyLRU最通用缓存场景生产首选volatile-lru仅带过期的 keyLRU永久数据与缓存数据混合存储allkeys-lfu所有 keyLFU访问频次差异大需精准识别热点volatile-lfu仅带过期的 keyLFU带过期的缓存场景精准淘汰allkeys-random所有 key随机数据冷热均匀无明显热点volatile-random仅带过期的 key随机带过期的均匀访问场景volatile-ttl仅带过期的 key按过期时间优先淘汰更早过期的数据noeviction-不淘汰默认策略内存满了直接报错不适合缓存场景生产环境做缓存最常用的就是allkeys-lru简单有效绝大多数场景都适配。四. 缓存使用的四大注意事项缓存不是加了就万事大吉用不好反而会引入更多问题。最经典的就是四大问题预热、穿透、雪崩、击穿。4.1 缓存预热问题现象Redis 刚启动、或者大规模 key 失效之后缓存几乎是空的。这时候所有请求直接穿透到数据库瞬间把数据库压垮。 就像早高峰安检仪刚开机没准备好所有人直接挤到检票口直接造成拥堵。解决方案 上线前先做缓存预热通过离线统计的历史热点数据提前批量导入 Redis。 不用追求 100% 准确只要能挡住 80% 的主流请求就行。后续随着实时访问缓存会自动迭代更新逐渐贴合最新的热点。4.2 缓存穿透问题现象客户端查询的 key不仅 Redis 里没有数据库里也没有。 这样的请求每次都会打到数据库而且永远不会写入缓存。如果量大了一样能把数据库拖垮。 这就叫缓存穿透 —— 相当于缓存这层筛子直接被穿过去了。产生原因业务参数校验不全非法 id、异常格式的请求直接打到数据库运维误操作批量删除了部分数据恶意攻击故意用大量不存在的 key 打爆数据库。解决方案空值缓存就算数据库查不到也给 Redis 写一个空标记值设置一个较短的过期时间。这样后续同样的请求会被缓存挡住不会次次打库。布隆过滤器把所有合法的 key 预先加载到布隆过滤器里请求先过过滤器判定不存在就直接返回根本不用查缓存和数据库。空间开销极小效率极高适合数据量大、key 范围固定的场景。4.3 缓存雪崩问题现象短时间内大量缓存 key 同时失效缓存命中率断崖式下跌海量请求直接打到数据库导致数据库压力飙升甚至宕机。 就像大坝突然垮了洪水直接冲向下游。常见原因Redis 本身宕机或者集群大面积节点故障整个缓存层失效大量 key 设置了完全相同的过期时间同一时间集体失效。解决方案高可用保障用哨兵或者集群保证缓存层的可用性避免单点故障过期时间打散给 key 的过期时间加一个随机偏移量比如基础 1 小时 随机 0~10 分钟避免大量 key 同时过期。4.4 缓存击穿问题现象某一个超高热度的 key突然过期失效了。瞬间成千上万的请求同时打向这一个 key全部穿透到数据库直接把数据库打挂。 可以理解为单点的缓存雪崩是雪崩的特例但因为是核心热点 key破坏力同样很大。解决方案热点 key 永不过期对于确定的超级热点数据不设置过期时间后台异步更新分布式锁限流查询数据库的时候加分布式锁同一时间只允许一个请求去查库写缓存其他请求等待避免把数据库打穿服务降级极端情况下非核心功能直接返回默认值优先保住核心业务。源码视角淘汰策略的工程权衡站在系统编程的角度看Redis 的淘汰策略设计充满了工程权衡的智慧。 很多人吐槽 Redis 的 LRU 不严格不是标准的双向链表实现。但实际上严格 LRU 要给每个 key 维护链表指针内存开销大还要处理插入删除高并发下锁的开销也不小。Redis 选择的采样 LRU每次随机选 5 个 key淘汰其中最久未访问的。虽然不是理论最优但足够接近真实效果而实现成本、性能开销都低了一个数量级。 这就是典型的工程思路不追求理论上的完美追求性价比最高的方案。够用、好维护、性能够比「最正确」重要得多。核心考点总结缓存本质用高速小容量设备做低速大容量设备的缓冲核心逻辑是二八定律用空间换时间。缓存模式标准 Cache Aside 旁路模式读未命中则查库写回写操作先更库再删缓存。更新策略定期生成可控但实时性差实时生成灵活但依赖淘汰机制。淘汰策略四类算法FIFO、LRU、LFU、Random两个范围allkeys 全量、volatile 仅带过期生产首选 allkeys-lruLFU 适合频次差异大的场景noeviction 不适合缓存。四大经典问题预热启动时空缓存压数据库提前导入热点数据穿透不存在的 key 反复打库空值缓存或布隆过滤器解决雪崩大量 key 同时失效高可用架构 过期时间打散击穿热点 key 失效永不过期或分布式锁限流。结语 我是草莓熊 Lotso若这篇技术干货帮你打通了学习中的卡点 【关注】跟我一起深耕技术领域从基础到进阶见证每一次成长 ❤️ 【点赞】让优质内容被更多人看见让知识传递更有力量 ⭐ 【收藏】把核心知识点、实战技巧存好需要时直接查、随时用 【评论】分享你的经验或疑问比如曾踩过的技术坑一起交流避坑 ️ 【投票】用你的选择助力社区内容方向告诉大家哪个技术点最该重点拆解 技术之路难免有困惑但同行的人会让前进更有方向愿我们都能在自己专注的领域里一步步靠近心中的技术目标结语缓存从来不是一个set一个get那么简单它是一套完整的体系选什么更新策略、用什么淘汰算法、怎么规避常见风险每一步都有讲究。本质上我们是用少量的内存空间、可接受的缓存不一致概率换取整个系统十倍甚至百倍的性能提升。理解了这些设计的本质才能根据业务场景选对方案遇到问题也能快速定位根因从容排障。✨把这些内容吃透超牛的放松下吧✨ʕ˘ᴥ˘ʔづきらど
返回列表