Redis思维导图我前后画过三版第一版是把命令参考从头抄到尾画完自己都不想看第二眼第二版按数据类型重排看着整齐但线上出问题的时候一个节点都用不上第三版才勉强能拿出来给人看因为它终于从“命令清单”变成了“决策索引”——遇到内存涨了、延迟抖了、主从断了能顺着一条分支走到答案。这份东西本质上不是知识图谱而是一张给未来的自己用的导航图Redis 的知识点太碎碎到靠脑子记只能记住常用的那二三十条命令剩下的全部沉在文档深处。这张图解决的就是“知道在哪、知道怎么选、知道坑在哪”这三件事。不管你是刚学 Redis、还在纠结 ziplist 和 listpack 区别的新人还是已经能独立维护一套缓存集群、但总在细节上翻车的老手下面这套主干划分和绘制方法都可以直接抄去改成自己的版本。1. 先想清楚这张图给谁看再动手画1.1 从“背命令”到“建索引”的认知转变绝大多数人第一次画 Redis 思维导图中心节点写“Redis”然后往外拉五个分支String、List、Hash、Set、ZSet每个分支下面挂一堆命令再补一个“持久化”和“集群”。这个结构不能算错但它有个致命问题它是按“文档目录”组织的不是按“问题”组织的。文档目录适合查阅不适合回忆而思维导图的价值恰恰在于回忆和推演——你合上电脑脑子里还能剩下的那几条线才是真正被结构化的知识。我后来换了个判断标准如果某个节点在我排障时永远不会被想起来那它就不该出现在图上或者至少不该出现在主干上。比如GETRANGE、SETRANGE这种命令我一年用不到一次把它们和SETNX、INCR放在同一层级等于稀释了重点。反过来“内存为什么没降”“主从为什么全量同步”“集群为什么返回 MOVED”这类问题每次出事都要重新查一遍它们才该占据主干位置。所以这张图的定位应该是一张决策索引主干不是数据类型而是“你在什么场景下会打开这张图”。我自己的五个触发场景是——设计阶段选结构、容量规划算内存、上线前配持久化、故障时查高可用、以及日常最频繁的缓存异常处理。五个场景对应五条主干每条主干下面才是具体知识点。这个顺序排下来图的宽度大概五六层深度控制在四层以内一屏能看全。1.2 我这版图的五条主干和取舍逻辑具体拆一下这五条主干你照着改就行。第一条是数据结构与底层编码。注意我把“编码”提到了和“类型”同级的位置因为真正影响性能的是编码不是类型。同样是 Hash元素少的时候是一块连续内存元素多了就变成哈希表加指针跳转两者的内存占用和访问延迟差一个量级。图上必须能一眼看到“什么条件下会切换编码”。第二条是内存管理与过期淘汰。这条主干是全网教程最敷衍的部分通常就一句“配置 maxmemory-policy”。但线上最常见的告警就是内存打满这条线不画细出事只能干瞪眼。第三条是持久化与高可用。RDB、AOF、主从、哨兵、集群五个东西经常被混在一起讲其实它们解决的是完全不同的问题前两个解决“数据别丢”后三个解决“服务别停”。图上必须把这两类分开否则很容易出现“配了哨兵就以为数据安全了”的认知错位。第四条是缓存三大问题与业务侧应对。穿透、击穿、雪崩加上一致性、大 key、热 key这条主干其实一半是 Redis 知识一半是业务设计知识。我坚持把它放在图里因为它是我打开这张图频率最高的原因。第五条是执行模型与命令边界。单线程、事务、Lua、Pipeline、慢查询这几个东西的共同点是“不懂就会写出偶发故障”。比如在 Lua 脚本里写了个范围过大的循环整个实例卡住几秒这种事光看文档看不出来。提示主干数量别超过七个。超过七个图就从“索引”退化成“目录”你会开始依赖搜索而不是记忆那还不如直接开文档。2. 主干一数据结构与底层编码怎么切才不白画2.1 五类基础对象与内部编码的对应关系这部分的画法建议是“两列对照”左列写对外暴露的类型右列写内部可能的编码中间用条件箭头连起来。 Redis 对外只有五种基础类型但内部的编码实现有十来种而且随着版本演进而变化——这一点必须标注在图上不然你三年后回看会怀疑自己记错了。我把对应关系整理成一张表直接铺到图的第二层对外类型可能的内部编码触发切换的关键条件Stringint、embstr、raw值能否转成整数、长度是否超过 44 字节Listlistpack旧版为 ziplist、quicklist单节点元素数量与元素大小Hashlistpack旧版为 ziplist、hashtable字段数超过 128 或任一值超过 64 字节Setintset、listpack、hashtable是否全为整数、元素数量阈值ZSetlistpack旧版为 ziplist、skiplist成员数超过 128 或任一成员超过 64 字节图上的写法我建议用颜色区分连续内存的编码标一种颜色指针结构的编码标另一种。这样你一眼就能看出“我现在这个 key 是省内存但怕变长还是费内存但稳定”。这个视觉提示比文字说明有用得多尤其在做容量评估的时候扫一眼就知道哪些 key 有膨胀风险。2.2 44 字节和 128 个元素阈值背后到底是什么逻辑图上光写“44 字节”“128 个”是不够的必须把“为什么是这个数”写成备注挂在节点下面否则你永远记不住也永远不敢改配置。这两个数字背后是两套完全不同的逻辑。先说44 字节。String 用 embstr 编码时redisObject 头占 16 字节sdshdr8 头占 3 字节末尾还有一个\0占 1 字节。内存分配器按 size class 分配64 字节是最小的一个常用档位于是64 - 16 - 3 - 1 44。超过 44 字节一次分配装不下就得改用 raw 编码对象头和字符数组分成两次分配。所以这个 44 不是随便定的是分配器档位倒推出来的。你在图上标注“44 64 字节档位 − 对象头 − SDS 头 − 结束符”比记一个孤零零的数字牢靠得多。再说128 个元素 / 64 字节。这是hash-max-listpack-entries、hash-max-listpack-value、zset-max-listpack-entries、zset-max-listpack-value这组配置的默认值。设计意图是小集合用连续内存省掉每个元素的指针开销同时因为数据量小查找时线性扫描也不慢一旦超过阈值线性扫描的成本开始压过指针开销就切换到哈希表或跳表。这里有个实操细节值得单独画一个节点这个阈值是按“单个 key”算的不是全局。我见过有人把hash-max-listpack-entries从 128 调到 512以为能省内存结果一批大 Hash 全变成 listpack 后单次HGET的耗时从微秒级涨到几十微秒延迟毛刺就是这么来的。所以图上应该配一句警告调大阈值省内存代价是单次操作变慢高 QPS 场景慎调。2.3 容易被漏掉的四类扩展结构五种基础类型之外还有四类结构经常在图上缺席但它们的实用价值很高尤其是在“用 Redis 解决一个具体问题”的时候。我把它们单独挂在第一主干下面作为“特殊用途”分支Bitmap本质是 String用位操作。适合签到、活跃用户标记这类场景一个用户一年 365 天只占 46 字节。图上要标注它的坑——SETBIT的偏移量很大时会直接分配整块内存比如偏移量设成 100 万立刻就占 125KB。HyperLogLog基数统计标准误差约 0.81%固定占 12KB。适合 UV 统计这类“要数量不要明细”的需求。图上必须写明它不能取出元素也不能做交集以外的复杂运算。GEO底层是 ZSet存的是 geohash 编码后的分值。适合附近的人、范围查询但要注意它的精度和边界问题跨经纬度分界线的查询容易漏数据。Stream消息队列形态支持消费组和消息确认。适合轻量级异步任务但要标注清楚它没有强制的持久化保证也没有消息堆积的自动处理机制。这四类结构在图上的价值不在于“知道有”而在于“知道什么时候不该用”。比如有人用 HyperLogLog 做需要精确去重的业务或者用 Stream 做需要可靠投递的核心链路这些都是选型事故而图上的一句注释就能提前拦住。3. 主干二内存管理与过期淘汰别只写一句“配策略”3.1 maxmemory 与八种淘汰策略的决策路径这条主干的第一层应该是maxmemory这个参数本身而不是策略。原因很简单不设 maxmemory后面的策略全是摆设。很多线上事故的根因就是这个参数留空进程一路吃内存直到被系统干掉。图上要画一条明确的线设了上限 → 才有淘汰没设上限 → 只能靠系统 OOM。第二层才是八种策略。这里不要平铺要画成决策路径策略淘汰范围挑选依据典型适用场景noeviction不淘汰写入直接报错数据不可丢、有外部持久层兜底allkeys-lru所有 key最近最少使用通用缓存最常用allkeys-lfu所有 key访问频率最低有明显热点、长尾明显的场景allkeys-random所有 key随机访问分布均匀几乎不用volatile-lru设了过期时间的 key最近最少使用缓存与持久数据混布volatile-lfu设了过期时间的 key访问频率最低同上且热点集中volatile-random设了过期时间的 key随机极少用volatile-ttl设了过期时间的 key剩余存活时间最短希望优先淘汰快过期的图上的关键注释是带 volatile 前缀的策略在没有设置过期时间的 key 上完全不生效。这一条我踩过一个实例配了volatile-lru结果业务方写进来的 key 有一半没设 TTL内存打满后淘汰不了直接开始报错。所以图上要加一条连线volatile-* → 依赖 TTL 覆盖率 → 未设 TTL 的 key 不会被淘汰。另外 LRU 和 LFU 的差别也值得一个节点。LRU 实现上采样的是近似算法不是精确链表采样数由maxmemory-samples控制默认 5调大更精确但更耗 CPU。LFU 则是给每个对象维护一个 8 位的计数器还有衰减机制适合“昨天爆过、今天凉了”的流量。这两个细节图上一句话带过就够但必须有。3.2 惰性删除加定期删除为什么删了 key 内存还不降这是最高频的疑问之一必须单独画一个分支。Redis 的过期删除是两套机制配合惰性删除是指 key 被访问时才检查是否过期过期就删。好处是不浪费 CPU坏处是没人访问的过期 key 会一直躺着。定期删除是后台每秒跑若干次由hz控制默认 10每次随机抽取一批设了 TTL 的 key删掉其中过期的如果这批里过期比例超过 25%就立刻再抽一轮直到比例降下来或达到时间上限。这个机制解释了两个现象。第一内存占用和 key 数量不是同步下降的因为定期删除是抽样采样不到的就留着。第二主从架构下从库不会自己删过期 key它等主库发来删除命令才删所以从库内存可能比主库高这是正常的不是 bug。图上还可以挂一个实用节点手动清理用SCAN配合UNLINK不要用KEYS。KEYS是全量遍历且阻塞几十万 key 的实例上执行一次前端能感觉到卡顿。UNLINK是异步释放内存比DEL温和得多大 key 场景下差别明显。注意UNLINK只是把释放内存的动作挪到后台线程key 本身在命令返回时就已经不可见了。如果你需要立刻确认内存下降可能要等一小会儿。3.3 内存碎片与容量估算图上的“算一遍”节点容量估算这件事文档里很少有人写清楚但它是我打开这张图最实际的原因之一。图上我放了一个简易算法节点思路是这样一个 key 的实际占用 ≈ key 字符串长度 value 长度 对象头 16 字节 SDS 头 哈希表 entry 开销 分配器对齐产生的浪费。粗算时每个 key 的固定元数据开销按 50 到 100 字节估然后整体再乘一个 1.2 到 1.5 的系数覆盖碎片和哈希表扩容的瞬时翻倍。举个例子1000 万个 key平均 value 1KB。原始数据约 10GB。key 名平均 30 字节1000 万个就是 300MB。元数据按 80 字节算是 800MB。加起来 11.1GB再乘 1.3实际大概要准备 14GB 以上。这个数字在采购或扩容时非常关键凭感觉估通常会差 30% 以上。内存碎片这块图上挂两个指标就够mem_fragmentation_ratio正常在 1 到 1.5 之间超过 1.5 说明碎片偏多低于 1 说明发生了 swap这个更危险必须立刻查。处理方式上开启主动碎片整理activedefrag会增加 CPU 开销我一般是在低峰期开一段时间再关掉长期开着要评估 CPU 余量。另一个办法是主从切换把从库提升为主库新主库的内存是紧凑的这个操作顺便还完成了扩容。4. 主干三持久化与高可用两类问题必须分开画4.1 RDB 和 AOF 的参数取舍别背结论要背条件这条主干我画成了一个“二选一再加混合”的结构。RDB 是快照AOF 是追加日志混合持久化是两者结合这三种模式的取舍要看你能容忍丢多少数据、能接受多大的写放大。RDB 的关键机制是fork加写时复制。fork出来的子进程负责把内存数据写盘主进程继续处理请求。这里有两个必须画在图上的点一是fork本身会阻塞主线程阻塞时间和实例内存量正相关内存越大越明显所以大实例要做容量规划二是写时复制意味着写入越频繁额外占用的内存越多极端情况下可能翻倍这也是为什么有的实例在做快照时内存突然冲高。AOF 的关键在appendfsync这个参数三档的差别值得单独一个表取值行为最多丢多少数据性能影响always每条命令都落盘基本不丢写入延迟明显升高everysec每秒落盘一次约 1 秒折中最常用no交给操作系统决定可能丢较多最快但风险最高我自己的选择是默认everysec只有明确知道“丢一秒数据不可接受”且能承担延迟代价的场景才用always。这个判断要写进图上因为很多人是照着某篇教程抄的配置抄完不知道为什么。还有一个节点容易被忽略AOF 重写。日志会越写越大需要定期重写压缩。自动重写由auto-aof-rewrite-percentage相对上次重写后的大小增长比例默认 100和auto-aof-rewrite-min-size默认 64MB两个参数控制。重写同样是fork子进程完成的所以它和 RDB 快照一样有阻塞风险。图上画一条线AOF 重写 → fork → 内存翻倍风险 → 避开写入高峰。4.2 主从复制的三个阶段以及最常见的三个误解主从复制我画成了三段流程因为这个过程的分段方式直接决定你排查问题的方向。第一阶段是建立连接和握手从库连上主库发PSYNC。第二阶段是全量同步主库fork出子进程生成 RDB 发给从库同时把这期间的新写入攒在缓冲区里等 RDB 发完再补发。第三阶段是命令传播之后主库把每条写命令实时发给从库。图上必须标注三个误解误解一从库是只读的所以不会有一致性问题。从库默认只读但只读不等于实时。主从之间有网络延迟从库的数据可能落后主库几十毫秒甚至更多。刚写完立刻读从库读不到这是典型的读写分离踩坑现场。误解二从库能分担主库的写压力。不能。从库只接受读请求所有写还是走主库。想横向扩展写能力只能上集群分片。误解三主从复制能替代持久化。不能。主从是内存到内存的复制如果主库和从库同时宕机比如同一个机房断电数据一样没了。持久化解决的是“落盘”主从解决的是“多一份在线副本”两件事。这部分我还挂了一个小节点复制积压缓冲区。从库短暂断连后能否做部分重同步取决于断开期间的写命令是否还在这个环形缓冲区里。缓冲区大小由repl-backlog-size控制默认 1MB写入量大的实例应该调大否则断连几秒就得全量同步全量同步又要fork形成连锁反应。4.3 哨兵和集群看着都叫高可用其实是两码事这两者在图上必须是两个并列分支不能合并。它们的区别我用一句话概括哨兵解决“谁挂了怎么办”集群解决“一台装不下怎么办”。哨兵是一组独立进程监控主从节点发现主库不可达后经过投票判定客观下线然后选一个从库提升为主库通知其他节点切换。它的核心参数是quorum表示判定客观下线需要多少个哨兵同意。这里有个容易搞错的地方quorum 只用于判定下线真正执行故障转移还需要选举出一个领头哨兵这个选举是另一套多数派逻辑。所以哨兵至少要部署三个且为奇数两个哨兵的配置在脑裂场景下是不安全的。集群则是数据分片把整个键空间切成 16384 个槽每个主节点负责一部分。为什么是 16384 而不是更大一个常见解释是心跳包要携带槽位图16384 个槽用位图表示是 2KB节点间每秒都要交换包太大会占带宽。这个数字不用死记但知道它有工程原因比当成魔法数好。集群图上的关键节点是至少三主三从才有基本的容错能力主节点之间通过集群总线通信端口是客户端端口加 10000防火墙只开客户端端口会导致集群建不起来cluster-require-full-coverage决定部分槽不可用时整个集群是否拒绝服务默认开启也就是有一片挂了整体不可用很多人在生产上会关掉它换取部分可用性但关掉之后要自己处理数据不完整的业务影响。4.4 分片、MOVED 和 ASK客户端到底在做什么集群这部分如果只画架构不画请求路径等于没画。我在图上画了一条请求流客户端连上任意节点 → 计算 key 属于哪个槽 → 槽不在当前节点 → 返回 MOVED 重定向 → 客户端更新本地槽位缓存 → 重新请求正确节点。MOVED 和 ASK 的区别值得单独一句MOVED 表示槽的归属已经永久变了客户端应该更新缓存ASK 表示这只是迁移过程中的临时重定向客户端不该更新缓存。搞混这两个会出现客户端把槽位缓存刷错、请求反复横跳的情况。这也是为什么生产上推荐用支持集群协议的客户端让它自己维护槽位映射而不是自己写重定向逻辑。槽位计算用的是 CRC16 取模 16384。这里挂一个实用技巧需要把相关 key 放到同一个槽时用 hash tag也就是在 key 里用花括号包住参与计算的部分比如order:{12345}:detail和order:{12345}:items会落在同一个槽多 key 操作才能成立。但滥用 hash tag 会导致数据倾斜全压到一个节点上图上要标一句“慎用仅在必须做多 key 原子操作时用”。5. 主干四缓存三大问题与业务侧应对5.1 穿透、击穿、雪崩三者的问题根源完全不同这三个词经常被混用其实它们的成因、现象、解法都不一样。图上我做成了一张对照表因为这是最需要“一眼分清”的部分问题根源现象常用解法穿透查询的数据在缓存和库里都不存在大量请求打到数据库且都是无效查询缓存空值并设短 TTL、布隆过滤器前置拦截、参数合法性校验击穿某个热点 key 过期瞬间瞬时大量请求同时涌向数据库查同一个 key互斥锁重建、逻辑过期不设物理 TTL、热点 key 预热雪崩大批 key 同时过期或缓存层整体不可用数据库瞬间承压可能连锁拖垮整个链路过期时间加随机偏移、多级缓存、熔断降级、集群高可用穿透的解法里缓存空值最简单但要小心如果攻击者每次用不同的随机 key 查询空值缓存救不了你只能靠布隆过滤器在入口拦掉明显不存在的 key。布隆过滤器的特点是“说不存在就一定不存在说存在可能误判”所以它只适合做前置拦截不能当作准确判断。这个语义必须写清楚我见过有人拿它当精确去重用的。击穿的互斥锁方案落地时有个细节拿到锁的线程去查库并回填没拿到锁的线程短暂等待后重试读缓存而不是直接返回失败。否则高并发下会有大量请求失败。等待时间要设上限避免线程堆积。雪崩的随机偏移具体做法是 TTL 加一个随机量比如基础 30 分钟上下浮动 5 分钟。这个改动一行代码效果立竿见影。另外要提醒的是缓存层整体不可用的场景这时候任何 key 级别的策略都没用只能靠熔断和降级图上要画一条独立分支提醒自己“别把希望全寄托在过期时间打散上”。5.2 双写一致性先删缓存还是先更库这个问题的标准答案通常写成“先更新数据库再删除缓存”但图上光写这一句会误导人因为它只在特定条件下成立。我在图上画的是条件判断先更库再删缓存问题在于删缓存失败或删除前的极短窗口内有读请求把旧值又写回缓存。概率不高但存在。先删缓存再更库问题窗口更大删完缓存、还没更库的这段时间读请求会把旧值读出来写回缓存然后库里更新了缓存里是脏的而且这个脏数据会一直留到 TTL 到期。所以落地上通常是先更库、再删缓存然后延迟一小段时间再删一次用第二次删除兜住窗口期。延迟多久这个要结合主从复制延迟和业务读请求的耗时来估通常几百毫秒到一秒。图上的注释是延迟时间不是拍脑袋要按主从延迟的 P99 来定宁可长一点。更彻底的方案是订阅数据库的变更日志异步删缓存把一致性收敛到一个组件里业务代码不用管。代价是引入额外依赖链路变长。这个取舍要看业务对一致性的敏感度——如果是商品库存这种宁可慢一点也要准如果是首页推荐位这种容忍几十秒的旧数据完全没问题。图上做个简单的分级比背一句“先更库再删缓存”有用得多。5.3 大 key 和热 key怎么发现怎么治这两个是同一条分支下的两个子节点因为它们的发现手段相似但处理思路相反大 key 是拆热 key 是散。大 key指的是 value 过大比如一个 String 几百 KB或者元素过多比如一个 Hash 几十万字段。危害是操作耗时长、网络传输量大、删除时阻塞。发现手段用--bigkeys扫描或者对已知的大集合用MEMORY USAGE单独看。处理思路是拆分大 Hash 按字段前缀拆成多个小 Hash大 List 按业务维度切分超大 String 压缩或改用其他存储。删除时要配合UNLINK异步释放。热 key指的是单个 key 的 QPS 极高把单个节点的 CPU 打满。危害是负载不均集群里其他节点闲着这一个节点成瓶颈。发现手段有--hotkeys需要开启 LFU 策略才有效或者客户端侧埋点统计。处理思路是分散本地缓存挡一层、把 key 复制成多个副本加随机后缀、读写分离。提示--hotkeys依赖 LFU 的访问计数如果实例用的是 LRU 策略这个命令扫出来的结果没有参考价值。这一点在图上要单独标出来。6. 主干五执行模型不懂这条线就会写出偶发故障6.1 单线程到底单在哪以及阻塞点在哪“Redis 是单线程的”这句话是简化说法准确表述是命令的执行是单线程的。网络读写在新版本里可以由多个 IO 线程分担但命令从解析到执行到写回仍然在一个线程里串行完成。这个模型的好处是没有锁竞争、没有上下文切换坏处是任何一个慢命令都会阻塞所有其他请求。图上要列清楚阻塞点时间复杂度是 O(N) 且 N 可能很大的命令KEYS、FLUSHALL的同步版本、大集合的SMEMBERS、HGETALL、大 key 的删除、fork操作、以及 Lua 脚本里的长循环。这些的共同特征是“执行时间不可控”而单线程模型对不可控最敏感。我还会在图上标注一个量化感受单线程执行时一个耗时 100 毫秒的命令意味着这段时间内所有其他请求都在排队。如果 QPS 是 1 万那就是 1000 个请求被拖慢。这个换算能让人直观理解为什么“偶尔慢一下”是很严重的事。6.2 事务、Lua、Pipeline三者的边界不要搞混这三个东西经常被放在一起提但它们解决的完全是不同的问题图上必须是三个并列节点每个节点写清楚“能做什么、不能做什么”。事务MULTI/EXEC提供的是命令打包执行中间不会插入其他客户端的命令。但它没有回滚——如果中间某条命令执行出错比如类型不匹配其他命令照样执行只在返回结果里标记错误。这一点和关系型数据库的事务完全不同必须写进图上否则会写出“以为失败了其实部分生效”的代码。Lua 脚本提供的是原子性加逻辑能力。脚本执行期间不会插入其他命令可以在里面做条件判断、循环、多个 key 的读写。代价是脚本必须写得克制循环次数要有上限不要在里面做全量遍历执行时间过长的脚本会导致其他请求全部阻塞超时后其他客户端会收到“脚本繁忙”的报错。脚本还要注意不要依赖随机函数或系统时间因为主从复制和脚本缓存会导致不一致。Pipeline提供的是批量发送减少网络往返次数。它不保证原子性中间可能插入其他客户端的命令某条失败也不影响其他条。它的价值纯粹是网络层面的优化一次往返发 100 条命令比发 100 次往返快得多。图上的注释是Pipeline 里的命令数量要控制太多会占满服务端的输出缓冲区反而引发问题。6.3 慢查询日志和延迟监控出事时的第一手证据这条分支我画得比较细因为它是排障时的入口。慢查询日志由两个参数控制slowlog-log-slower-than是阈值单位微秒默认 10000也就是 10 毫秒slowlog-max-len是保留条数。查出来的记录包含命令、耗时、时间戳但不包含客户端信息旧版本如此新版本有所增强所以定位到具体业务要靠时间点去比对日志。延迟监控用LATENCY系列命令可以记录不同事件的耗时分布包括命令执行、fork、过期删除等。这个比慢查询更有针对性因为有些卡顿不是单条命令慢而是一批小命令挤在一起。图上还要挂一个基础但重要的节点INFO命令的输出要会看。used_memory和used_memory_rss的差异反映碎片connected_clients反映连接数instantaneous_ops_per_sec反映当前负载keyspace_hits和keyspace_misses算命中率。命中率低于 80% 就该看看是不是缓存设计有问题了。7. 把图真正画出来工具、流程和维护7.1 工具选型先看你要不要版本管理工具这块我的建议很简单先确定这张图是给自己看还是给别人看再决定用什么。自己看优先选大纲优先型先用缩进的纯文本把结构列出来再导入图形工具渲染。好处是结构清晰、改起来快、能做版本管理文本文件天然适合。我现在的习惯是先写一份 Markdown 大纲确认主干和层级没问题再导成图。反过来先画图再想结构会陷入“调整布局半小时内容没写几行”的泥潭。给别人看或者要分享选在线协作型一个链接发出去对方能直接展开折叠节点。但要注意在线工具的免费版通常限制节点数量图大了会被截断。还有一种代码化绘图型用文本描述生成图形好处是可以进代码仓库跟着版本走改一行就能重新生成。适合团队里多人维护同一份知识库的场景。缺点是样式调整不灵活排版经常需要手工微调。具体哪款产品不重要图上真正重要的是结构本身。我见过用最朴素的纯文本缩进写得极好的 Redis 笔记也见过用很漂亮的工具画出来但层级混乱的图。7.2 三步绘制法先骨架、再血肉、最后挂经验我的绘制流程固定分三步每次画新主题都照这个走。第一步定主干不超过七个。主干不是知识点分类而是“我会在什么场景下打开它”。前面说的五条主干就是这么来的。这一步只写一级节点不写任何细节写完自己看一眼这七条能不能覆盖我 90% 的使用场景不能就调整。第二步每个主干铺两层最多三层。第一层是概念第二层是关键参数或条件第三层只放“数字和阈值”。再往下就太细了细到那个程度不如直接查文档。比如“淘汰策略”是第一层“八种策略的适用场景”是第二层“默认值和采样数”是第三层到此为止。第三步挂经验节点。这一步是这张图和网上任何一份笔记的区别所在。每个主干下面挑两三个自己踩过的坑用一句话写清楚“现象 原因 应对”挂在对应节点旁边。比如“内存没降 → 定期删除是抽样 → 用 SCAN 加 UNLINK 手动清”。这些节点不需要严谨的文档表述越口语越好因为它们是给未来的自己看的提示。提示经验节点建议单独用一种颜色。这样你打开图扫一眼就知道哪些是官方知识、哪些是自己的血泪复习的时候重点完全不同。7.3 用图排障的实际走法图不是画完就挂墙上的它得有使用场景。我自己的用法是“顺着分支往下走”遇到延迟抖动先看执行模型分支——有没有慢命令、有没有大 key 删除、有没有fork再看内存分支——是不是内存打满触发了频繁淘汰最后看持久化分支——是不是正在做 AOF 重写。这三条线走完八成的原因能定位到。遇到请求失败先看缓存问题分支——是不是穿透把库打挂了再看集群分支——是不是槽迁移导致的短暂不可用最后看连接数——是不是客户端连接池耗尽。遇到数据不一致直接跳到一致性分支按“先更库再删缓存 延迟双删”的顺序核对业务代码再看主从延迟。这个走法的好处是它把“我该查什么”变成了一个有顺序的动作而不是打开文档漫无目的地翻。这也是我坚持把图做成“问题索引”而不是“知识目录”的原因。8. 常见问题和速查8.1 画图过程中最容易犯的六个错误第一个错误是把命令当知识点。SET、GET、INCR这种不需要画画了只会稀释重点。真正该画的是“什么情况下用什么结构”以及“这个结构的代价是什么”。第二个错误是层级超过四层。超过四层图就没法一屏看完一屏看不完就等于没有。信息该压缩就压缩该合并就合并。第三个错误是只写结论不写条件。比如“用 LFU 更好”这话在没热点的场景下是错的。所有结论都要挂上适用条件。第四个错误是不留版本标记。Redis 从 3.x 到 7.x 变化不少ziplist 换 listpack、多线程 IO、AOF 多文件结构这些如果不在图上标注版本三年后你会分不清哪些是自己记错了。第五个错误是把图和文档混在一起。图负责结构和索引细节该查文档就查文档不要试图把图做成百科。第六个错误是画完不维护。建议每季度过一遍把解决过的新问题补进去把过时的结论删掉。图的价值和它的新鲜度成正比。8.2 线上高频问题速查表现象优先怀疑快速验证处理方向内存持续上涨不降大 key、未设 TTL、碎片--bigkeys、INFO memory拆大 key、补 TTL、低峰期整理碎片延迟偶发毛刺慢命令、fork、大 key 删除慢查询日志、LATENCY换用异步删除、避开高峰做快照主从数据不一致复制延迟、读写分离INFO replication看偏移量关键读走主库、缩短复制链路集群请求报重定向错误槽迁移、客户端缓存过期客户端日志看 MOVED/ASK用支持集群协议的客户端、刷新槽位缓存缓存命中率低key 设计不合理、TTL 过短INFO stats看命中数调整 key 粒度、延长热点 key TTL连接数打满连接池配置、连接泄漏INFO clients调小空闲连接、检查异常分支是否释放写入报 OOM 错误maxmemory到顶且策略为 noevictionINFO memory与配置改淘汰策略或扩容这张表我放在图的最外层作为“入口节点”。它的作用不是替代深入排查而是让你在慌的时候有个起点。我自己的体会是这张 Redis 思维导图真正产生价值是在我把它从“整理笔记”改成“记录决策”之后。早期那两版画得很全命令一条不落但从来不会打开现在这版内容少了三分之一反而成了常用工具因为每一条都能对应到一个具体动作。如果你也要画建议别追求全先把最近三个月踩过的坑挂上去图自然就长成你自己的形状了。另外一个小技巧每次排查完一个问题花两分钟把结论补进对应的分支坚持半年这张图会比任何一份教程都贴合你的实际工作。
阅读完成 · 觉得有帮助?