前言
我已经学习完了Redis的基础篇,笔记见https://blog.lecspace.com/index.php/archives/80/。但是,这只是学会使用Redis的入场券,想要在被面试官拷打redis相关知识点时游刃有余,必须要更加深入研究它。
我会跟着《Redis45讲》进行学习,这篇文章是我学习这东西的笔记。
1.怎样学Redis更好?
此节不重要,浓缩总结一下:如何学Redis?
🧭 两大维度:
- 系统维度:理解 Redis 的底层原理与架构;
- 应用维度:从实际业务场景和案例出发,掌握使用技巧。
🧩 三大主线(简称“三高”):
| 主线 | 涉及模块 | 目标 |
|---|---|---|
| 高性能 | 线程模型、数据结构、持久化、网络框架 | 提升吞吐与响应速度 |
| 高可靠 | 主从复制、哨兵机制 | 保证数据一致与高可用 |
| 高可扩展 | 数据分片、负载均衡 | 支撑大规模集群部署 |
作者建议:
- 先按“三高主线”构建知识框架;
- 再结合“应用场景驱动 + 典型案例驱动”深入学习。
01 | 基本架构:一个键值数据库包含什么?
1)主旨
- 先用最小可用的键值库 SimpleKV 搭“骨架”,形成系统观,再带着框架去理解 Redis 的复杂特性与优化路径。
2)SimpleKV 的架构与搭建顺序
- 数据模型:Key 为
String;Value 支持基础类型(String、整数等)。
└→ 现实里的 KV(如 Redis)会把 Value 做成多类型(String/Hash/List/Set…),以适配更多场景。【重点】 - 操作接口:最小集合为 PUT/GET/DELETE/SCAN,可扩展 EXISTS。
└→ 操作能力决定适用场景:KV 易做点查/简单集合操作,但不擅长聚合计算(如平均值)。【重点】 数据放哪里:
- 内存:快,但断电丢;
- 外存:稳,但慢。
SimpleKV 选内存以贴近 Redis 的“高性能缓存”定位。【重点】
访问模式(I/O 模型):
- 库调用(如 RocksDB) vs 网络服务(如 Redis/Memcached);
- 线程/进程模型取舍:单线程易被阻塞,多线程有锁竞争。I/O 设计直接影响吞吐与延迟。【重点】
- 索引模块:按 key 找 value 的位置;内存 KV 常用 哈希表(O(1) 近似)。
└→ Redis 的多 Value 类型内部还有自己的数据结构(如列表/集合),二级结构的选择影响性能。【重点】 操作模块:
- GET/SCAN:读出 value;
- PUT:分配空间并写入;
- DELETE:删除并释放空间。
存储/持久化模块:
- 内存分配器选择会影响碎片与效率(SimpleKV 用
malloc/free,Redis 可选多种分配器); 持久化策略:
- 逐条落盘:稳但慢;
- 周期落盘:快但偶有丢失。
Redis 对持久化做了更多机制与优化(见下)。
- 内存分配器选择会影响碎片与效率(SimpleKV 用
3)从 SimpleKV → Redis 的关键“进化”
- 访问方式:以 网络服务为主(RESP 协议),通用性更强。
- 数据模型:丰富的 Value 类型 → 对应更丰富的命令(LPUSH/LPOP、SADD/SREM…)。
- 持久化:AOF(日志) + RDB(快照) 两条线,权衡性能 vs 数据安全。【重点】
- 集群/高可用:支持复制、哨兵、分片等,满足 高可靠/高扩展。【重点】

