• 第五章、Redis 得持久化


    一、总体介绍

    • 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
    • RDB 持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
    • AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。Redis 还能对 AOF 文件进行后台重写,使得 AOF 文件的体积不至于过大。

    二、RDB(Redis DataBase)

    2.1、RDB 简介

    RDB 是 Redis 用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。恢复时是将快照文件直接读到内存里。

    2.2、触发方式

    RDB 有两种触发方式,分别是自动触发和手动触发。

    • 1、自动触发:在 redis.conf 配置文件中的 SNAPSHOTTING 下
    • save:这里是用来配置触发 Redis 的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示 m 秒内数据集存在 n 次修改时,自动触发bgsave(这个命令下面会介绍,手动触发 RDB 持久化的命令)
      默认配置如下:
    save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存。
    save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存。
    save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存。

    如果你只是用 Redis 的缓存功能,不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。可以直接一个空字符串来实现停用:save ""

    • stop-writes-on-bgsave-error :默认值为 yes。当启用了 RDB 且最后一次后台保存数据失败,Redis 是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果 Redis 重启了,那么又可以重新开始接收数据了。
    • rdbcompression :默认值是 yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis 会采用 LZF 算法进行压缩。如果你不想消耗 CPU 来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
    • rdbchecksum :默认值是 yes。在存储快照后,我们还可以让 redis 使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
    • dbfilename :设置快照的文件名,默认是 dump.rdb
    • dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。

    总结:也就是说通过在配置文件中配置的 save 方式,当实际操作满足该配置形式时就会进行 RDB 持久化,将当前的内存快照保存在 dir 配置的目录中,文件名由配置的 dbfilename 决定。

    • 2、手动触发:手动触发 Redis 进行 RDB 持久化的命令有两种
      • save
      • bgsave
    • save:
      该命令会阻塞当前 Redis 服务器,执行 save 命令期间,Redis 不能处理其他命令,直到 RDB 过程完成为止。显然该命令对于内存比较大的实例会造成长时间阻塞,这是致命的缺陷,为了解决此问题,Redis 提供了第二种方式。
    • bgsave:
      执行该命令时,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是 Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

    总结:

    • 基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。
    • 执行执行 flushall 命令,也会产生 dump.rdb 文件,但里面是空的。
    2.3、恢复数据
    • 将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可,redis 就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。
    • 获取 redis 的安装目录可以使用 config get dir 命令。
    • 载入备份文件数据得标识是:
      RDB数据恢复
    2.4、停止 RDB 持久化
    • 有些情况下,我们只想利用 Redis 的缓存功能,并不像使用 Redis 的持久化功能,那么这时候我们最好停掉 RDB 持久化。可以通过上面讲的在配置文件 redis.conf 中,可以注释掉所有的 save 行来停用保存功能或者直接一个空字符串来实现停用:save ""
    • 也可以通过命令:redis-cli config set save " "
    2.5、RDB 优势和劣势
    • 1、、优势
    • 1.RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。
    • 2.生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
    • 3.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
    • 2、劣势
    • 1、RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,如果不采用压缩算法(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)
    • 2、RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个格式的 RDB 版本,存在老版本 Redis 服务无法兼容新版 RDB 格式的问题(版本不兼容)
    • 3、在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)。

    三、AOF(Append Only File)

    RDB 持久化存在一个缺点是一定时间内做一次备份,如果 redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)。对于数据完整性要求很严格的需求。
    这时候来看另一种持久化方式-AOF

    3.1、AOF 简介

    Redis 的持久化方式之一 RDB 是通过保存数据库中的键值对来记录数据库的状态。而另一种持久化方式 AOF 则是通过保存 Redis 服务器所执行的写命令来记录数据库状态。

    redis 写入数据
    redis 写入数据

    RDB 持久化方式就是将上图中 str1,str2,str3 这三个键值对保存到 RDB 文件中,而 AOF 持久化则是将执行的 set,sadd,lpush 三个命令保存到 AOF 文件中

    3.2、AOF 配置

    在 redis.conf 配置文件的 APPEND ONLY MODE 下

    • appendonly:默认值为 no,也就是说 redis 默认使用的是 rdb 方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。
    • appendfilename :aof 文件名,默认是"appendonly.aof"
    • appendfsync:aof 持久化策略的配置;
      • no 表示不执行 fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全;
      • always 表示每次写入都执行 fsync,以保证数据同步到磁盘,效率很低
      • everysec 表示每秒执行一次 fsync,可能会导致丢失这 1s 数据。通常选择 everysec ,兼顾安全性和效率。
    • no-appendfsync-on-rewrite:在 aof 重写或者写入 rdb 文件的时候,会执行大量 IO,此时对于 everysec 和 always 的 aof 模式来说,执行 fsync 会造成阻塞过长时间,no-appendfsync-on-rewrite 字段设置为默认设置为 no。如果对延迟要求很高的应用,这个字段可以设置为 yes,否则还是设置为 no,这样对持久化特性来说这是更安全的选择。 设置为 yes 表示 aof rewrite 期间对新写操作不 fsync,暂时存在内存中,等 rewrite 完成后再写入,默认为 no,建议 yes。Linux 的默认 fsync 策略是 30 秒。可能丢失 30 秒数据。默认值为 no。
    • auto-aof-rewrite-percentage:默认值为 100。aof 自动重写配置,当目前 aof 文件大小超过上一次重写的 aof 文件大小的百分之多少进行重写,即当 aof 文件增长到一定大小的时候,Redis 能够调用 bgrewriteaof 对日志文件进行重写。当前 AOF 文件大小是上次日志重写得到 AOF 文件大小的二倍(设置为100)时,自动启动新的日志重写过程。
    • auto-aof-rewrite-min-size:64mb。设置允许重写的最小 aof 文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写。
    • aof-load-truncated:aof 文件可能在尾部是不完整的,当 redis 启动的时候,aof 文件的数据被载入内存。重启可能发生在 redis 所在的主机操作系统宕机后,尤其在 ext4 文件系统没有加上 data=ordered 选项,出现这种现象 redis 宕机或者异常终止不会造成尾部不完整现象,可以选择让 redis 退出,或者导入尽可能多的数据。如果选择的是 yes,当截断的 aof 文件被导入的时候,会自动发布一个 log 给客户端然后 load。如果是 no,用户必须手动 redis-check-aof 修复 AOF 文件才可以。默认值为 yes
    3.3、开启 AOF
    • 将 redis.conf 的 appendonly 配置改为 yes 即可。
    • AOF 保存文件的位置和 RDB 保存文件的位置一样,都是通过 redis.conf 配置文件的 dir 配置。
    • 可以通过 config get dir 命令获取保存的路径。
    3.4、AOF 文件恢复

    重启 Redis 之后就会进行 AOF 文件的载入,异常修复命令:redis-check-aof --fix 进行修复

    3.5、AOF 重写
    • 1、AOF 重写后文件内容形式

    由于 AOF 持久化是 Redis 不断将写命令记录到 AOF 文件中,随着 Redis 不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题,Redis 新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令 bgrewriteaof 来重写。

    redis写入数据命令
    redis写入数据命令

    如上图:如果不进行 AOF 文件重写,那么 AOF 文件将保存四条 SADD 命令,如果使用 AOF 重写,那么 AOF 文件中将只会保留下面一条命令:sadd animals "dog" "tiger" "panda" "lion" "cat"

    也就是说 AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件

    • 2、AOF 重写触发

    AOF 文件重写触发机制:通过 redis.conf 配置文件中的 auto-aof-rewrite-percentage:默认值为 100,以及 auto-aof-rewrite-min-size:64mb 配置,也就是说默认Redis会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发。

    • 3、AOF 重写原理过程

    这里再提一下,我们知道 Redis 是单线程工作,如果 重写 AOF 需要比较长的时间,那么在重写 AOF 期间,Redis 将长时间无法处理其他的命令,这显然是不能忍受的。Redis为了克服这个问题,解决办法是将 AOF 重写程序放到子程序中进行,这样有两个好处:
      ①、子进程进行 AOF 重写期间,服务器进程(父进程)可以继续处理其他命令。
      ②、子进程带有父进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。
      使用子进程解决了上面的问题,但是新问题也产生了:因为子进程在进行 AOF 重写期间,服务器进程依然在处理其它命令,这新的命令有可能也对数据库进行了修改操作,使得当前数据库状态和重写后的 AOF 文件状态不一致。
      为了解决这个数据状态不一致的问题,Redis 服务器设置了一个 AOF 重写缓冲区,这个缓冲区是在创建子进程后开始使用,当 Redis 服务器执行一个写命令之后,就会将这个写命令也发送到 AOF 重写缓冲区。当子进程完成 AOF 重写之后,就会给父进程发送一个信号,父进程接收此信号后,就会调用函数将 AOF 重写缓冲区的内容都写到新的 AOF 文件中。
      这样将 AOF 重写对服务器造成的影响降到了最低。

    3.6、AOF 的优缺点
    • 1、优点:
        >①、AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。
        ②、AOF 文件使用 Redis 命令追加的形式来构造,因此,即使 Redis 只能向 AOF 文件写入命令的片断,使用 redis-check-aof 工具也很容易修正 AOF 文件。
        ③、AOF 文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。例如,如果我们不小心错用了 FLUSHALL 命令,在重写还没进行时,我们可以手工将最后的 FLUSHALL 命令去掉,然后再使用 AOF 来恢复数据。

    • 2、缺点:
        >①、对于具有相同数据的的 Redis,AOF 文件通常会比 RDF 文件体积更大。
        ②、虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但在 Redis 的负载较高时,RDB 比 AOF 具好更好的性能保证。
        ③、RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 方式更健壮。官方文档也指出,AOF 的确也存在一些 BUG,这些 BUG 在 RDB 没有存在。

    • 3、which one 那么对于 AOF 和 RDB 两种持久化方式,我们应该如何选择呢?

      >如果可以忍受一小段时间内数据的丢失,毫无疑问使用 RDB 是最好的,定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快,而且使用 RDB 还可以避免 AOF 一些隐藏的 bug;否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制,而是应该两种一起用,在这种情况下,当redis重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。Redis 后期官方可能都有将两种持久化方式整合为一种持久化模型。

    3.7、RDB-AOF混合持久化

    在 Redis4.0 之后又新增了 RDB-AOF 混合持久化方式。

    • aof-use-rdb-preamble:设置为 yes 表示开启,设置为 no 表示禁用。

    当开启混合持久化时,主进程先 fork 出子进程将现有内存副本全量以 RDB 方式写入 aof 文件中,然后将缓冲区中的增量命令以 AOF 方式写入 aof 文件中,写入完成后通知主进程更新相关信息,并将新的含有 RDB 和 AOF 两种格式的 aof 文件替换旧的 aof 文件。
    简单来说:混合持久化方式产生的文件一部分是 RDB 格式,一部分是 AOF 格式。
    这种方式优点我们很好理解,缺点就是不能兼容 Redis4.0 之前版本的备份文件了


    四、总结 (Which one)

    • 同时开启两种持久化方式

    在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,
    因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整.
    RDB 的数据不实时,同时使用两者时服务器重启也只会找 AOF 文件。那要不要只使用AOF呢?作者建议不要,因为 RDB 更适合用于备份数据库(AOF 在不断变化不好备份),
    快速重启,而且不会有 AOF 可能潜在的 bug,留着作为一个万一的手段。

    • 性能建议
    • 因为 RDB 文件只用作后备用途,建议只在 Slave 上持久化 RDB 文件,而且只要15分钟备份一次就够了,只保留 save 900 1 这条规则。
    • 如果 Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load 自己的 AOF 文件就可以了。代价一是带来了持续的 IO,二是 AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF 重写的基础大小默认值64M太小了,可以设到 5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
    • 如果不 Enable AOF ,仅靠 Master-Slave Replication 实现高可用性也可以。能省掉一大笔 IO 也减少了 rewrite 时带来的系统波动。代价是如果 Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB 文件,载入较新的那个。新浪微博就选用了这种架构。
  • 相关阅读:
    [辛酸历程]在Mac中使用Python获取屏幕截图
    一个简单的验证码识别教程
    JavaScript的函数作用域
    函数声明和函数表达式
    数组 方法和属性
    递归
    闭包
    浏览器解析JavaScript原理
    JavaScript的数据类型2
    利用canvas画一个动态时钟
  • 原文地址:https://www.cnblogs.com/pengguozhen/p/13397885.html
Copyright © 2020-2023  润新知