ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Redis核心知识点梳理:数据结构、持久化与高可用实战

Redis核心知识点梳理:数据结构、持久化与高可用实战

作为后端开发,Redis几乎是绕不开的中间件,也是每次技术面试里出现频率最高的名字之一。但真要系统梳理redis知识点,很多人反而说不完整。我见过不少简历上写着“熟悉Redis”的开发者,面对面沟通后发现,对方对它的理解基本停留在get、set、设个过期时间这个层级。不是他们不认真,而是Redis这块内容太分散:数据结构、持久化、高可用、缓存一致性、性能排查,每一块都能单独拎出来讲很久。

这篇文章我就按照自己这些年实际使用Redis的顺序,把知识点拆成几个容易理解的部分:先讲清楚五种数据结构在真实场景里的选型,再聊持久化的权衡,然后说内存回收、高可用方案,接着是缓存三类故障的应对,最后分享一些日常排查问题的命令和使用习惯。适合刚把Redis理论基础过了一遍、准备落实到项目里的同学,也适合工作一两年后想回头把知识体系补齐的朋友。

1. 数据结构不是背八股,你要知道每种类型真正卡脖子的地方

很多人背数据结构能背得很流利:String是字符串、Hash是哈希、List是列表、Set是集合、ZSet是有序集合。可真到项目里选型的时候,却常常判断失误。我认为,背结构定义没有意义,关键是理解每种类型的行为边界和性能特点,知道它们在什么场景下会“卡脖子”。

1.1 String:最简单的结构,最容易被用错

String不只是存个字符串那么简单,它能做的事非常多。它支持 incr、decr 这类原子加减操作,所以最常见的用法是计数器,比如统计访问量、限流计数、库存扣减。为什么推荐用 incr 而不是先 get 再 set?因为 get 和 set 是两步操作,中间会被其他请求插进来,高并发下一定会出问题。而 incr 是Redis内部原子执行,可以放心压。

另一个高频用法是分布式锁。早期用 setnx 加锁,还要自己配 expire 防止死锁,很多老项目里能看到这种写法。现在正经做法是SET key value EX ttl NX,一条命令同时搞定“不存在才设置”和“过期时间”,原子性才有保证。

String需要留意的坑是大字符串。一个value几十MB的话,无论是网络传输还是内存拷贝都会对Redis造成明显压力,甚至可能堵塞主进程。所以在项目里我习惯给String设个头:超过10KB的内容就考虑单独文件存储或者拆分成多个键,不要让单键体积太夸张。

1.2 Hash:结构化的选择逻辑

Hash适合存“一个对象的多个字段”,比如用户信息、商品信息。你可以只改其中一个字段,比如更新用户头像,用hset user:123 avatar xxx,不需要像String那样整个反序列化再覆盖回去,读写效率都更高。

关于Hash和String怎么选,我自己的判断标准很简单:如果这个对象经常需要整体读写,而且字段基本不变,那用String存JSON反而方便;如果对象会频繁改动某个字段,或者字段可能不断增加,就选Hash。举个例子,购物车数据用Hash很合适,每个sku是一个field,数量是value,用户增删商品就是hincrby cart:456 sku_789 1,天然支持加减。

Hash也有自己的坑。如果field数量特别多,或者某个field对应的value特别大,这个key就会成为大Key,影响集群的扩容和数据迁移。线下扫大Key的时候,Hash经常是重灾区。

1.3 List:不止队列

List底层是链表,头部和尾部操作是 O(1),所以它最经典的场景就是消息队列。用lpush从左边塞消息,用brpop从右边阻塞读取,客户端没有数据时接管阻塞,比轮询省资源得多。很多轻量项目不需要引入重量级消息队列,用List就完全够用。

List还不是只能做队列。lrange可以用来做简单的分页数据,但由于它查找中间元素是 O(N),数据量一大性能会明显下降,所以只适合做短列表的分页。如果列表一直在增长,还要记得用ltrim限制长度,否则内存会被撑爆。我见过一个项目把日志写进List,忘记trim,半年后一个key里存了几百万条记录,那叫一个惨烈。

1.4 Set 与 ZSet:去重和排序的两把刀

Set是无序、去重的集合,应用场景非常典型:一个用户关注了哪些人、哪些文章被哪些用户点赞、标签系统的去重统计。它还支持集合运算,比如计算两个Set的交集,可以用来做“互相关注”这类推荐功能。