圈重点
- 系统观优先:先搭框架(数据模型→接口→I/O→索引→操作→持久化),再深入点技。
【重点:学习顺序与定位问题的方法论】 - 操作能力决定边界:KV 擅长点查与简单集合操作,不擅长复杂聚合(平均值、join)。
【重点:选型与场景匹配】 - 多类型 Value = 性能与空间的权衡:每种结构背后都有不同的时间/空间复杂度与内存布局。
【重点:命令性能差异的根源在“底层数据结构”】 - I/O 与线程模型是吞吐/延迟的第一性问题:单线程避免锁但怕阻塞;多线程并发高但有竞争。
【重点:理解 Redis 为何“单线程也高性能”及其边界】 - 内存分配与碎片会放大延迟波动与内存占用。
【重点:生产环境经常被忽视的性能坑】 持久化两条线(AOF/RDB):
- AOF:更安全,可控刷盘,可能带来写放大/延迟抖动;
- RDB:整库快照,恢复快但快照时有资源压力。
【重点:按业务容忍度选择或组合】
- 从 SimpleKV 到 Redis 的“加法”:网络协议、丰富数据结构、两种持久化、复制/哨兵/分片。
【重点:Redis 的价值不只在快,更在“完备的工程化能力”】
速用清单
- 说清 KV 的能与不能:点查强,聚合弱。
- 题到 性能:先问 I/O/线程模型、数据结构、内存分配、持久化策略。
- 题到 持久化:AOF vs RDB 的权衡与组合策略(如 AOF everysec + 定期 RDB)。
- 题到 集群/高可用:复制、哨兵、分片的一句话职责与常见坑(复制延迟、重分片、热点键)。
- 题到 命令效率:回到底层结构(Hash/Skiplist/Ziplist/Quicklist/Dict…)解释“为什么”。
SimpleKV 相比 Redis 还缺什么?
- 协议与客户端生态(RESP、Pipeline、批量、连接管理)。
- 过期与淘汰策略(TTL、LRU/LFU、定期/惰性删除)。【重点】
- 复制/哨兵/分片(高可用与水平扩展)。【重点】
- 更丰富的数据结构(Hash/List/Set/ZSet、Stream、Bitmap/HyperLogLog、Geo)。
- 持久化完善(AOF 重写、RDB 触发策略、混合持久化、恢复流程)。【重点】
- 内存治理(分配器选择、碎片率监控、maxmemory 策略)。
- 可观测性(慢日志、命令统计、热点 Key、延迟监控)。
- 安全与多租户(权限/ACL、隔离/限流/防穿透)。
- 脚本与事务(Lua、事务/原子性原语、分布式锁语义)。
02 | 数据结构:快速的Redis有哪些慢操作?
1)Redis 为啥快?
- 内存数据库:操作发生在内存,先天快。
- 数据结构选得好:键值组织 + 值的底层结构共同决定了增删改查的复杂度。【重点】
2)键和值如何组织?
全局哈希表(dict)保存所有键值对:
- 哈希桶数组 → 每个桶存 entry(含
key*和value*指针)。 - 查找复杂度 ≈ O(1)(与数据量弱相关)。【重点】
- 哈希桶数组 → 每个桶存 entry(含

- 冲突处理:链式哈希(同桶元素用链表串起来)。

- 扩容机制:渐进式 rehash(请求期间分批搬迁哈希桶,避免一次性阻塞)。【重点】
3)值(集合类型)的底层数据结构(6 选)
- String:SDS(简单动态字符串)。
List / Hash / Set / ZSet:会在两种结构间切换(按大小/编码等阈值):
- 整数数组(intset)、双向链表(linkedlist)、压缩列表(ziplist)、哈希表(hashtable)、跳表(skiplist)。【重点】

直觉复杂度梯度(查找):
- hashtable:O(1);skiplist:O(logN);
- linkedlist / ziplist / intset:O(N)(顺序访问为主)。

