【每日八股】复习 Redis Day1:Redis 的持久化(上)
文章目录
- 复习 Redis Day1:Redis 的持久化(上)
- 简述 Redis 持久化的两种策略?
- RDB(Redis Database)
- AOF(Append Only File)
- 混合持久化
- 如何选择持久化策略?
- AOF 的三种持久化/写回策略?
- AOF 的磁盘重写机制?
- 为什么先执行一个 Redis 写命令,再将该命令写入到 AOF 缓冲区?
- AOF 重写的具体过程?
复习 Redis Day1:Redis 的持久化(上)
简述 Redis 持久化的两种策略?
Redis 提供两种主要的持久化策略,用于将缓存中的数据保存到磁盘当中,避免设备故障重启后数据的丢失。这两种持久化策略分别是 RDB 和 AOF。
RDB(Redis Database)
概念
RDB 是指定时间间隔生成的数据的快照(二进制压缩文件,默认文件名为 dump.rdb
)。
触发方式
Redis 会定时自动触发,开启子进程写 RDB;也可以通过命令进行手动触发。
优点
- 文件紧凑,适合 Redis 备份以及容灾恢复;
- 恢复大数据集时速度比 AOF 快,因为 RDB 是整个数据库的快照,而 AOF 是写命令的集合,通过 AOF 恢复还需要执行相应的命令;
- 对性能影响小,因为 Redis 开启子进程写 RDB,不占用主进程。
缺点
- 可能丢失最后一次快照后的数据,可以通过 AOF + RDB 混合来解决;
- 大数据集时,子进程生成 RDB 快照较慢,可能占用更多的 CPU 和内存。
AOF(Append Only File)
概念
记录所有写操作命令(以文本形式追加到文件中,文件名为 appendonly.aof
)。
工作流程
命令先执行,之后写入 AOF 缓冲区。缓冲区当中的数据将根据同步策略持久化到磁盘当中,比如:
always
:每个命令都会同步到磁盘,安全性最佳但性能最差;everysec
:每秒同步一次,最多丢失一秒的数据;no
:由 OS 决定,速度最快,但是安全性最差。
优点
- 数据安全性较高,在
everysec
同步策略下最多丢失「一秒」的数据。相较于 AOF,RDB 可能会丢失上一次快照之后的全部数据。 - AOF 文件的可读性强,便于人工修复与分析。
- 支持后台重写压缩文件。
缺点
- 文件体积通常比 RDB 大。
- 恢复速度慢,因为需要重新执行所有命令。
- 高频写入时 I/O 压力大。
混合持久化
概念
AOF 重写时生成 RDB 格式的快照作为基础数据,后续的增量数据写入到 RDB 当中。
优点
- 兼顾了 RDB 的快速恢复以及 AOF 的数据安全性;
- 减少 AOF 文件体积,重写效率高。
如何选择持久化策略?
场景 | 策略 |
---|---|
允许分钟级数据丢失 | RDB,因为 RDB 文件小,恢复速度快 |
需要更高的数据安全性 | AOF,并开启逐条写入,牺牲性能换取安全性 |
兼顾数据安全性与性能 | RDB + AOF 混合 |
灾难恢复 | RDB,因为 RDB 文件更小,恢复速度快 |
总的来说,RDB 更重视恢复速度(可能丢失分钟级数据),AOF 更重视数据安全性(everysec
同步策略下最多丢失一秒的数据,always
下不丢失数据,但会因为 I/O 压力上升导致性能下降)。
AOF 的三种持久化/写回策略?
分别是 always
、everysec
和 no
。
always
:每次写操作执行完毕后,同步 AOF 日志数据到磁盘;everysec
:每次写操作完毕后,将写操作写入 AOF 缓冲区,每秒持久化到磁盘一次;no
:不控制回写磁盘的时机,由 OS 决定何时将缓冲区当中的数据写入到磁盘。
AOF 的磁盘重写机制?
AOF 的磁盘重写机制(AOF Rewrite)是为了解决随着写命令增多而导致的 AOF 文件体积过大以及恢复速度变慢的问题。其核心是基于当前 Redis 数据库的状态新建一个更紧凑的 AOF 文件,从而移除旧 AOF 文件中冗余的命令,只保留当前 Redis 数据库状态的最小集合。
具体来说,触发 AOF 重写之后,「Redis 开启一个子进程」,将当前 Redis 缓存当中的状态转为写命令并写入一个新的 AOF 文件,新的 AOF 文件与当前 AOF 文件等效,但体积更小,因为删除了冗余的旧命令和重复命令。
为什么先执行一个 Redis 写命令,再将该命令写入到 AOF 缓冲区?
先执行 Redis 命令可以保证写入到 AOF 当中的命令一定是正确的,在数据恢复时不需要再进行语法检查。缺点在于如果 Redis 执行命令后突然宕机,还没来得及将命令记录到 AOF,会导致数据丢失。
AOF 重写的具体过程?
Redis 使用「子进程」执行重写,仅在子进程 fork()
时可能阻塞主进程。具体来说:
步骤一:主进程 fork 子进程
主进程调用 fork()
创建子进程,子进程获得 fork()
执行时与主进程完全相同的内存数据快照。
步骤二:子进程生成新的 AOF 文件
子进程遍历 Redis 内存中所有 key-value pair,将每个键的当前状态转为等效的 Redis 命令,写入临时文件。
步骤三:处理重写期间的增量数据
主进程继续接收客户端的请求,新的写命令会正常执行,并「同时」追加到原 AOF 缓冲区和重写 AOF 缓冲区。
步骤四:子进程完成重写
子进程生成新的 AOF 后,向主进程发送信号。主进程收到信号后,将重写缓冲区内的所有命令追加到新的 AOF 文件尾,并将旧的 AOF 替换为新的 AOF。