ZSet在Set基础上加了分数,底层用跳跃表实现排序,插入和删除是 O(logN),所以它能稳定支撑排行榜、延时队列这些场景。排行榜是ZSet最出名的应用:key存榜单名,member存用户ID,score存分数,更新成绩直接zadd leaderboard 99 userA,取前十名用zrevrange leaderboard 0 9 withscores。

实现排行榜时要注意一个细节:如果两人的分数一样,Redis按字典序排序,而不是按时间先后。需要“同分时先到先得”的话,可以用“分数=业务分数 + 一个随排名递减的小数”这种设计,也可以把时间戳作为分数的低位移来拼。这个技巧我实际用过,效果很稳。

1.5 我的一个取舍教训

有一年我做了一个带会话列表功能的小项目,数据特点是“用户最近联系过的会话”要按最后活跃时间倒序展示。我当时直接选ZSet,member是会话ID,score是最后活跃时间。逻辑上完全通顺,但跑起来后发现两个问题:一是用户会话很多时,每次用户点开一个会话都要zadd更新score,写操作非常频繁;二是列表展示还需要同时取会话的详情,ZSet里只存了ID,还要回查详情表。

这个需求换成“Hash存会话详情 + 定时排序”会更合适:会话详情实时更新,排序按需计算而不是每次写入都触发生成索引。吃一堑长一智,我现在选型的思路是:先看访问模式是“读多写少”还是“写多读少”,再看是否需要范围查询,最后还要考虑数据生命周期的维护成本。数据结构不是越高级越好,而是越匹配场景越好。

2. 持久化是典型的“平时不管,出事就慌”:RDB与AOF的权衡

Redis是内存数据库,数据在内存里,这句话很多人知道,但没意识到它的另一面:进程一退出,内存里的数据就没了。所以持久化不是一个可以拖到上线后再说的事,而是一开始就要决策的架构选项。

2.1 RDB到底什么时候触发

RDB就是每隔一段时间把内存里的全量数据保存成一份二进制快照。触发方式最直观的是配置文件里的save规则,例如默认配置里有一条save 900 1,意思是900秒内至少有1次写操作就触发一次快照。下面还有save 300 10和save 60 10000,数字越小代表触发越频繁。

RDB执行时主进程通过 fork 出一个子进程来干活,子进程负责把数据写入临时文件,写完之后替换旧文件。因为 fork 之后用的是操作系统的写时复制技术,子进程写的是当时的“内存快照视角”,主进程继续接受请求,所以正常情况不会阻塞业务。但是如果内存特别大,fork 瞬间耗时就会上升,这是要在容量规划时提前考虑的点。

RDB的优点是恢复快、文件紧凑,适合做备份、灾备和冷启动。它的缺点是存在明显的丢失窗口:如果你一个小时才产生一次RDB快照,那么这一个小时内的数据在宕机时全丢。Redis默认的save配置对大部分场景来说太宽松了,所以纯靠RDB扛数据风险,我是很不放心的。

2.2 AOF的三种策略

AOF是把每一条写命令追加到文件末尾,本质上是一份操作日志。通过appendfsync配置可以控制刷盘频率,有三个值:always表示每条命令都强制刷盘,最安全但性能慢;everysec表示每秒刷一次,最多丢一秒数据,这是性能和安全的折中;no表示由操作系统决定什么时候刷,能丢多少数据完全看运气。

AOF文件会越来越大,所以Redis提供了重写机制。重写不是把原文件变小,而是基于当前内存状态生成一条条最小命令集合:比如同一个key被set了一百次,重写后就只剩最后一次。Redis同时提供了手动触发命令,也支持自动触发条件,默认是文件大小超过上次重写后的一倍、且达到64MB时才考虑。

有时候面试会问“AOF重写会不会阻塞服务”。实际上重写也走 fork 子进程,主进程一边处理请求一边把新命令写入重写缓冲,保证重写后的文件不丢请求。但如果写入压力太大,缓冲积压,主进程也会进入等待状态,这也是线上要注意的现象。

2.3 组合使用怎么设计

生产环境我建议RDB和AOF都开,而不是二选一。AOF负责把丢失窗口压到最小,RDB负责提供快速恢复能力和定期备份。Redis重启时,如果AOF开关是开的,会优先用AOF恢复,因为AOF的数据更新。但AOF恢复速度比RDB慢,所以如果数据量巨大,可以评估业务对恢复时间的容忍度。

