谈谈Redis 的持久化策略?
参考文章:
Redis
的确是将数据存储在内存的,但是也会有相关的持久化机制将内存持久化备份到磁盘,以便于重启时数据能够重新恢复到内存中,避免数据丢失的风险。而Redis
持久化机制有三种:AOF
、RDB
、混合型持久化(4.x版本后提供)
-
RDB持久化
关闭 RDB 持久化只需要将 save 保存策略注释掉即可
RDB持久化的方式有两种:
-
手动触发(分为手动 save 和手动 bgsave)
-
手动save:阻塞当前 Redis,直到持久化完成,可能造成长时间阻塞,线上不建议使用。
-
手动bgsave:Redis 进程执行
fork
创建子进程进行持久化,阻塞事件很短。在执行Redis-cli shutdown
关闭Redis
服务时或执行flushall
命令时,如果没有开启AOF
持久化,自动执行bgsave
-
-
被动触发(以下四种情况会被动触发)
-
达到了在 redis.conf 中配置被动触发的条件,会触发 bgsave 生成 rdb 文件
Redis 中 save 操作的配置:从右向左条件主键变弱,如果60s发生了10000次写操作,就进行持久化,如果没有达到,在300s时,如果有100次写操作就会持久化,如果没有达到在3600s,如果有一次写操作就会持久化
-
主从复制时,从节点需要全量同步主节点的数据,会触发 bgsave
-
执行
debug reload
命令重新加载 redis 时,会触发 bgsave -
执行
shutdown
命令时,如果没有开启 aof 持久化,会触发 bgsave
-
bgsave子进程工作原理:
由子进程继承父进程所有资源,且父进程不能拒绝子进程继承,bgsave子进程先将内存中的全量数据copy到磁盘的一个
RDB临时文件
,持久化完成后将该临时文件替换原来的dump.rdb
文件。如果持久化过程中出现了新的写请求,则系统会将内存中发生数据修改的物理块copy出一个副本,bgsave 子进程会把这个副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据,
fork
使用了写时复制技术(Copy-On-Write)
。
操作系统中的写时复制技术:
目的:是避免不必要的内存拷贝。
在Linux系统中,调用
fork
系统调用创建子进程时,并不会把父进程所有占用的内存页复制一份,而是与父进程共用相同的内存页 ,而当子进程或者父进程对内存页 进行修改时才会进行复制 ------ 这就是著名的写时复制
机制。那么bgsave中的写时复制技术即如果在持久化过程中,写入了新的数据,此时再去将元数据重新拷贝一份,进行修改。
优点:
- 使用单独子进程持久化,保证 redis 高性能。
- RDB 持久化存储压缩的二进制文件,适用于备份、全量复制,可用于灾难备份,同时
RDB
文件的加载速度远超于AOF
文件。
缺点:
- 没有实时持久化,可能造成数据丢失。
- 备份时占用内存,因为
Redis
在备份时会独立创建一个子进程,将数据写入到一个临时文件(需要的内存是原本的两倍) RDB
文件保存的二进制文件存在新老版本不兼容的问题。
-
-
AOF持久化
默认AOF没有开启,可在
redis.conf
中配置Redis7发生了重大变化,原来只有一个appendonly.aof文件,现在具有了三类多个文件:
- 基本文件:RDB格式或AOF格式。存放RDB转为AOF当时内存的快照数据。该文件可以有多个。
- 增量文件:以操作日志形式记录转为AOF后的写入操作。该文件可以有多个。
- 清单文件:维护AOF文件的创建顺序,保证激活时的应用顺序。该文件只可以有1个。
aof 文件中存储的
resp 协议数据格式
,如果执行命令set a hello
,aof文件内容如下:(*3代表有3条命令,$5代表有5个字符)
bash*3 $3 set $1 a $5 hello
AOF持久化时,其实是先写入缓存中,之后再同步到磁盘中,同步策略有三种:
appendfsync always
:每次写入都同步到磁盘,最安全,但影响性能。appendfsync everysec
(推荐、默认配置):每秒同步一次,最多丢失1秒的数据。appendfsync no
:Redis
并不直接调用文件同步,而是交给操作系统来处理,操作系统可以根据buffer
填充情况/通道空闲时间等择机触发同步;这是一种普通的文件操作方式。性能较好,在物理服务器故障时,数据丢失量会因OS
配置有关。
优点:
- 数据丢失风险较低,后台线程处理持久化,不影响客户端请求处理的线程。
缺点:
- 文件体积由于保存的是所有命令会比
RDB
大上很多,而且数据恢复时也需要重新执行指令,在重启时恢复数据的时间往往会慢很多。
AOF的重写(Rewrite)机制:
-
为了防止AOF文件太大占用大量磁盘空间,降低性能,Redis引入了Rewrite机制对AOF文件进行压缩
Rewrite就是对AOF文件进行重写整理。当开启Rewrite,主进程redis-server创建出一个子进程bgrewriteaof,由该子进程完成rewrite过程。
首先会对现有aof文件进行重写,将计算结果写到一个临时文件,写入完毕后,再重命名为原aof文件,进行覆盖。
配置AOF重写频率
bash# auto‐aof‐rewrite‐min‐size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大 # auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写
AOF的持久化流程图:
-
混合持久化开启
默认开启,即AOF持久化的基本文件时的基本文件是RDB格式的。(必须先开启aof)
混合持久化重写aof文件流程 :aof 在重写时,不再将内存数据转为 resp 数据写入 aof 文件,而是将之前的内存数据做 RDB 快照处理,将
RDB快照+AOF增量数据
存在一起写入新的 AOF 文件,完成后覆盖原有的 AOF 文件。
Redis重启加载数据流程:
- 先加载 RDB 数据到内存中
- 再重放增量 AOF 日志,加载 AOF 增量数据
优点:
- 结合了 RDB 和 AOF,既保证了重启 Redis 的性能,又降低数据丢失风险
缺点:
- AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;