4)集合操作的复杂度——四句口诀
- 单元素操作是基础:底层若是哈希表,多为 O(1)(如 HGET/HSET、SADD/SREM)。【重点】
- 范围操作非常耗时:遍历/范围读取多为 O(N)(如 HGETALL、SMEMBERS、LRANGE、ZRANGE)。【重点】
- 统计操作通常高效:记录了长度/基数的结构,LLEN/SCARD 常为 O(1)。
- 例外情况有几个:List 的 头尾操作(LPUSH/RPUSH/LPOP/RPOP)可 O(1)(有偏移量/指针可直达)。
5)慢从哪来?
- 哈希冲突链过长;
- 一次性 rehash 会阻塞(Redis 用渐进式缓解);【重点】
- 对集合做全量遍历/范围操作导致 O(N);
- 选择了不合适的底层结构(如把 List 当随机读写容器)。
实战“避坑清单”(按影响度排序)
- 避免 O(N) 的范围命令:HGETALL / SMEMBERS / LRANGE / ZRANGE 等,
→ 尽量用 SCAN/HSCAN/SSCAN/ZSCAN 渐进遍历;限制返回条数。【重点】 - 单元素优先:HGET/HSET、SADD/SREM、ZADD/ZREM 等是基础操作路径,延迟稳定。
- 别把 List 当数组:List 适合 队列(头尾),不适合随机访问/大范围读取。
→ 队列/日志:LPUSH/RPOP 等;随机访问考虑 Hash/Sorted Set。 关注哈希表负载与 rehash:
- 大批量写入可能触发扩容;
- 服务繁忙期避免集中触发;
- 合理批量/预热/均衡写入节奏。【重点】
按“规模/类型”选编码:
- 小而简单的集合:ziplist/intset(省内存、CPU 缓存友好);
- 变大后自动“升级”为 hashtable/skiplist(更快)。【重点】
你最该记的“圈重点”
- 全局哈希表 + 渐进式 rehash 是 Redis 查找快且不抖的根基。【重点】
- 集合底层结构两套切换(空间 vs 时间):小集合偏紧凑结构(ziplist/intset),大集合自动升级(hashtable/skiplist)。【重点】
- 范围 = O(N),生产环境要警惕;用 SCAN 系列替代全量遍历。【重点】
- List 的价值在“头尾 O(1)”,主要用于队列,不做随机读。【重点】
- 复杂度=数据结构:先判断底层结构,再推操作成本,少靠死记硬背。【重点】
面试/答辩速背(30 秒)
- Redis 快:内存 + 数据结构。键值由全局哈希表组织,冲突用链式,渐进式 rehash摊薄扩容成本。
- 集合类型底层:hashtable O(1)、skiplist O(logN)、其余多为 O(N)。
- 命令策略:单元素优先,范围慎用 → 用 SCAN;List 只做队列头尾。
- 小集合走 ziplist/intset 省内存,变大自动升级到更高效结构。
“每课一问”参考思路
问:整数数组(intset)和压缩列表(ziplist)查找不是 O(N),为啥还用作底层?
答:因为它们在小集合下有显著工程优势:
- 内存开销小(紧凑、额外指针少);
- CPU 缓存友好(连续内存,遍历快);
- 编码简单、分配/拷贝便宜(小集在 O(N) 的常数项很小);
- 按阈值“自动升级”到 hashtable/skiplist,兼顾小集合省内存与大集合高性能。【重点:小规模走空间效率,大规模走时间效率】
03 | 高性能IO模型:为什么单线程Redis能那么快?
一句话总览(背诵版)
- Redis“单线程”只指:网络 I/O + KV 读写在一个线程;持久化/异步删除/集群同步等有额外线程。
- 用单线程的核心原因:避免多线程对共享数据的并发控制与锁开销。
- 快的本质:内存操作 + 高效数据结构(哈希表、跳表)+ I/O 多路复用(select/epoll 等)+ 非阻塞套接字 + 事件回调。
- 关键阻塞点被规避:
accept()、recv()改为非阻塞,由内核监听 FD,事件就绪再回调处理。
面试常问点 & 标准作答要点
1) Redis 真的是单线程吗?
- 答:对外部服务路径(网络 I/O 与键值读写)是单线程;后台任务(持久化、异步删除、集群数据同步)有额外线程。
- 加分:单线程减少锁竞争、上下文切换、并发 Bug;更易维护和调试。
2) 为什么不做多线程?
- 多线程需要保护共享资源(如 List 的长度计数),必须串行化关键区或加锁 → 锁竞争、上下文切换、复杂性↑,吞吐不一定随线程数线性增长,甚至下降。
3) 单线程为何还能很快?
- 内存级操作 + 高效数据结构(哈希表/跳表)
- I/O 多路复用:内核同时监听多个监听/已连接套接字(FD),请求就绪触发事件 → 事件队列 → 单线程回调处理。
- 非阻塞 Socket:避免阻塞在
accept()/recv();Redis 线程可继续处理其他事件。 - 事件驱动:避免忙轮询,减少 CPU 浪费,提升吞吐和响应。
4) I/O 多路复用怎么落地?
- 机制:select / epoll(Linux)、kqueue(FreeBSD)、evport(Solaris)。
- 流程:设置 FD 非阻塞 → 注册到多路复用器 → 内核监听 → 事件触发 → 放入事件队列 → 回调处理函数(如
accept/readhandler)。

