持久化
前言:简单来说就是,redis内存和硬盘两边都存。插入数据时,内存硬盘都写入,查询数据时,直接从内存读取,硬盘的数据只是redis在重新启动的时候来恢复内存中的数据的
代价就是消耗更多空间。
RDB:Redis DataBase 定期备份
RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和 自动触发。
save手动触发
阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例造成长时间 阻塞,基本不采用。
bgsave手动触发
此处为并发编程的场景,redis使用的是多进程的方式来完成的并发编程,来完成bgsave的实现
Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,不会影响Redis服务器处理其他客户端的请求和命令,子进程处理完成后自动 结束。阻塞只发生在 fork 阶段,一般时间很短。

-
执行 bgsave 命令,Redis 父进程判断当前进是否存在其他正在执行的子进程,如 RDB/AOF 子进 程,如果存在 bgsave 命令直接返回。
-
父进程执行 fork 创建子进程,fork 过程中父进程会阻塞,通过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一次 fork 操作的耗时,单位为微秒。
-
父进程 fork 完成后,bgsave 命令返回 "Background saving started" 信息并不再阻塞父进程,可 以继续响应其他命令。
-
子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执 行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选 项。
-
进程发送信号给父进程表示完成,父进程更新统计信息。
RDB 文件的处理
保存:RDB 文件保存再 dir 配置指定的目录(默认 /var/lib/redis/)下,文件名通过 dbfilename 配置(默认 dump.rdb)指定。可以通过执行 config set dir {newDir} 和 config set dbfilename {newFilename} 运行期间动态执行,当下次运行时 RDB 文件会保存到新目录。
压缩:Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大 小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
redis的触发时机:
1、手动(save,bgsave),注意,直接使用save是不会触发子进程&文件替换逻辑的
,
2、自动(配置文件中,如下图)
修改后需要重启redis服务器才能生效

注意:虽然压缩 RDB 会消耗 CPU,但可以大幅降低文件的体积,方便保存到硬盘或通过网络发送到 从节点,因此建议开启。
校验:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redischeck-dump 工具检测 RDB 文件并获取对应的错误报告。

RDB优缺点:
• RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全 量复制等场景。比如每 6 小时执行 bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中 (如 hdfs)用于灾备。

• Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
• RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运行都要执行 fork 创建子进 程,属于重量级操作,频繁执行成本过高。通过AOF解决以下问题

• RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风 险。
另外:
假如把rdb文件损坏,比如破坏里面的二进制数据,再kill后会发现服务器无法启动,发生这种服务器挂掉的情况,可以查看 /var/log/redis/下的redis-server.log
redis提供了rdb文件的检查工具:redis-check-rdb ,可以先通过该工具,检查rdb文件格式是否符合要求

AOF:Append Only File 实时备份
AOF(Append Only File)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是Redis 持久化的主流方式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能非常有帮助。注意AOF存储的是文本格式,这点与RDB的二进制存储不同
AOF类似于MySQL的binlog,他会把用户的每个操作都记录到文件中,redis重新启动的时候就会读取aof文件的内容。注意开启aof的时候rdb就不生效了
使用AOF
开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF 文件名通过 appendfilename 配置(默认是 appendonly.aof)设置。修改后重新启动redis生效

AOF 的工作流程操作:命令写入(append)、文件同步(sync)、文件重写 (rewrite)、重启加载(load)

-
所有的写入命令会追加到 aof_buf(缓冲区)中。
-
AOF 缓冲区根据对应的策略向硬盘做同步操作。
-
随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
-
当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。
1. 所有的写入命令会追加到 aof_buf(缓冲区)中。
为什么需要 aof_buf 这个缓冲区?Redis 使用单线程响应命令,如果每次写 AOF 文件都直 接同步硬盘,性能从内存的读写变成 IO 读写,必然会下降。先写入缓冲区可以有效减少 IO 次数。
对于一些极端情况,比如将数据写入缓冲区的过程中,此时数据仍在内存里,如果此时金钟挂掉了此时数据就会丢失,但是仍有一些方法来规避该风险:**Redis 提供多种缓冲区同步策略,让用户根据自己的需求做出合理的平衡。**比如设置的刷新频率越高,数据的可靠性就越高,但同时对性能的影响也会更高,这其实是一种取舍策略。类似于mysql的事务,隔离级别等等
2. AOF 缓冲区根据对应的策略向硬盘做同步操作。
Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制

everysec:每秒执行一次。这也是默认模式。

3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
随着命令不断写入 AOF,文件会越来越大,将会影响到AOF的下次启动时间,为了解决这个问题,Redis 引入 AOF 重写机制压缩文 件体积 。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF 文件。
AOF重写机制:write(核心,redis启动时只关注最终结果,该机制就是确保最终的结果达到最佳)
• 进程内已超时的数据不再写入文件。
• 旧的 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 重写,请求不执行。如果当前进程正在执行 bgsave 操作,重写命令 延迟到 bgsave 完成之后再执行。
-
父进程执行 fork 创建子进程。
-
重写
a. 主进程 fork 之后,继续响应其他命令。所有修改操作写入 AOF 缓冲区并根据 appendfsync 策 略同步到硬盘,保证旧 AOF 文件机制正确。
b. 子进程只有 fork 之前的所有内存信息,父进程中需要将 fork 之后这段时间的修改操作写入 AOF 重写缓冲区中。
-
子进程根据内存快照,将命令合并到新的 AOF 文件中。
-
子进程完成重写
a. 新文件写入后,子进程发送信号给父进程。
b. 父进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF 文件中。
c. 用新 AOF 文件替换老 AOF 文件。
fork()创建子进程后,父进程 同时进行的两项核心工作 ,以及子进程 进行的一项工作。这三条并行的主线是:
-
**主线一(父进程 - 持续服务):** 父进程继续正常接收并处理客户端的新请求。
-
主线二(父进程 - 记录增量): 父进程将这些新请求产生的 AOF 日志,写入一个专用的 AOF 重写缓冲区。
-
主线三(子进程 - 生成快照): 子进程基于
fork()时继承的内存数据快照,将其转换成 AOF 格式,并写入一个全新的 AOF 文件。


父进程fork之后,就已经让子进程写心得aof文件了,且随着时间推移,子进程写完新的aof文件后将会替换掉旧的aof文件,是否意味着父进程写的这个旧的即将被销毁的aof文件毫无意义?
为非如此,因为需要考虑极端情况,假设在重写过程中途服务器挂了,子进程的数据就会丢失且新的aof文件不完整,所以父进程坚持写旧的aof文件,就是确保了服务器中途挂掉后重启时的数据完整性。
混合持久化

redis上同时存在aof和rdb快照的时候,以aof为主

总结:
-
Redis 提供了两种持久化方案:RDB 和 AOF。
-
RDB 视为内存的快照,产生的内容更为紧凑,占用空间较小,恢复时速度更快。但产生 RDB 的开 销较大,不适合进行实时持久化,一般用于冷备和主从复制。
-
AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF 文件。
-
RDB 和 AOF 都使用 fork 创建子进程,利用 Linux 子进程拥有父进程内存快照的特点进行持久化, 尽可能不影响主进程继续处理后续命令。


