前言

我已经学习完了Redis的基础篇,笔记见https://blog.lecspace.com/index.php/archives/80/。但是,这只是学会使用Redis的入场券,想要在被面试官拷打redis相关知识点时游刃有余,必须要更加深入研究它。

我会跟着《Redis45讲》进行学习,这篇文章是我学习这东西的笔记。

1.怎样学Redis更好?

此节不重要,浓缩总结一下:如何学Redis?

🧭 两大维度:

  • 系统维度:理解 Redis 的底层原理与架构;
  • 应用维度:从实际业务场景和案例出发,掌握使用技巧。

🧩 三大主线(简称“三高”):

主线涉及模块目标
高性能线程模型、数据结构、持久化、网络框架提升吞吐与响应速度
高可靠主从复制、哨兵机制保证数据一致与高可用
高可扩展数据分片、负载均衡支撑大规模集群部署

作者建议:

  • 先按“三高主线”构建知识框架;
  • 再结合“应用场景驱动 + 典型案例驱动”深入学习。

01 | 基本架构:一个键值数据库包含什么?

1)主旨

  • 先用最小可用的键值库 SimpleKV 搭“骨架”,形成系统观,再带着框架去理解 Redis 的复杂特性与优化路径。

2)SimpleKV 的架构与搭建顺序

  1. 数据模型:Key 为 String;Value 支持基础类型(String、整数等)。
    └→ 现实里的 KV(如 Redis)会把 Value 做成多类型(String/Hash/List/Set…),以适配更多场景。【重点】
  2. 操作接口:最小集合为 PUT/GET/DELETE/SCAN,可扩展 EXISTS
    └→ 操作能力决定适用场景:KV 易做点查/简单集合操作,但不擅长聚合计算(如平均值)。【重点】
  3. 数据放哪里

    • 内存:快,但断电丢;
    • 外存:稳,但慢。
      SimpleKV 选内存以贴近 Redis 的“高性能缓存”定位。【重点】
  4. 访问模式(I/O 模型)

    • 库调用(如 RocksDB) vs 网络服务(如 Redis/Memcached);
    • 线程/进程模型取舍:单线程易被阻塞,多线程有锁竞争。I/O 设计直接影响吞吐与延迟。【重点】
  5. 索引模块:按 key 找 value 的位置;内存 KV 常用 哈希表(O(1) 近似)。
    └→ Redis 的多 Value 类型内部还有自己的数据结构(如列表/集合),二级结构的选择影响性能。【重点】
  6. 操作模块

    • GET/SCAN:读出 value;
    • PUT:分配空间并写入;
    • DELETE:删除并释放空间。
  7. 存储/持久化模块

    • 内存分配器选择会影响碎片与效率(SimpleKV 用 malloc/free,Redis 可选多种分配器);
    • 持久化策略

      • 逐条落盘:稳但慢;
      • 周期落盘:快但偶有丢失。
        Redis 对持久化做了更多机制与优化(见下)。

3)从 SimpleKV → Redis 的关键“进化”

  • 访问方式:以 网络服务为主(RESP 协议),通用性更强。
  • 数据模型丰富的 Value 类型 → 对应更丰富的命令(LPUSH/LPOP、SADD/SREM…)。
  • 持久化AOF(日志) + RDB(快照) 两条线,权衡性能 vs 数据安全。【重点】
  • 集群/高可用:支持复制、哨兵、分片等,满足 高可靠/高扩展。【重点】

圈重点

  1. 系统观优先:先搭框架(数据模型→接口→I/O→索引→操作→持久化),再深入点技。
    【重点:学习顺序与定位问题的方法论】
  2. 操作能力决定边界:KV 擅长点查与简单集合操作,不擅长复杂聚合(平均值、join)。
    【重点:选型与场景匹配】
  3. 多类型 Value = 性能与空间的权衡:每种结构背后都有不同的时间/空间复杂度内存布局
    【重点:命令性能差异的根源在“底层数据结构”】
  4. I/O 与线程模型是吞吐/延迟的第一性问题:单线程避免锁但怕阻塞;多线程并发高但有竞争。
    【重点:理解 Redis 为何“单线程也高性能”及其边界】
  5. 内存分配与碎片会放大延迟波动与内存占用。
    【重点:生产环境经常被忽视的性能坑】
  6. 持久化两条线(AOF/RDB)

    • AOF:更安全,可控刷盘,可能带来写放大/延迟抖动;
    • RDB:整库快照,恢复快但快照时有资源压力。
      【重点:按业务容忍度选择或组合】
  7. 从 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)(与数据量弱相关)。【重点】

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

  • 扩容机制渐进式 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)集合操作的复杂度——四句口诀

  1. 单元素操作是基础:底层若是哈希表,多为 O(1)(如 HGET/HSET、SADD/SREM)。【重点】
  2. 范围操作非常耗时:遍历/范围读取多为 O(N)(如 HGETALL、SMEMBERS、LRANGE、ZRANGE)。【重点】
  3. 统计操作通常高效:记录了长度/基数的结构,LLEN/SCARD 常为 O(1)
  4. 例外情况有几个:List 的 头尾操作(LPUSH/RPUSH/LPOP/RPOP)可 O(1)(有偏移量/指针可直达)。