5) Redis 的潜在阻塞点/慢点(面试高频追问)
- 网络层:
accept()、recv()(已用非阻塞+多路复用规避)。 - 慢命令/高复杂度命令:
SORT、SUNION、ZUNIONSTORE、KEYS、超大LRANGE/HGETALL等。 - 大 Key/Big Value:单线程处理一个大对象会拉长事件处理时间。
- 持久化:RDB/AOF 重写期间的 I/O 压力、写放大。
- 内存复制/序列化:协议编解码、大量返回值拷贝。
- 网络带宽/内核参数:大批量返回、Nagle、缓冲区设置不当等。
- 阻塞式操作:同步删除、脚本执行时间过长、事务中重命令。
- 集群/复制:全量同步、慢网络导致的复制积压。
和 Go 后端的关联点(容易被问)
- Go 的多路复用模型:Go 的
netpoller在 Linux 下基于 epoll;与 Redis 的事件驱动理念一致(就绪再处理)。 - 避免在 Redis 上做重活:在 Go 层限制慢命令、避免大 Key、细化数据结构(分片/拆桶)、限流与超时。
- 连接管理:用连接池(如
go-redis),Pipeline/批量以减少 RTT;合理ReadTimeout/WriteTimeout。 - 观测与保护:慢查询日志、
latency doctor、maxmemory策略、AOF 后台重写时的降压策略。 - 脚本与事务:Lua 脚本控制原子性但要短小;事务避免长队列。
图景化理解(面试口述示意)
单线程事件环:
- 内核监听一组 FD(监听 + 已连接)。
- 事件就绪 → 投递到事件队列。
- Redis 单线程按事件处理(
accept/read/ 解析 / 执行命令 /send)。
- 关键点:单线程不在某个 FD 上阻塞,把等待交给内核,自己只做“就绪即处理”。
你可以这样回答“为什么 Redis 单线程还这么快?”
Redis 的对外服务路径是单线程,避免了多线程对共享数据结构的加锁与上下文切换开销;它把等待交给内核,通过 非阻塞 socket + epoll/kqueue 的多路复用 实现事件驱动,单线程就能高并发处理大量连接。同时,Redis 基于内存与高效数据结构(哈希表/跳表)把单次操作成本压到极低,所以整体吞吐非常高。
面试加分扩展:Redis 6.0 的多线程
- 要点:Redis 6.0 在 I/O 阶段(读写/解析/回复)引入多线程以进一步利用多核,核心命令执行仍保持单线程逻辑,避免数据结构并发控制复杂化。
- 如何衔接本章:多路复用 + 事件环依旧存在,多线程更多用于I/O offload,不破坏核心串行语义。
复习清单(打星必背)
- “单线程”的准确含义与后台线程存在
- 单线程优点:无锁/少锁、上下文切换少、可维护性好
- 非阻塞 socket 与 阻塞点:
accept/recv - select/epoll/kqueue 的就绪事件驱动模型
- Redis 高性能三件套:内存 + 高效数据结构 + I/O 多路复用
- 面试陷阱:慢命令、大 Key、持久化冲击、复制放大
- Go 侧优化:Pipeline/批量、连接池、限时限流、慢日志与告警
- Redis 6.0 多线程的I/O 加速与执行仍单线程的设计取舍
“每课一问”参考答案(潜在瓶颈)
- 协议解析/序列化成本
- 单条命令执行过久(慢命令/大返回集)致事件环停顿
- 持久化/复制期间的磁盘与网络压力
- 大 Key/热 Key导致单事件占用时间过长
- 网络栈/带宽与内核参数(缓冲区、队列)限制
04 | AOF日志:宕机了,Redis如何避免数据丢失?
一、AOF 的作用与场景
🔹 Redis 为什么需要持久化?
- Redis 通常运行在内存中,宕机会导致数据丢失。
从数据库恢复数据:
- ❌ 频繁访问数据库 → 数据库压力大
- ❌ 恢复慢 → 响应变慢
- ✅ 持久化的目标:在不依赖外部数据库的情况下,保证数据可靠性。
🔹 Redis 持久化方式
- AOF 日志(Append Only File)
- RDB 快照(下一节)
二、AOF 的核心机制
1️⃣ AOF 是“写后日志”
- 数据库的 WAL(Write Ahead Log)是写前日志:先写日志再更新。
Redis 的 AOF 是写后日志:
先执行命令(更新内存) → 再记录日志(命令文本)
📘 为什么写后?
- 如果先记日志再执行,可能会把错误命令写入日志,导致恢复出错。
- 写后日志只记录执行成功的命令,保证日志的正确性。
优点:
- ✅ 只记录合法命令
- ✅ 不阻塞当前命令执行
风险:
- ⚠️ 刚执行完命令但未写入日志 → 宕机会丢失该命令
- ⚠️ 写日志慢(磁盘 I/O 压力大)→ 阻塞后续命令