需要特别强调的是,Redis 4.0以后有一个混合持久化选项,开启后AOF重写生成的文件前半段是RDB格式的二进制快照,后半段是重写期间的增量命令,恢复时既有RDB的快速加载,又能保证数据较完整。很多发行版默认把这个打开了,如果条件允许,我建议保持开启。

对比项RDBAOF
数据完整性较差,有丢失窗口较好,everysec最多丢一秒
文件大小紧凑较大,但重写后可控制
恢复速度快稍慢
对性能影响fork时短暂影响刷盘频率影响写入性能
典型用途定期备份、冷备主数据可靠性

2.4 一次数据丢失定位的复盘

以前接过一个数据报表项目,线上Redis里存的是当天清洗后的原始指标,第二天早上要跑汇总。我接手之前一直没开AOF,只靠默认RDB策略。某个晚上机器意外重启,重启后发现当天白天的数据几乎全部丢失,因为距离上次满足RDB触发条件已经过了很久。排查的时候打开配置文件,看到appendonly no,那一刻真的很无奈。

那次事故之后,我立了几个规矩:第一,业务数据进入Redis之前,先想清楚“如果这一秒宕机,丢多少数据能接受”;第二,不能只说开AOF,还要确认用的是哪种策略组合,以及RDB定时备份有没有落到独立存储;第三,持久化配置变更要纳入代码评审和上线检查,不能只在某台机器上手工改一下,下次重新部署又丢了配置。

3. 内存这只隐形的老虎:过期删除、淘汰策略与大Key

Redis的数据存在内存里,内存是有限而且不便宜的。如果只关心读写命令,不关注内存是怎么被一点一点吃掉的,迟早有一天会碰到Redis变慢、拒绝写入,甚至OOM的问题。

3.1 过期删除为什么需要两种策略

给key设置EXPIRE后,Redis是怎么把过期数据弄掉的?如果每个key都起一个定时器,成千上万的定时器会占用大量资源,不现实。所以Redis用的是“惰性删除+定期删除”的组合。

惰性删除的意思是:key过期了不立即删,而是在你下次访问它的时候才检查是否过期,过期就删除。定期删除是:Redis默认每100毫秒抽查一批设置了过期时间的key,把其中过期的删掉。这两种方案配合起来,既不浪费CPU做无谓的定时器,又能避免过期key长期霸占内存。

这里有个常见问题:如果一个key已经过期,但一直没人访问,惰性删除永远不会触发它;定期删除每次抽查又碰巧抽不到它,这个key会持续占用内存。这也是为什么不能只依赖过期机制,还要保留淘汰策略作为兜底。

3.2 淘汰策略八种怎么选

当内存达到maxmemory上限时,Redis必须决定是拒绝新写入,还是干掉一部分旧数据。默认策略是noeviction,直接返回错误。这种情况我在业务高峰期见过,写入一旦报错,上游根本不知道发生了什么,只能看到一堆异常。

如果不想拒绝写入,就要选一个合适的淘汰策略。常见的有allkeys-lru:所有key里挑选最近最少使用的数据淘汰;volatile-lru:只从设置了过期时间的key里挑;allkeys-lfu:按访问频率而不是最近访问时间淘汰。选择逻辑其实不复杂:如果Redis主要做缓存,所有数据都能随时从后端重建,那直接allkeys-lru或allkeys-lfu;如果Redis里有一部分数据是绝对不能随便丢的,就不要用 allkeys 系列,改成 volatile 系列,并保证重要key不设过期时间或者设得很长。

还有一点,LFU和LRU在实践中差异不小。我做过一个活动页面,流量集中在那几天,LRU容易把一些平时访问少但刚被活动拉起来的key误判为冷数据,LFU能更好地反映长期访问热度。但LFU实现的淘汰逻辑更占用一些CPU,需要根据实际场景取舍。

3.3 大Key是怎么拖垮Redis的

大Key没有一个绝对标准,但行业内一般把单个String超过10KB、集合类型元素超过5000个、或者单个元素特别大,都视为需要关注的大Key。大Key的可怕之处在于:在集群模式下,key按哈希槽分布在某个节点上,一个大Key会让数据倾斜;执行删除或序列化操作时会占用较长CPU时间。

