Redis 的知识点可以放进同一个框架中理解:
- 应用维度回答 Redis 用来解决什么问题。
- 系统维度回答 Redis 内部如何处理请求、管理内存和保存数据。
- 高性能、高可靠、高可扩展三条主线把底层机制串联起来。
本文以 Redis Open Source 6.0 及之后版本的通用机制为主;涉及 Redis 7.0 起的多文件 AOF 等版本差异时单独说明。

一、两大维度
1. 应用维度
应用维度关注 Redis 在业务系统中的角色,主要包括三类应用。
缓存应用
缓存把读取频繁、生成成本高的数据放入更快的访问路径。设计缓存时需要明确:
- 缓存对象:适合缓存读取频繁、计算或查询成本高,并且允许短暂陈旧的数据。
- 过期时间:使用 TTL 控制生命周期,并增加随机抖动,避免大量 Key 同时失效。
- 更新策略:常见做法是先更新数据库,再删除缓存;删除失败时需要重试或消息补偿。
- 淘汰策略 :数据内存超过
maxmemory后,根据访问模式选择近似 LRU、近似 LFU、随机淘汰或只淘汰带过期时间的 Key;noeviction不淘汰 Key,而是拒绝会继续增加内存的写命令。 - 后端保护:缓存失效后,数据库侧仍需要限流、熔断、请求合并和降级措施。
缓存应用中的核心问题包括缓存一致性、缓存污染、缓存雪崩、缓存击穿和缓存穿透。
数据结构应用
Redis 不只是字符串缓存。不同数据结构对应不同的计算模型。
| 数据结构 | 主要能力 | 典型场景 | 注意点 |
|---|---|---|---|
| String | 计数、位操作、对象序列化 | 计数器、令牌、简单缓存 | 避免存放过大的序列化对象 |
| Hash | 字段级读写 | 对象属性、购物车 | 关注字段数量和底层编码转换 |
| List | 有序元素、阻塞读写 | 简单队列、任务列表 | 可靠消费能力有限 |
| Stream | 消息追加、消费组、确认机制 | 消息流、事件处理 | 需要管理消费者和待确认消息 |
| Set | 去重和集合运算 | 标签、共同关注、抽奖 | 大集合运算可能阻塞主线程 |
| Sorted Set | 按分值排序 | 排行榜、延迟队列 | 控制成员规模和范围查询结果量 |
| Bitmap(基于 String) | 位级记录与统计 | 签到、状态标记 | 适合连续、紧凑的整数 ID |
| HyperLogLog | 近似基数统计 | UV、去重计数 | 标准误差约为 0.81%,不能返回具体成员 |
| GEO | 地理位置索引 | 附近的人、门店距离 | 底层基于 Sorted Set |
集群应用
当数据容量、访问吞吐或可用性要求超出单实例能力时,需要组合复制、哨兵和分片机制。
- 主从复制提供数据副本和读扩展,但复制是异步的,从库不是强一致副本。
- 哨兵机制负责监控、下线判断、领导者选举和主从故障切换。
- Redis Cluster把数据分配到多个节点,以水平扩展容量和吞吐。
2. 系统维度
系统维度沿一次请求的处理链路拆解 Redis。
网络层
Redis 使用非阻塞套接字和 I/O 多路复用处理大量连接。Linux 上通常使用 epoll,内核只返回已经就绪的文件描述符,事件循环不需要逐个轮询连接。
Redis 6 开始支持 I/O 线程并行处理部分网络读写,但命令执行仍以串行方式为主。网络收发可以并行,不代表耗时命令可以并行执行。
处理层
Redis 通过事件循环接收请求并执行命令。串行执行带来两个特点:
- 常规命令在核心执行路径中不会与其他命令交错,因此其数据修改具有原子执行语义;这不等于支持事务回滚,也不代表结果已经持久化或复制完成。
- 不需要为共享数据结构引入大量线程锁和上下文切换。
相应的代价是主执行路径对慢操作非常敏感。一次耗时几十毫秒的命令会让后续请求排队。
线上需要重点关注:
- 命令的时间复杂度。
- 命令实际处理的元素数量。
- 返回结果大小。
- Lua 脚本执行时间。
- BigKey 的读取、删除和迁移成本。
遍历线上数据时应优先使用 SCAN、HSCAN、SSCAN 和 ZSCAN。COUNT 只是每轮工作量和返回量的提示,不是严格上限;完整遍历期间若数据发生变化,还可能返回重复元素,因此调用方需要按业务要求去重。
内存层
Redis 对象包含类型、编码、引用计数以及 LRU/LFU 相关字段等元数据。同一种逻辑类型可以根据数据规模、元素大小和版本配置使用不同的底层编码,以平衡内存占用和操作效率。
数据规模超过阈值后,底层编码可能发生转换,进而改变内存占用和性能特征。
内存管理包括三个重要机制:
- 过期删除:惰性删除在访问 Key 时检查过期状态;定期删除周期性抽样清理过期 Key。
- 内存淘汰 :数据内存超过
maxmemory且命令试图继续增加内存时,Redis 根据maxmemory-policy淘汰 Key,或者在noeviction下返回错误。复制和 AOF 等部分缓冲区不计入淘汰判断,因此配置时要为它们和系统开销预留内存。 - 碎片管理 :频繁分配和释放可能导致常驻内存高于实际数据内存。
mem_fragmentation_ratio同时受到分配器碎片和进程其他开销影响,需要结合allocator_frag_ratio、allocator_rss_ratio、used_memory与 RSS 判断,不能只凭一个比值下结论。
存储层
Redis 的主要持久化方式是 RDB 和 AOF。
RDB保存某一时刻的数据快照:
- 文件紧凑。
- 加载和恢复速度快。
- 两次快照之间的数据可能丢失。
- 生成快照通常依赖
fork和写时复制。 - 内存规模大、写入频繁时,需要关注 fork 延迟和复制页开销。
AOF通过可重放的操作记录恢复数据。传统 AOF 的增量部分记录会改变数据集的命令;Redis 7.0 起采用多文件 AOF,由一个基础文件、一个或多个增量文件以及清单文件组成,基础文件可以使用 RDB 或 AOF 格式:
- 数据丢失窗口由刷盘策略决定。
appendfsync always可靠性更高,但写入开销大。appendfsync everysec通常在性能和持久性之间取得平衡,异常宕机时通常可能丢失约 1 秒的数据。- AOF 重写根据当前内存数据生成能够重建现状的紧凑基础文件,并不是读取旧 AOF 后简单合并历史命令。
- 重写期间会增加 CPU、内存和磁盘压力。
启用 aof-use-rdb-preamble 后,AOF 基础部分可以使用 RDB 格式,后续变化保存在增量 AOF 中,从而兼顾恢复速度和较小的数据丢失窗口。
二、三大主线
1. 高性能主线
Redis 的低延迟来自多种设计共同作用:
- 数据主要存放在内存中。
- 数据结构和底层编码针对常见操作做了优化。
- 网络层使用非阻塞 I/O 和多路复用。
- 核心命令执行路径避免了大量线程同步。
- 单条命令通常短小且执行时间可预测。
性能风险
慢命令
大范围聚合、全量遍历、复杂 Lua 脚本和超大结果集都会占用主执行路径。
BigKey
BigKey 可能表现为单个 Value 很大,也可能表现为集合成员非常多。它会同时放大:
- 网络传输成本。
- 序列化和反序列化成本。
- 删除和过期成本。
- 主从复制流量。
- RDB 和 AOF 成本。
- 集群槽迁移时间。
持久化抖动
fork、写时复制、AOF 刷盘和 AOF 重写可能引起延迟尖峰。
系统环境
内存换页、透明大页、CPU 抢占、磁盘拥塞和网络丢包都会影响 Redis 延迟。
常用诊断入口
SLOWLOG:查看慢命令。LATENCY DOCTOR:分析常见延迟来源。INFO commandstats:查看各命令调用次数和耗时。INFO memory:检查内存、碎片和淘汰情况。CLIENT LIST:检查连接和客户端缓冲区。redis-cli --bigkeys:通过SCAN遍历并按类型比较逻辑长度,适合发现成员多或字符串长的 Key,但它不等同于精确的内存占用排名;需要估算内存时可结合MEMORY USAGE或redis-cli --memkeys。
诊断时要区分服务端执行时间、请求排队时间和网络往返时间。客户端观察到的延迟不等于命令本身的执行时间。
2. 高可靠主线
可靠性不是绝不丢数据,而是明确故障模型、可接受的数据丢失窗口和服务恢复时间。
数据持久性
- 仅使用 RDB:恢复快,但数据丢失窗口通常较大。
- 仅使用 AOF:数据更完整,但文件体积和恢复成本更高。
- 使用 RDB 与 AOF,并让 AOF 基础文件采用 RDB 格式:兼顾备份能力、恢复速度与较小的数据丢失窗口,但最终保证仍取决于刷盘策略和故障类型。
主从复制
初次同步通常经历全量复制:
- 主库生成 RDB 快照;启用无盘复制时,子进程可以直接把 RDB 数据流发送给从库,而不先落本地磁盘。
- 从库接收并加载 RDB 数据集;加载大数据集时,从库仍可能出现阻塞窗口。
- 主库把快照期间累积的写命令发送给从库。
- 主从进入持续的增量复制状态。
连接短暂中断时,可以根据复制 ID、复制偏移量和复制积压缓冲区进行部分重同步,避免再次传输完整快照。
复制是异步的,因此存在两个边界:
- 从库可能落后于主库,读取从库会得到陈旧数据。
- 主库故障时,尚未复制到从库的数据可能丢失。
WAIT 可以等待指定数量的从库确认已接收当前连接此前的写入,从而降低故障时丢失写入的概率;确认接收不等于已持久化。它不会把 Redis 变成强一致系统,故障切换时仍不能保证已确认写入绝不丢失。
哨兵与故障切换
哨兵执行以下任务:
- 监控主库、从库和其他哨兵。
- 判断实例是否主观下线。
- 通过多个哨兵形成客观下线判断。
- 由多数哨兵授权并选举一个领导者执行故障转移;配置的
quorum用于客观下线判断,不等同于执行故障转移所需的多数票。 - 选择合适的从库升级为新主库。
- 让其他从库改为复制新主库。
故障转移期间仍可能发生:
- 短暂不可写。
- 客户端继续连接旧主库。
- 网络分区时旧主库可能在一段时间内仍可写,形成短暂双主;可用
min-replicas-to-write和min-replicas-max-lag缩小风险窗口,但不能获得严格强一致。 - 已确认写入仍可能丢失,实际范围取决于复制延迟、网络分区持续时间、持久化配置和客户端连接位置,不能笼统视为固定的"少量"。
客户端需要支持通过哨兵发现新主库、重新连接和有限重试。对超时后结果未知的写请求,盲目重试可能造成重复执行,业务操作还需要具备幂等性或请求去重能力。
3. 高可扩展主线
Redis Cluster 使用数据分片突破单机容量和吞吐上限。
哈希槽
Redis Cluster 使用 16384 个哈希槽。Key 对应的槽位为:
text
slot = CRC16(effective_key) mod 16384
一般情况下 effective_key 就是完整 Key;使用有效 Hash Tag 时,它是第一对合法花括号中的非空内容。槽位被分配给不同主节点,集群扩缩容的本质是重新分配槽位,并迁移槽位中的 Key。
路由与重定向
- MOVED:当前节点不是该槽位的负责节点,客户端应转向返回的节点,并刷新或修正本地槽位映射。
- ASK :槽位正在迁移,客户端只把当前请求临时转向目标节点,并在发送实际命令前先发送
ASKING;客户端不应据此永久更新槽位映射。 - Hash Tag :当 Key 包含符合规则的
{...}且括号内非空时,只对其中的内容计算槽位,可以让相关 Key 落在同一槽中。
扩展边界
- 跨槽多 Key 命令受到限制,数据建模时需要提前设计 Key 的共置关系。
- 扩容不能自动消除热 Key,单个热点仍可能压垮一个分片。
- BigKey 会拖慢槽迁移并放大网络和阻塞风险。
- 集群节点使用 Gossip 传播状态,节点过多会增加集群总线流量和状态收敛成本。
热点数据可以通过本地缓存、Key 拆分、请求合并、限流或业务维度分片进行治理。
三、从问题反推底层机制

