redis 持久化
redis 持久化
redis 是一个内存数据库,把数据存储在内存中的,内存中的数据是不持久的,要想做到持久,就需要让redis把数据存储到硬盘上。
为了保证速度块,数据肯定还是得在内存中,但是为了持久化,数据还得想办法存储在硬盘上。
redis持久化策略
RDB => Redis DataBase 定期备份
RDB 定期的把 Redis 内存中的所有数据,都给写入到硬盘中,生成一个 “快照”。
“定期”具体来说又分为两种方式:
-
手动触发
即通过redis客户端,执行特定的命令(save / bgsave),来触发快照生成。-
save
执行 save 命令的时候,redis 就会全力以赴的进行 “快照生成” 操作,此时就会阻塞 redis 其他客户端的命令~~ (进而导致类似于 keys *的后果)save 命令就是直接再当前进程中,直接往 /var/lib/redis/dump.rdb 文件中写入,没有文件替换操作。
-
bgsave bg => background(后面)
bgsave 不会影响 redis 服务器处理其他客户端的请求和命令。
其中bgsave的执行流程图如下:
1.父进程先判断当前是否已经存在其他正在工作的子进程。
即比如现在已经有一个子进程正在执行 bgsave,此时就直接把当前的 bgsave 返回~~
2.如果没有其他工作的子进程,就通过 fork 这样的系统调用去创建一个子进程
3.默认情况下父进程会阻塞等待子进程退出。
即父进程设置了"nohup"参数为"no"。这就意味着父进程将会阻塞等待子进程完成持久化操作,并且在此期间无法处理新的命令请求。
如果父进程设置了"nohup"参数为"yes",它将不会等待子进程退出。此时子进程负责进行写文件,生成快照。父进程继续接收客户端的请求,继续正常提供服务。
4.子进程完成整体的持久化过程之后,就会通知父进程,父进程就会更新一些统计信息,进而子进程就可以结束销毁了。
其中 redis 生成的快照 rdb 文件,是存放在 redis 的工作目录中的。该路径也是在redis 配置文件中进行设置的。配置文件通常在 /etc/redis/redis.conf
rdb 机制生成的镜像文件,redis 服务器默认就是开启了 rdb 的
其中 rbd 是 一个二进制文件,即把内存中的数据以压缩的形式,保存到这个二进制文件中。
当子进程生成 rdb 镜像操作的时候,此时就会把要生成的快照数据,先保存到一个临时文件中,当这个快照生成完毕之后,再删除之前的的 rdb 文件,把新生成的临时的 rdb 文件名字改成刚才的 dump.rdb,至始至终,rdb文件只有一个。
-
-
自动触发
在redis配置文件中,设置一下,让redis 每隔多长时间/每产生多少次修改就触发。
默认配置是下面的三种的档位:1. 时间过了900秒,且期间至少有1 次key的变化时 2. 时间过了300秒,且期间至少有10次key的变化时 3. 时间过了60秒,且期间至少有10000次key的变化时
rdb 文件处理
- 保存:RDB ⽂件保存再 dir 配置指定的⽬录(默认 /var/lib/redis/)下,⽂件名通过 dbfilename 配置(默认 dump.rdb)指定。可以通过执行 config set dir {newDir} 和 config set dbfilename {newFilename} 运⾏期间动态执行,当下次运行时 RDB ⽂件会保存到新目录。
- 压缩:Redis 默认采用 LZF 算法对⽣成的 RDB 文件做压缩处理,压缩后的⽂件远远小于内存大小d,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
- 校验:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用Redis 提供的 redischeck-dump ⼯具检测 RDB 文件并获取对应的错误报告。
rdb 优缺点
- RDB 是⼀个紧凑压缩的⼆进制⽂件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全 量复制等场景。⽐如每 6 小数执行 bgsave 备份,并把 RDB ⽂件复制到远程机器或者⽂件系统中 (如 hdfs)用于灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的⽅式。
- RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运行都要执行 fork 创建⼦进程,属于重量级操作,频繁执行成本过高。
- RDB 文件使用特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有⻛险。
AOF => Append Only File 实时备份
AOF 类似于 mysql 的binlong,就会把用户的每个操作,都记录到文件中。
当redis重新启动的时候,就会读取这个aof文件中的内容,用来恢复数据。
当开启 AOF 的时候,rdb 文件就不生效了,启动的时候就不再读取rdb文件内容了,以AOF文件为主。
AOF是一个文本文件,默认一般是关闭状态,修改配置文件来开启 AOF 功能。
其中上面那行表示是否开启 AOF,下面那行表示的是生成的AOF文件名,它生成所存放的路径和 rdb 所在的目录是一样的。
AOF 工作流程
AOF 工作流程图如下:
步骤1) 所有的写⼊命令会追加到 aof_buf(缓冲区)中。
步骤2) AOF 缓冲区根据对应的策略向硬盘做同步操作。
步骤3) 随着 AOF ⽂件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
步骤4) 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。
AOF 缓冲区刷新策略
Redis 提供了多种 AOF 缓冲区同步⽂件策略,由参数 appendfsync 控制,不同值的含义。默认是 everysec级别。
- always::只要写入到缓存区就立即刷新,频率最高的,数据最可靠的,性能最低。
- everysec:每秒刷新一次缓冲区,频率较低一些,数据可靠性低一些,性能会提高。
- no:Redis不会主动将写入操作同步到磁盘,而是依赖操作系统来处理磁盘同步。
系统调用 write 和 fsync 说明:
- write 操作会触发延迟写(delayed write)机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性 能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区 ⻚空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
- fsync 针对单个⽂件操作,做强制硬盘同步,fsync 将阻塞直到数据写⼊到硬盘。
AOF 重写机制
随着命令不断写⼊ AOF,⽂件会越来越⼤,为了解决这个问题,Redis 引⼊ AOF 重写机制压缩⽂件体积。AOF ⽂件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF ⽂件。
为什么重写后的 AOF 可以变小?有如下原因:
- 进程内已过期的数据不再写⼊⽂件。
- 旧的 AOF 中的⽆效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本。
- 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b c。
较小的 AOF ⽂件一方面降低了硬盘空间占⽤,一方面可以提升启动 Redis 时数据恢复的速度。
AOF 重写过程一样也是分为手动触发和自动触发:
- 手动触发
手动触发:调用 bgrewriteaof 命令 - 自动触发
自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时机。
- auto-aof-rewrite-min-size:表示触发重写时 AOF 的最小文件大小,默认为 64MB。
- auto-aof-rewrite-percentage:代表当前 AOF 占用小相比较上次重写时增加的比例。
AOF 重写流程
-
执行 AOF 重写请求。
如果当前进程正在执行 AOF 重写,请求不执⾏。
如果当前进程正在执行 bgsave 操作,重写命令延迟到 bgsave 完成之后再执行。 -
父进程执行 fork 创建子进程。
-
重写
a. 父进程 fork 之后,继续响应其他命令。所有修改操作写⼊ AOF 缓冲区,并根据 appendfsync 策略同步到硬盘,保证旧 AOF ⽂件机制正确。
b. 子进程只有 fork 之前的所有内存信息,父进程中需要将 fork 之后这段时间的修改操作写⼊AOF 重写缓冲区(即aof_rewrite_buf)中。 -
子进程根据内存快照,将命令合并到新的 AOF ⽂件中。
-
子进程完成重写
a. 新⽂件写⼊后,子进程发送信号给父进程。
b. 父进程把 aof_rewrite_buf 缓冲区内临时保存的命令追加到新 AOF ⽂件中。
c. ⽤新 AOF ⽂件替换⽼ AOF ⽂件。
混合持久化
混合持久化指的是将Redis的数据同时持久化到磁盘的两种方式的结合使用。
混合持久化将这两种方式结合起来:
- Redis会定期执行RDB快照,将内存中的数据快照保存到磁盘上的RDB文件中。
- 同时,Redis会将写操作命令追加到AOF日志中,以保持AOF文件的实时更新。
这样,即使Redis在RDB快照之间崩溃,也可以通过AOF日志还原最后一次快照之后的数据。而且,RDB提供了一个全量备份,可以用于更长时间的数据恢复。
当配置文件中,开启这个选项时,AOF文件内容不是文本文件,而是二进制的。
持久化流程
当 Redis 启动时,会根据 RDB 和 AOF ⽂件的内容,进⾏数据恢复,具体流程如下:
总结
- Redis 提供了两种持久化⽅案:RDB 和 AOF。
- RDB 视为内存的快照,产⽣的内容更为紧凑,占用空间较⼩,恢复时速度更快。但产⽣ RDB 的开销较⼤,不适合进⾏实时持久化,⼀般⽤于冷备和主从复制。
- AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF ⽂件。
- RDB 和 AOF 都使⽤ fork 创建⼦进程,利⽤ Linux ⼦进程拥有⽗进程内存快照的特点进⾏持久化,尽可能不影响主进程继续处理后续命令。