举个例子,一个业务高峰期,某个存全量用户标签的Set有几百万个member,有一次清空它执行del,结果单节点Redis瞬间卡住,下游请求大量超时。线下扫出来的结果很惊人:这一个key占了节点内存的三分之一。

扫大Key不要靠猜,直接用redis-cli --bigkeys就能把实例里最大的Key类型扫出来。线上执行时要小心,内存大的实例建议在低峰期跑。发现大Key后,可以按业务维度拆分:比如把用户标签按用户ID分桶,拆成多个小key;或者把集合迁移到独立存储,不占用Redis核心内存。

3.4 热点Key的内存与流量双重压力

热点Key指的是短时间内被大量请求命中的key,比如双11的爆款商品、微博热搜。它不只是CPU压力,更是流量压力:所有请求都打到一个key上,单节点线程扛不住。

应对的办法一是多级缓存:Redis前面再加一层本地内存缓存,让绝大多数热点流量在应用层就返回;二是把热点key复制成多份,比如在key后面加随机后缀,让请求分散到多个key上,最后再对账;三是设置逻辑过期,不把压力全压在Redis上。热点key的治理属于典型的“治慢病”,每分钟都在和流量赛跑,越早发现越从容。

4. 从主从复制到Cluster:高可用的每一层解决什么

后端同学经常把“主从”“哨兵”“集群”挂在嘴边,但真心建议先理清一个主线:这三层解决的是不同的问题。主从解决数据冗余和读写分离,哨兵解决故障自动切换,Cluster解决水平扩展和分片存储。它们不是替代关系,而是层层叠加的演进关系。

4.1 主从复制:读写分离的代价

主从复制指的是一个主节点负责处理写请求,一个或多个从节点复制主节点数据,可以承担读请求。早期版本用SYNC做全量同步,后来优化成PSYNC。全量同步发生在从节点第一次连上来时:主节点生成RDB快照发给从节点,从节点加载恢复;如果从节点断线后重新连接,且断线期间的增量数据还在主节点的复制积压缓冲区里,就可以做部分同步,不需要重新全量复制。

这里有一个常见的误解:主从同步是异步的,所以从节点的数据可能比主节点旧,尤其在主节点写压力大、网络延迟高的场景。如果业务读取直接打到从节点,可能读到刚写进去的数据,也可能读到老数据,这就是读写分离的代价。要是业务要求“写后立即读”,那这个读请求尽量还是走主节点。

4.2 哨兵:不是高可用本身,而是故障转移的调度者

单靠主从复制,主节点挂了,写服务就停了,因为从节点不会自动升级。哨兵(Sentinel)就是来解决这个问题的。哨兵会持续探测主节点状态,一个哨兵觉得主节点不回复了,会把它标记为“主观下线”,但不敢确定,因为可能是哨兵自己的网络抖动。只有当多个哨兵都认为主节点下线时,才升级为“客观下线”,然后从可用的从节点里选举一个新的主节点。

哨兵内部还使用了类似Raft的共识机制,避免多个哨兵同时发起切换导致混乱。这个设计很妙:它不追求所有哨兵意见完全一致,只要过半数的哨兵能互相通信并共同决策,就能完成切换,从而容忍部分哨兵节点失效。

我重点提醒一点:哨兵只负责自动切换,切换期间会有一小段不可用窗口。如果业务对可用性要求极高,应用层需要搭配故障转移的感知机制,例如连接池自动重连,不能让客户端拿旧连接一直写到死节点上。

4.3 Cluster:数据分片的思路

主从架构下,一台Redis能存的数据总量有上限。Cluster把数据分散到多个节点,每个节点负责一部分哈希槽。整个Cluster固定有16384个槽位,key通过CRC16算法计算出一个哈希值,再对16384取模,就能定位到具体某个槽,而槽分布在不同节点上。

为什么是16384而不是更大的数字?官方给出过一个解释:节点之间需要交换槽位信息,16384个槽的称重消息体控制在合理大小;而65536个槽会导致心跳包体偏大。即使未来节点数变得非常多,16384也留出了充足的余量。

使用Cluster对客户端代码是有侵入性的:跨节点的多key操作(例如一次mget多个key)不被支持,因为每个key可能落在不同节点。这就要求在设计key时考虑好“同类key要落在同一个槽”,目前常见的做法是把共同业务标识拼进key中,或者用哈希标签{}强制相关key路由到同一槽。这个细节,很多第一次接触集群的同事都会踩坑。