三、AOF 三种写回策略(appendfsync)
| 策略 | 写回时机 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|---|
| always | 每条命令执行完后立刻写盘 | 几乎不丢数据 | 性能最差,主线程阻塞明显 | 数据绝对不能丢(金融类) |
| everysec | 每秒异步写盘 | 性能好,影响可控 | 宕机可能丢最近 1 秒数据 | 性能与可靠性折中(默认) |
| no | 操作系统决定 | 性能最高 | 宕机丢数据风险最大 | 数据可从 DB 重建的缓存场景 |
📌 核心考点:
Redis 的三种持久化策略体现了系统设计的经典哲学——trade-off(性能 vs. 可靠性)。
四、AOF 文件过大的问题与解决方案
问题:
- 文件系统对文件大小有限制。
- 文件越大,追加命令越慢。
- 宕机恢复时需重放所有命令,恢复速度变慢。
✅ 解决方案:AOF 重写机制(Rewrite)
⚙️ 原理:
- 根据当前内存中的最新数据生成新的 AOF 文件
- 不再保存所有历史命令,而是只记录恢复当前状态所需的最简命令集合。
📘 举例:
- 原日志中 6 条命令修改一个 list,最终状态是
[D, C, N] 重写后只保留:
LPUSH u:list "N" "C" "D"- 多条操作 → 一条命令(多变一)
📈 优点:
- 文件显著变小
- 重放更快

五、AOF 重写的实现细节(重点)
🔹 非阻塞的重写过程
主线程执行
bgrewriteaof命令后:- fork 一个子进程(bgrewriteaof)
- 子进程拷贝主线程的内存快照,用于生成新的 AOF 文件
- 主线程继续处理客户端请求,不被阻塞
🔹 “一个拷贝,两处日志”
- 一个拷贝:
fork 时复制主线程的内存,用于子进程重写。 两处日志:
- 主线程继续记录当前命令到旧 AOF 文件缓冲区
- 同时把新命令也写入重写缓冲区
- 重写完成后,把重写缓冲区的命令追加到新文件,替换旧文件。
📌 结论:
AOF 重写通过子进程完成,不阻塞主线程,但 fork 阶段会有短暂的内存复制耗时(可能造成瞬时阻塞)。

六、潜在风险与面试延伸题
⚠️ 1) AOF 重写会完全无阻塞吗?
不会。虽然重写由子进程执行,但 fork 期间会执行写时复制(Copy-On-Write),如果 Redis 数据量大,fork 时间会显著变长,可能短暂阻塞主线程。
⚠️ 2) 为什么重写日志不直接共用原 AOF 文件?
防止数据不一致:
- 重写过程和主线程的写操作是并行的。
- 共用同一文件可能导致新旧命令交织,日志错乱。
- 所以采用独立重写文件,最后再整体替换。
七、面试口述范式(推荐复述模板)
Redis 的 AOF 是一种写后日志机制,会记录执行成功的命令,用于宕机恢复。
它提供三种写回策略:always、everysec、no,在性能与可靠性之间做权衡。
为了防止 AOF 文件过大,Redis 支持后台非阻塞重写,由子进程bgrewriteaof完成,通过“一个拷贝,两处日志”保证数据不丢。
这体现了 Redis 在持久化机制中对性能、可靠性和主线程无阻塞的综合平衡。
八、Go 后端开发面试关联点
Go 服务常用
go-redis,要了解:- AOF 配置 (
appendfsync everysec) - RDB/AOF 混合持久化策略
- AOF 配置 (
设计缓存时:
- 明确 缓存数据是否要求持久化
- 合理选择策略:缓存型用
no,持久化用everysec
监控与优化:
- 关注
aof_current_size、aof_base_size - fork 时间过长 → 调整
vm.overcommit_memory
- 关注
若问“Redis 为什么快还能持久化?”:
- 持久化异步化 + fork + COW + 写后日志 → 主线程性能不受影响
九、复习要点清单 ✅
- Redis 持久化的两种方式:AOF / RDB
- AOF 是写后日志,记录执行成功的命令文本
- 三种写回策略:Always / Everysec / No
- AOF 文件过大 → AOF 重写机制
- 重写通过
bgrewriteaof子进程执行 → 非阻塞主线程 - “一个拷贝,两处日志”机制
- 潜在阻塞点:fork 过程(COW)
- 不共用日志的原因:避免数据交错/不一致
- trade-off 思想:性能与可靠性的取舍
05 | 内存快照:宕机后,Redis如何实现快速恢复?
一、RDB 是什么?解决了 AOF 的什么痛点
- 定义:把某一时刻内存中的所有数据写到磁盘(RDB 文件 = Redis DataBase snapshot)。
- 对比 AOF:AOF 恢复要重放命令,日志多时恢复慢;RDB 直接读入内存,恢复快。
二、核心设计与关键问题
1) “给哪些数据拍照?”
- 全量快照:把所有键值写入 RDB(“大合影”)。文件越大,写盘时间越久。
2) “拍照时能不能动?”
- bgsave(推荐,默认):主线程
fork子进程写 RDB,主线程不被长期阻塞。 - save:主线程直接写 RDB,会阻塞。
- COW(写时复制):bgsave 期间有写请求,修改的页被复制一份;子进程写旧快照页,主线程继续改新页 → 快照完整 + 业务可写。
面试金句:RDB = bgsave + COW,既保证快照一致性,也不拖慢写路径。