5)慢从哪来?

  • 哈希冲突链过长;
  • 一次性 rehash 会阻塞(Redis 用渐进式缓解);【重点】
  • 对集合做全量遍历/范围操作导致 O(N)
  • 选择了不合适的底层结构(如把 List 当随机读写容器)。

实战“避坑清单”(按影响度排序)

  1. 避免 O(N) 的范围命令:HGETALL / SMEMBERS / LRANGE / ZRANGE 等,
    → 尽量用 SCAN/HSCAN/SSCAN/ZSCAN 渐进遍历;限制返回条数。【重点】
  2. 单元素优先:HGET/HSET、SADD/SREM、ZADD/ZREM 等是基础操作路径,延迟稳定。
  3. 别把 List 当数组:List 适合 队列(头尾),不适合随机访问/大范围读取。
    → 队列/日志:LPUSH/RPOP 等;随机访问考虑 Hash/Sorted Set。
  4. 关注哈希表负载与 rehash

    • 大批量写入可能触发扩容;
    • 服务繁忙期避免集中触发;
    • 合理批量/预热/均衡写入节奏。【重点】
  5. 按“规模/类型”选编码

    • 小而简单的集合: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 / read handler)。

5) Redis 的潜在阻塞点/慢点(面试高频追问)

  • 网络层:accept()recv()(已用非阻塞+多路复用规避)。
  • 慢命令/高复杂度命令SORTSUNIONZUNIONSTOREKEYS、超大 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 doctormaxmemory 策略、AOF 后台重写时的降压策略。
  • 脚本与事务:Lua 脚本控制原子性但要短小;事务避免长队列。

图景化理解(面试口述示意)

  • 单线程事件环

    1. 内核监听一组 FD(监听 + 已连接)。
    2. 事件就绪 → 投递到事件队列。
    3. 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 持久化方式

  1. AOF 日志(Append Only File)
  2. RDB 快照(下一节)

二、AOF 的核心机制

1️⃣ AOF 是“写后日志”

  • 数据库的 WAL(Write Ahead Log)是写前日志:先写日志再更新。
  • Redis 的 AOF 是写后日志

    先执行命令(更新内存) → 再记录日志(命令文本)

📘 为什么写后?

  • 如果先记日志再执行,可能会把错误命令写入日志,导致恢复出错。
  • 写后日志只记录执行成功的命令,保证日志的正确性
  • 优点:

    • ✅ 只记录合法命令
    • ✅ 不阻塞当前命令执行
  • 风险:

    • ⚠️ 刚执行完命令但未写入日志 → 宕机会丢失该命令
    • ⚠️ 写日志慢(磁盘 I/O 压力大)→ 阻塞后续命令