4.4 脑裂问题为什么会存在

脑裂是分布式系统里一个经典的难题。简单描述就是:主节点和哨兵之间的网络被切断了,哨兵认为主节点死了,于是把某个从节点晋升为新主;但此时旧主节点并没有真正挂掉,它还在继续接收写入,只是它无法把数据同步给新主。

等网络恢复后,旧主发现自己已经不是主节点,会降级为从节点,但它脑裂期间接收的写入数据已经丢了。这些数据本来客户端是以为写成功了的。减轻脑裂危害的办法是设置min-replicas-to-write和min-replicas-max-lag,意思是当从节点数量低于阈值或者数据同步落后太多时,拒绝写入。这样即使发生脑裂,旧主节点也写不了数据,后续由新主接管业务,损失的数据面会小很多。

5. 缓存穿透、击穿、雪崩:三种故障要分开治

缓存场景里最常出现的三类故障,名字听起来非常像,但成因和应对策略差别很大,我建议使用的时候把它们分开记,分开治。

5.1 穿透:查询不存在的数据

缓存穿透指的是大量请求查询一个“缓存里没有,数据库里也不存在”的key,比如用随机不存在的用户ID发起攻击。每次请求都绕过缓存直接打数据库,数据库压力瞬间飙升,Redis反而成了摆设。

应对穿透有两个主流办法。第一个是缓存空值:把查询结果为空的情况也写进Redis,设置一个较短的过期时间比如三到五分钟,后续相同空查询直接命中缓存。第二个是布隆过滤器:请求到达Redis之前,先判断这个key是否“可能存在”,如果过滤器说一定不存在,就直接拒绝,不访问后端。

布隆过滤器的原理非常值得理解:它用多个哈希函数把值映射到位数组上,判断存在时有概率误判,但判断不存在时一定准确。所以布隆过滤器擅长“拦截必定不存在的情况”,但它无法删除某个元素,因为一个位可能被多个元素共享。如果业务需要频繁删除,那就要考虑带可删除能力的变体结构。

5.2 击穿:热点key过期的瞬间

击穿和穿透不一样。击穿是某个热点key突然过期,导致大量并发请求同时打到数据库。它不是“不存在”的问题,而是“瞬间失效”的问题。

处理方案一是互斥锁:当发现缓存中没有该key时,不是立刻去查数据库,而是先获取一把分布式锁,只有拿到锁的请求才能访问数据库并回填缓存,其他请求等待一会儿再重新读缓存。方案二是逻辑过期:缓存里存value时附带一个业务过期时间,即使物理上key没有过期,发现逻辑过期后立即返回旧数据,同时后台异步去刷新缓存。

我个人更偏爱逻辑过期,因为互斥锁会让大量请求在锁等待中排队,对毛刺很敏感;而逻辑过期让用户几乎无感知,先返回旧值再更新新值。但是逻辑错误也常见:如果后台异步刷新失败,用户会一直看到旧数据,所以要搭配重试和告警。

5.3 雪崩:大量key同时失效

雪崩是面积更大的一种故障:大量key在同一时间过期,或者整个Redis实例宕机,流量集体涌向数据库,数据库扛不住就一片一片地挂。

针对key同时过期,最简单有效的手段是给过期时间加一个随机扰动。比如基础过期时间是600秒,实际设置的时候再随机加上分钟级别的波动。很多代码里直接set key value ex 600,看起来没问题,但如果有批量导入任务一次性写入几千个缓存,这些key会在同一分钟集体过期,很容易引发雪崩。

针对Redis实例宕机的场景,上面讲的主从、哨兵、集群部署就是兜底方案,同时业务侧需要设计快速降级:当Redis不可用时,宁可走数据库也不要把所有流量直冲进来。

5.4 布隆过滤器的实际坑

布隆过滤器确实能挡穿透,但它有两个需要提前准备的点:一是容量和误判率的关系。一个过滤器设计容纳十万个元素,结果你塞了一百万个,那误判率会指数级上升,拦截效果崩塌。所以上线前要做容量规划,预留未来增长空间。二是布隆过滤器通常在业务启动时初始化,如果历史数据量很大,初始构建会占用不少时间。我遇到过项目上线时将千万级userID导入布隆过滤器,跑了好几分钟才完成,期间业务只能用空值缓存做降级。