三、快照频率的取舍(不能“每秒连拍”)
- 频繁全量快照的两大代价:
① 磁盘带宽被吃满(前一次未完,下一次又来)
② fork 本身阻塞主线程(内存越大越久) - 过稀又有数据丢失风险(两次快照间的修改不在 RDB 内)。

四、增量思路 & 混合持久化(RDB + AOF)
- 增量快照理念:只记录自上次快照以来被修改的数据,但需要额外“修改元数据”,空间与复杂度↑。

Redis 4.0 混合方案(强烈推荐):
- 周期性 RDB(提供快速恢复)
- 两次 RDB 之间用 AOF 记录变更(减少 RDB 频率 & AOF 体量、避免频繁重写)
- 做到恢复快、丢失少、开销可控。

五、面试高频问答范式
Q:RDB 会阻塞吗?
A:save 会;bgsave 主逻辑不阻塞,但fork 短时阻塞不可避免。写入阶段依赖 COW,主线程可继续写。
Q:为什么不用“每秒 bgsave”?
A:磁盘压力+频繁 fork 造成性能抖动与主线程短阻塞,得不偿失。
Q:如何既恢复快又尽量少丢?
A:RDB + AOF(everysec)混合持久化:RDB 负责基线,AOF 覆盖快照间变更。
六、Go 后端落地建议(易被追问)
- 持久化策略:生产建议 RDB + AOF(everysec)。
- 运维调度:在低峰期做 RDB;写高峰期避免触发快照。
- 监控项:fork 时长、磁盘带宽、
used_memory与 COW 额外内存、RDB 用时。 内核/配置:
vm.overcommit_memory=1(降低大内存 fork 失败几率)rdb-save-incremental-fsync yes(增量 fsync 降低大抖动)- SSD、充足可用内存,避免 COW 导致 OOM。
七、选择建议(背诵版)
- 不能丢:RDB + AOF 混合。
- 可分钟级丢失:仅 RDB。
- 只用 AOF:优先 everysec(性能/可靠性折中)。
每课一问 · 场景风险分析(面试思路)
条件:2C/4GB/500GB 云主机;Redis 占 2GB;写 80%;持久化仅 RDB。
主要风险
- fork 短时阻塞:2GB 内存 + 高写入 → fork 更慢,主线程短暂停顿(尾延迟抖动)。
- COW 额外内存:写 80% 导致大量页被改写,COW 复制页激增,瞬时内存需求可能逼近/超过 4GB → OOM 风险或内核杀进程。
- 磁盘 I/O 压力:全量 RDB 写盘时间长;与常态写放在同一盘上会争用带宽,放大延迟。
- 数据丢失窗口:仅 RDB → 两次快照间宕机会丢最近窗口内的数据,写多更敏感。
- CPU 资源紧张:2C 下,fork+压缩+IO 校验等占用 CPU,影响请求处理。
改进建议
- 启用 RDB + AOF(everysec) 混合;降低 RDB 频次、在低峰执行。
- 使用 SSD,并确保与业务日志/其他重 IO 任务分盘。
- 预留足够内存(≥ 数据 + 峰值 COW 余量),或限制写峰值。
- 调整内核与 Redis:
vm.overcommit_memory=1、rdb-save-incremental-fsync yes。 - 观察 fork 时间、RSS、页脏化速率、磁盘吞吐;必要时分片/集群降低单实例内存规模。
复习清单(打星记忆)
- RDB = 快照文件,恢复快;AOF = 命令日志,恢复慢但粒度细
- bgsave + COW 核心机制;
save会阻塞 - 频繁全量快照不可取:磁盘 & fork 抖动
- 混合持久化(RDB + AOF everysec) = 恢复快 + 丢失少 + 开销可控
- 高写入场景仅 RDB 的五大风险与缓解措施