三、AOF 三种写回策略(appendfsync

策略写回时机优点缺点使用场景
always每条命令执行完后立刻写盘几乎不丢数据性能最差,主线程阻塞明显数据绝对不能丢(金融类)
everysec每秒异步写盘性能好,影响可控宕机可能丢最近 1 秒数据性能与可靠性折中(默认)
no操作系统决定性能最高宕机丢数据风险最大数据可从 DB 重建的缓存场景

📌 核心考点
Redis 的三种持久化策略体现了系统设计的经典哲学——trade-off(性能 vs. 可靠性)


四、AOF 文件过大的问题与解决方案

问题:

  1. 文件系统对文件大小有限制。
  2. 文件越大,追加命令越慢。
  3. 宕机恢复时需重放所有命令,恢复速度变慢。

✅ 解决方案:AOF 重写机制(Rewrite)

⚙️ 原理:

  • 根据当前内存中的最新数据生成新的 AOF 文件
  • 不再保存所有历史命令,而是只记录恢复当前状态所需的最简命令集合。

📘 举例:

  • 原日志中 6 条命令修改一个 list,最终状态是 [D, C, N]
  • 重写后只保留:

    LPUSH u:list "N" "C" "D"
  • 多条操作 → 一条命令(多变一

📈 优点:

  • 文件显著变小
  • 重放更快


五、AOF 重写的实现细节(重点)

🔹 非阻塞的重写过程

  • 主线程执行 bgrewriteaof 命令后:

    • fork 一个子进程(bgrewriteaof)
    • 子进程拷贝主线程的内存快照,用于生成新的 AOF 文件
    • 主线程继续处理客户端请求,不被阻塞

🔹 “一个拷贝,两处日志”

  1. 一个拷贝
    fork 时复制主线程的内存,用于子进程重写。
  2. 两处日志

    • 主线程继续记录当前命令到旧 AOF 文件缓冲区
    • 同时把新命令也写入重写缓冲区
    • 重写完成后,把重写缓冲区的命令追加到新文件,替换旧文件。

📌 结论
AOF 重写通过子进程完成,不阻塞主线程,但 fork 阶段会有短暂的内存复制耗时(可能造成瞬时阻塞)。


六、潜在风险与面试延伸题

⚠️ 1) AOF 重写会完全无阻塞吗?

不会。虽然重写由子进程执行,但 fork 期间会执行写时复制(Copy-On-Write),如果 Redis 数据量大,fork 时间会显著变长,可能短暂阻塞主线程

⚠️ 2) 为什么重写日志不直接共用原 AOF 文件?

防止数据不一致:

  • 重写过程和主线程的写操作是并行的。
  • 共用同一文件可能导致新旧命令交织,日志错乱。
  • 所以采用独立重写文件,最后再整体替换。

七、面试口述范式(推荐复述模板)

Redis 的 AOF 是一种写后日志机制,会记录执行成功的命令,用于宕机恢复。
它提供三种写回策略:alwayseverysecno,在性能与可靠性之间做权衡。
为了防止 AOF 文件过大,Redis 支持后台非阻塞重写,由子进程 bgrewriteaof 完成,通过“一个拷贝,两处日志”保证数据不丢。
这体现了 Redis 在持久化机制中对性能、可靠性和主线程无阻塞的综合平衡。

八、Go 后端开发面试关联点

  • Go 服务常用 go-redis,要了解:

    • AOF 配置 (appendfsync everysec)
    • RDB/AOF 混合持久化策略
  • 设计缓存时:

    • 明确 缓存数据是否要求持久化
    • 合理选择策略:缓存型用 no,持久化用 everysec
  • 监控与优化:

    • 关注 aof_current_sizeaof_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 体量、避免频繁重写)
    • 做到恢复快丢失少开销可控

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

主要风险

  1. fork 短时阻塞:2GB 内存 + 高写入 → fork 更慢,主线程短暂停顿(尾延迟抖动)。
  2. COW 额外内存:写 80% 导致大量页被改写,COW 复制页激增,瞬时内存需求可能逼近/超过 4GBOOM 风险或内核杀进程。
  3. 磁盘 I/O 压力:全量 RDB 写盘时间长;与常态写放在同一盘上会争用带宽,放大延迟。
  4. 数据丢失窗口:仅 RDB → 两次快照间宕机会丢最近窗口内的数据,写多更敏感。
  5. CPU 资源紧张:2C 下,fork+压缩+IO 校验等占用 CPU,影响请求处理

改进建议

  • 启用 RDB + AOF(everysec) 混合;降低 RDB 频次、在低峰执行。
  • 使用 SSD,并确保与业务日志/其他重 IO 任务分盘。
  • 预留足够内存(≥ 数据 + 峰值 COW 余量),或限制写峰值
  • 调整内核与 Redis:vm.overcommit_memory=1rdb-save-incremental-fsync yes
  • 观察 fork 时间、RSS、页脏化速率、磁盘吞吐;必要时分片/集群降低单实例内存规模。

复习清单(打星记忆)

  • RDB = 快照文件,恢复快;AOF = 命令日志,恢复慢但粒度细
  • bgsave + COW 核心机制;save 会阻塞
  • 频繁全量快照不可取:磁盘 & fork 抖动
  • 混合持久化(RDB + AOF everysec) = 恢复快 + 丢失少 + 开销可控
  • 高写入场景仅 RDB 的五大风险缓解措施
最后修改:2025 年 10 月 24 日
如果觉得我的文章对你有用,请随意赞赏