| 问题 | 首先检查 | 关键机制 | 常见治理方向 |
|---|---|---|---|
| 阻塞、延迟抖动 | 慢日志、延迟监控、CPU、fork、磁盘 | 事件循环、慢命令、持久化 | 拆分命令、异步删除、错峰持久化、治理 BigKey |
| 数据丢失 | AOF 刷盘策略、复制延迟、故障时间线 | RDB、AOF、异步复制 | 缩小刷盘窗口、监控复制偏移、用 WAIT 或最小副本写入降低风险,但不把它们视为强一致保证 |
| 主从不一致 | 复制延迟、网络、从库负载 | 异步复制、部分重同步 | 关键读走主库、容忍陈旧读、避免从库过载 |
| 热 Key、秒杀热点 | Key 访问频率、节点流量和 CPU | 分片、串行命令执行 | 本地缓存、Key 拆分、请求合并、限流 |
| 缓存污染 | 命中率、Key 生命周期、访问频率 | TTL、LRU、LFU | 使用 LFU、缩短低价值数据 TTL、分离缓存池 |
| 缓存雪崩 | 失效时间分布、后端负载 | 过期删除、缓存重建 | TTL 抖动、多级缓存、预热、限流和熔断 |
| 缓存击穿 | 单个热点 Key 是否失效 | 热点访问、缓存重建 | 互斥重建、逻辑过期、较长 TTL 配合主动刷新;避免无边界地让热点数据永不过期 |
| 缓存穿透 | 不存在 Key 的请求比例 | 缓存命中模型 | 缓存空值、参数校验、在应用侧或通过 RedisBloom 使用布隆过滤器 |
| 内存碎片 | used_memory、RSS、分配器与 RSS 碎片指标 |
内存分配器、对象生命周期 | 评估并启用主动碎片整理、优化对象规模;必要时再采用受控的主从切换或滚动重启 |
诊断顺序
- 确认现象和监控指标。
- 判断问题位于客户端、网络、命令执行、内存、持久化、复制还是分片环节。
- 检查数据结构、Key 大小、元素数量和访问频率。
- 检查 RDB、AOF、复制、哨兵或集群配置。
- 回到业务访问模式,确认一致性、容量和延迟目标是否合理。
四、知识闭环
评估任何 Redis 方案时,可以依次回答以下问题:
- 应用角色:Redis 是缓存、状态存储、消息通道,还是分布式数据结构?
- 数据特征:Key 数量、Value 大小、读写比例、热点分布和生命周期是什么?
- 性能路径:命令复杂度、网络往返、序列化和持久化是否可能造成阻塞?
- 可靠性边界:允许丢多少数据、允许中断多久、是否接受陈旧读?
- 扩展方式:使用单机、主从、哨兵还是 Redis Cluster?
- 集群约束:跨槽操作、BigKey 和热 Key 如何处理?
- 可观测性:是否持续监控延迟、命中率、内存、复制、持久化和节点状态?
Redis 知识体系的重点不是记住更多命令,而是能够根据业务需求判断机制取舍,并从线上现象快速定位到请求链路中的具体环节。