线程模型

Redis线程模型:

“关于 Redis 的线程模型,我是这样理解的:

首先,Redis 的核心命令执行是单线程的。它采用 Reactor 模式,基于 I/O 多路复用(如 epoll)来监听海量客户端连接。因为数据主要在内存中操作,且避免了多线程的上下文切换和锁竞争,所以单线程效率很高。

其次,Redis 6.0 引入了多线程 I/O。这是因为随着网络带宽增加,单线程处理网络读写成了瓶颈。现在的多线程主要用于并行处理网络数据的读写和协议解析,而命令的执行依然是单线程串行执行的,这样既提升了性能,又保证了命令的原子性。

此外,Redis 还有一些后台线程(BIO),用于处理像大 Key 删除、AOF 刷盘这样的耗时操作,防止这些操作阻塞主线程。”

追问准备:面试官可能会问:“既然单线程这么好,为什么不用多线程执行命令?”

回答:“主要是因为 Redis 的操作都是内存级的,CPU 通常不是瓶颈。如果改成多线程执行命令,为了保证数据一致性,需要引入复杂的锁机制,这会带来巨大的开销,而且会让代码变得非常复杂,得不偿失。目前的方案(单线程执行 + 多线程 I/O)是在性能和复杂度之间做的完美平衡。”

RDB快照

核心概念

RDB 是在某一个时间点将 Redis 内存中的全部数据生成一个快照(Snapshot),并写入磁盘(默认为 dump.rdb文件)。

触发机制

  1. 手动触发
    • SAVE:同步执行。会阻塞 Redis 主线程,直到 RDB 完成。生产环境严禁使用
    • BGSAVE(Background Save):异步执行。Redis 主进程会 fork出一个子进程,由子进程负责生成 RDB 文件,主进程继续处理请求。这是 RDB 的主要工作方式
  2. 自动触发
    • redis.conf中配置 save <seconds> <changes>。例如 save 900 1表示 900 秒内如果有至少 1 次修改,就触发 BGSAVE。

工作原理(Copy-On-Write)

这是面试高频考点。

  1. 执行 BGSAVE时,Redis 调用 fork()创建子进程。
  2. 父子进程共享同一块内存数据
  3. 子进程开始将数据写入临时的 RDB 文件。
  4. 此时,如果主进程收到写请求(修改数据),操作系统会使用写时复制(Copy-On-Write, COW)技术。主进程会将被修改的内存页复制一份副本进行修改,而子进程看到的仍然是旧的数据快照。这就保证了 RDB 文件的一致性。

优缺点

  • 优点

    • 恢复速度快:RDB 文件是二进制压缩文件,加载时直接读入内存,速度远快于 AOF 重放命令。
    • 体积小:文件紧凑,适合做冷备份和灾难恢复。
    • 对性能影响小:由子进程处理,主进程几乎不阻塞(除了 fork 瞬间)。
  • 缺点

    • 数据丢失风险大:如果在两次快照之间宕机,这期间的数据会丢失

      image-20260518135523433

    • fork 开销:如果数据集很大,fork操作可能会比较耗时,导致主进程短暂停止响应(Stop-The-World)

AOF日志追加

核心概念

AOF 记录的是每一个写命令(类似于 MySQL 的 binlog),以 RESP 协议 的格式追加到文件末尾(appendonly.aof)。

工作流程

  1. **命令追加 (Append)**:执行写命令时,将命令追加到 aof_buf缓冲区。

  2. **文件写入 (Write) & 同步 (Sync)**:根据不同的策略将缓冲区内容写入并同步到磁盘。

  3. ==文件重写 (Rewrite)==:随着时间推移,AOF 文件会变得很大(比如对一个 key 操作了 100 次,AOF 记录了 100 条命令,但其实只有最后一条有效)。Redis 会 fork 子进程,根据当前内存数据生成最小的写命令集合,替换旧的 AOF 文件。

    重写期间,主线程将新写命令同时写入:

    1. 原有 AOF 文件(保证旧 AOF 完整)

    2. AOF 重写缓冲区
      子进程完成后,主线程将重写缓冲区增量追加入新 AOF 文件,然后用新文件原子替换旧文件。

刷盘策略 (fsync)

==AOF先写到缓冲区【缓存区是操作系统的概念,操作系统会决定把自己的缓冲区数据刷盘,所以为什么可以操作系统控制的原因】,再刷盘==

这是 AOF 的关键配置,决定了数据安全性和性能的权衡:

  • appendfsync always每条命令都同步刷盘。最安全,但性能最差(硬盘 I/O 成为瓶颈)。
  • appendfsync everysec每秒刷盘一次(==默认推荐==)。最多丢失 1 秒的数据。兼顾性能和安全。
  • appendfsync no由操作系统控制。性能最好,但数据丢失风险不可控。

优缺点

  • 优点
    • 数据安全:默认每秒同步,最多丢失 1 秒数据;使用 always则基本不丢数据。
    • 可读性强:AOF 文件是文本格式(RESP),可以手动打开查看或修复(例如不小心执行了 FLUSHALL,只要没触发重写,可以去掉该命令重启恢复)。
  • 缺点
    • 文件体积大:即使经过重写,通常也比 RDB 大。
    • 恢复速度慢:重启时需要重新执行所有命令,数据量大时启动非常慢

AOF混合持久化方式

这是 Redis 4.0 引入的重大改进,也是目前生产环境的首选方案

核心概念

==基本流程和AOF一样==

==但是==在 AOF 重写(Rewrite) 的时候,不再单纯将内存数据转换为 RESP 命令写入 AOF,而是先将内存数据以 RDB 格式写入 AOF 文件的开头,然后再将重写缓冲区的增量命令(RESP格式)追加到文件末尾

文件结构

新的 AOF 文件结构如下:

1
[RDB 格式的全量数据] + [AOF 格式的增量数据]

优势

  1. 启动速度快:恢复时,先加载 RDB 部分(快),再重放 AOF 部分的增量命令(少)。
  2. 数据安全性高:结合了 AOF 的实时性。

如何开启

redis.conf中设置 aof-use-rdb-preamble yes(Redis 5.0 之后默认开启)。

问题

Redis 重启时加载文件的顺序是什么?

  • 如果开启了 AOF,优先加载 AOF。
  • 如果 AOF 关闭,或者 AOF 文件不存在,加载 RDB。
  • 如果开启了混合持久化,AOF 文件其实是混合格式,Redis 会自动识别并先按 RDB 加载,再执行后续的 AOF 命令。

三种模式可以同时开启

image-20260518142037028

数据丢失情况

  • RDB可能会丢失两次快照之间的数据
  • AOF按策略会丢失(例如每秒1次,则会丢失1秒的数据)
  • 混合模式:混合模式的数据安全性与传统 AOF 是一样高的,不会因为用了混合模式就增加数据丢失的风险

如果丢失了怎么办?

如果不幸发生了数据丢失,我会分两步走:

第一是止损。如果是误操作,我会尝试利用 AOF 文件的日志特性,通过 redis-check-aof工具或手动编辑移除误操作命令来恢复;如果是宕机,我会利用现有的 RDB 或 AOF 文件重启恢复,并接受这部分时间窗口内的数据丢失。

第二是复盘和预防。我会反思架构,强调单机的持久化机制(即使是混合模式)都存在理论上的数据丢失窗口。在生产环境中,必须通过部署主从架构来保证高可用,同时结合定期冷备 RDBAOF 实时记录,构建多层防护体系,而不是仅仅依赖 Redis 自身的持久化。”