还有一点容易忽略:布隆过滤器里的数据更新是滞后的。如果用户ID可以从逻辑上删除,但过滤器并不知道,这个ID可能会永远“碰巧”存在,后续查询会持续打到数据库。需要结合业务规则给布隆过滤器设定重建周期,不要让旧数据长期残留。

6. 我在日常排查Redis问题时最常用的命令和思路

到了运维和排障环节,很多人会慌乱,因为问题表现往往只是“Redis变慢了”或者“请求报错了”,但原因可以有太多层。我梳理一下我最常走的排查链路,希望能给出一套可以参照的顺序。

6.1 slowlog 慢查询

Redis变慢,第一步我习惯看慢查询日志。配置项slowlog-log-slower-than单位是微秒,默认值10000微秒也就是10毫秒,超过这个时长的命令会被记录。要特别注意,10毫秒在普通业务里已经很慢了,如果默认没改过,可以先把它调成5毫秒或更低,更早暴露问题。

用slowlog get能查看最近记录的命令,里面能看到执行耗时、命令内容、客户端IP。慢查询常见原因:执行了keys *这种全量匹配命令、用了hgetall取超大Hash、或者zrange在大ZSet上取了很大范围。解决思路是命令改写:keys换成scan,大集合操作分批处理,必要的话在代码里禁用危险命令。

6.2 连接数打满

另一种常见故障是连接数被打满。现象是业务侧报“无法获取连接”,Redis侧执行info clients能看到connected_clients接近配置上限。

排查时我先看应用连接池配置,很多问题的根源是连接池最大连接数设置过高,而Redis实例的maxclients不够大。还能在info clients里观察是否存在大量长期不释放的客户端连接,代码里连接忘了关、线程池泄漏都会造成连接一直被占着。有一个隐藏点:如果Redis配置了很短的timeout参数,空闲连接会被服务端强制断开,但客户端不知道,用的时候才发现连接已经失效,这种错位会引发大量重建连接的震荡。

6.3 memory 分析:别只看 used_memory

信息量很大,但不能只看used_memory。还要关注碎片率,就是mem_fragmentation_ratio。碎片率长期大于1.5,说明内存碎片化严重,考虑重启或者调整内存分配器策略;碎片率小于1则可能是使用了swap,性能会骤降。

要定位具体是哪些key在吃内存,最方便的还是redis-cli --bigkeys,它会遍历整个实例,统计每种类型里最大的key。遍历期间对线上会有一点性能影响,建议低峰期跑。更精细的分析可以用memory usage key看单个key的精确内存占用。

6.4 常用监控指标

平时我至少会盯这五个指标:命中率、内存使用率、连接数、慢查询数量、主从同步延迟。命中率直接体现缓存效率,低于80%就要检查是不是有大量key过期或者缓存设计不合理。内存使用率超过maxmemory的70%就要准备扩容或清理,因为超过上限后淘汰策略会开始工作。

主从同步延迟可以用info replication看从节点相对主节点落后的字节数。如果延迟持续增大,说明从节点消费不及,需要检查从节点是否负载过重、网络带宽是否瓶颈。一个不被重视的点是:从节点上的短连接和慢查询同样会拖累同步。

6.5 代码侧的使用习惯

最后聊几个我极力推荐的编码习惯。第一,能用pipeline就尽量用pipeline,批量写多个key时显著降低RTT;第二,能用批量命令就不逐条循环,比如mset优于多个set;第三,非特殊场景不要用keys通配,数据量大时它会让整个实例停顿;第四,给key命名带上业务前缀和冒号分隔,比如order:20250101:user:123,既能定位业务又能配合scan按前缀进退。

命名这件事,很多人觉得不重要,但到了排障的时候,一个清晰的key命名体系能帮你快速锁定问题域。我见过线上Redis里出现大量没有规律、没有业务含义的key,根本不知道该删还是该留,最后只能把整批数据迁移到新的key体系,代价巨大。

结合我的经验,Redis的学习可以层层展开:先从数据结构理解每个类型能解决的场景,再把持久化作为数据安全的底子打牢,随后在内存管理和高可用层面做架构权衡,最后用缓存故障的案例把理论和实践连起来。这几块不是割裂的,而是像齿轮一样咬合在一起。当你拿到一个新的业务需求,如果能脱口说出“这个用ZSet是为什么、内存会不会失控、宕机会丢多少、热点打过来怎么办”,那才是真正把redis知识点内化成自己的能力了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进