AOF
Redis 每执行一条写命令,就把该命令以追加形式写入一个文件。再重启时,先去读取这个文件的命令,然后执行,就能恢复缓存数据。这种方式就是 AOF(Append Only File)
Redis 中 AOF 默认是不开启的,可以通过修改配置文件开启
写回策略
如果每记录一条命令都要写回硬盘,那么会造成磁盘 IO 压力过大,进而阻塞进程
写回过程如下:
- 执行完写命令,将命令追加到 aof_buf 缓冲区
- 通过 write 系统调用,将缓冲区数据写入 AOF 文件,此时数据拷贝到文件系统 page cache
- 内核决定何时将数据写入硬盘
Redis 提供了 3 中写回硬盘的策略,控制上述第三步的过程
- Always:每次写命令之后,同步将 AOF 数据写回硬盘
- EverySec:每隔一秒将缓冲区的内容写入硬盘
- No:Redis 不控制,由操作系统来控制什么时候写入硬盘
以上三种策略都无法完美解决主进程阻塞和数据丢失的问题

AOF 重写
AOF 文件会随着写操作越来越多而变大,文件越大,带来的性能影响越大。因此提供了 AOF 重写机制,当 AOF 文件超过设定的阈值,就会触发 AOF 重写,来减小 AOF 文件大小
AOF 重写是指其会读取数据库所有键值对,然后将每一个键值对用一个命令记录到新的 AOF 文件。全部记录完之后,使用新的 AOF 文件替换旧的 AOF 文件
AOF 后台重写
写入 AOF 文件的过程是在主进程完成了,但由于写入内容少,因此不太影响命令操作。
但在 AOF 重写时需要读取所有键值对并写入新文件,这个过程是很耗时的,因此不能放在主进程操作
RDB
RDB 是一个快照,记录的是某个瞬间 Redis 中的内存数据。因此在恢复数据时,RDB 的效率会比 AOF 高很多
Redis 有两个命令来生成 RDB 文件
- save:在主进程生成 RDB 文件,会阻塞主进程
- bgsave:创建子进程来生成 RDB 文件
RDB 的加载是在 Redis 启动时自动执行的
在配置文件中,可以通过配置来实现间隔时间自动执行 bgsave 命令
执行快照时数据可以被修改吗?
执行 bgsave 快照过程中,Redis 的主进程是可以继续处理请求的,因此是可以被修改的
bgsave 执行时,子进程与主进程共享内存数据,如果主进程要修改共享数据中的某一块数据,就会发生写时复制,这块数据的物理内存会被复制一份,然后主进程在这个数据副本进行修改操作。与此同时,子进程可以继续吧原来的数据写入 RDB 文件
在极端情况下,如果所有共享内存都被修改,则此时的内存占用是原来的两倍
RDB + AOF 混合持久化
RDB 比 AOF 数据恢复效率高,但是快照频率难以控制:
- 频率太低,则容易丢失过多数据
- 频率太高,频繁写入磁盘和创建子进程会有额外开销
因此在 Redis 4.0 提出混合使用 AOF 日志和 RDB 快照
混合持久化工作在 AOF 日志重写的过程。在 AOF 重写时,会先将与主进程共享的内存数据以 RDB 方式写入 AOF 文件,然后主进程处理的操作命令会被记录在重写缓冲区,这些增量命令会以 AOF 方式写入 AOF 文件
因此使用了混合持久化之后,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据
大 Key 对持久化的影响
对 AOF 的影响
- 如果写入策略是 Always,既每次写入都会同步写入磁盘文件,那么在大 key 写入时,会导致写入时阻塞时间较长
对 AOF 重写及 RDB 的影响
- fork 创建子进程时,内核会把父进程的页表复制一份给子进程,如果页表很大,那么复制过程会很耗时,导致 fork 执行时阻塞
- 当主进程修改共享数据时,会发生写时复制。大 key 会导致复制的时间较长,导致主进程阻塞
其他影响
- 处理大 key 比较耗时,导致 Redis 主进程阻塞
- 大 key 导致带宽占用过高
- 集群场景内存分布不均
避免
- 设计阶段把大 key 进行拆分
- 定时检查是否存在大 key,进行优化
- 删除时不要使用 del,del 会阻塞主进程