撩一撩Redis:它是怎么持久化的

udonnodu_chahua-001

Redis 提供了两种不同级别的持久化方式:

  • RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
  • AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数
    据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
    在这里插入图片描述
    但是如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
    你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据:因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.

RDB

RDB的优点

  • 1:适合大规模数据恢复
  • 2:对数据完整性和一致性要求不高
  • 3:RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
  • 4:RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.
  • 5:RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
  • 6:与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.

RDB的缺点

  • 1:如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
  • 2:RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.fork过程就是子进程拷贝父进程的内存页,但是Linux使用了写时复制技术

RDB保存的是dump.rdb文件。在关机SNAPSHOTTING(快照),恢复时直接将快照文件读到内存

在这里插入图片描述

在下面三种情况任意一种发生都会发生快照

  • 900s内发生了一次1个key的变化
  • 300s内发生了10个key的变化
  • 60s内发生了10000个key变化

在这里插入图片描述

是怎的牛皮,自己可以调节,皮卡丘都惊呆了

在这里插入图片描述

实验:

1:准备工作

为了更能够方便实验更快得到修改快照,改成

在这里插入图片描述

意味着120s如果发生了10个key的变化,那么就发生快照,当然你也可以改成更快

在这里插入图片描述

2:这时候加入几个KV

在这里插入图片描述

两分钟后生成了dump.rdb文件,看清楚时间的差别,21:20的时候因为插入了几个KV,然后120s后也就是两分钟后21:22生成了dump.rdb文件,然后我不插入任何东西,120s内没有任何变化,所以在21:25的时候dump.rdb文件的修改时间还是21.22.

在这里插入图片描述

在这里插入图片描述

3:flushALL后马上形成快照
可以看到,因为执行了flushALL命令,dump.rdb文件就被刷新了,修改时间变化了。

在这里插入图片描述

4:假如我们重新做一次上面的操作,在flushALL之前,备份dump.rdb

在这里插入图片描述

在flushALL之前,里面有了很多KV,那么然后flushall,这时候Redis是没有任何数据的,同时dump.rdb也被刷新成空的了,那么关闭redis,由于恢复时会加载RDB文件(这时候AOF持久化方式没有打开),所以恢复时应该什么数据都没有,但是当我们用备份的dump.rdb.bk替代dump.rdb时,再启动redis服务器

在这里插入图片描述

看这里,又有我加过的数据,这里第二次我没有加那么多,只是shuntdown的时候它会快照一次

在这里插入图片描述
在这里插入图片描述

如何触发RDB快照

配置文件中的save默认配置

  • 1:命令save或者时bgsave
    save:save只管保存,其他不管,一切阻塞
    bgsave:Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照恶的时间
  • 2:执行flushall命令,但是会没有数据了,没有意义,要么就shutdown,关闭服务器时会迅速快照一次
  • 3:shutdown瞬间完成持久化

怎么进行恢复

将备份文件dump.rdb移动到redis安装目录并启动服务
其实你的dump.rdb在不同地方,配置不同的bump.rdb你就可以得到不同的数据库了
RDB是整个内存压缩过的Snapshot,RDB的数据结构,可以配置符合的快照触发条件
禁用的话:save不用这个指令,要么就传“”的东西给他

快照

1:在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。
2:你也可以通过调用 SAVE或者 BGSAVE , 手动让 Redis 进行数据集保存操作。

比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动保存一次数据集:

工作方式

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

Redis 调用forks. 同时拥有父进程和子进程。对于Linux中的fork,它就是子进程复制父进程的内存页面
子进程将数据集写入到一个临时 RDB 文件中。
当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。因为写时复制是在修改的时候子进程才会复制父进程的某一个修改页面放到自己的真正进程空间,否则和父进程公用。

在这里插入图片描述在这里插入图片描述

怎么还有啊!!!!!!!!!!!

AOF

APPEND ONLY FILE

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录)
只许追加文件但不可以改写文件,redis启动之初就会读取该文件重新构建数据
换言之,重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

你可能会说,说了这么多,不就是我干什么都被它给偷偷记录了吗,干嘛这么啰嗦

在这里插入图片描述

AOF 优点

  • 1:使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
  • 2:AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.
  • 3:Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
  • 4:AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF 缺点

  • 1:对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 2:根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)

实验:

1:准备工作

在这里插入图片描述

默认appendonly为no,现在改成yes,将这个持久化功能打开,重新启动服务器

在这里插入图片描述

多了一个这样的文件
在这里插入图片描述
文件内容

在这里插入图片描述

2:执行flushall后,先来看啊可能RDB文件和AOF文件不共存的情况

因为RDB持久化功能没有关,会有dump.rdb文件
先删了它。将服务器重新启动
按AOF恢复机制,会按照上面的命令重新执行一遍来恢复数据,也就是结果什么都没有。

在这里插入图片描述

3:但是如果删掉最后一个flushall

在这里插入图片描述

4:删掉RDB快照文件,重新启动服务器

在这里插入图片描述

数据又有了,它的恢复就是将这些命令重新执行一遍。

5:再执行一次flushALL,然后我们再来关闭shutdown,这个时候RDB会产生快照,这时候RDB持久化的数据肯定是空的,这次不删,也就是这次RDB和AOF文件会共存。而不管按照哪种方式,都因为flushALL导致启动后没有任何数据

6:但是为了比对两种方式,同样将appendonly的flushall命令删掉

7:重新启动服务器

在这里插入图片描述

看数据,又恢复了。

可见,如果RDB和AOF同时存在,应该听AOF的
在这里插入图片描述
在这里插入图片描述

AOF文件故障

Redis-check-aof --fix appendonly.aof可以修复这个文件
Redis-benchmark

AOF的同步机制Appendfsync:

  • Always:没修改同步,同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好
  • Everysec:每秒同步,出厂默认推荐,异步操作,每秒记录,如果一秒内宕机,有数据丢失,但是比起RDB指定时间内的数据丢失,还是好了很多
  • NO:从不同步
    在这里插入图片描述

AOF的日志重写

因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。

在这里插入图片描述

你不担心是吧,那好举个例子
如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。

在这里插入图片描述

然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。

为了处理这种情况, Redis 支持一种有趣的特性:

可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。

执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 则可以自动触发 AOF 重写

AOF文件损坏

服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:

为现有的 AOF 文件创建一个备份。
使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复:
$ redis-check-aof –fix

可以使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。

AOF日志重写工作原理

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

Redis 执行 fork() ,现在同时拥有父进程和子进程。
子进程开始将新 AOF 文件的内容写入到临时文件。
对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。
在这里插入图片描述

确保数据由完整的备份. 磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。
Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。
这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。
• 创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
• 确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
• 至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。
容灾备份
Redis 的容灾备份基本上就是对数据进行备份, 并将这些备份传送到多个不同的外部数据中心。容灾备份可以在 Redis 运行并产生快照的主数据中心发生严重的问题时, 仍然让数据处于安全状态。
因为很多 Redis 用户都是创业者, 他们没有大把大把的钱可以浪费, 所以下面介绍的都是一些实用又便宜的容灾备份方法:
• Amazon S3 ,以及其他类似 S3 的服务,是一个构建灾难备份系统的好地方。 最简单的方法就是将你的每小时或者每日 RDB 备份加密并传送到 S3 。 对数据的加密可以通过 gpg -c 命令来完成(对称加密模式)。 记得把你的密码放到几个不同的、安全的地方去(比如你可以把密码复制给你组织里最重要的人物)。 同时使用多个储存服务来保存数据文件,可以提升数据的安全性。
• 传送快照可以使用 SCP 来完成(SSH 的组件)。 以下是简单并且安全的传送方法: 买一个离你的数据中心非常远的 VPS , 装上 SSH , 创建一个无口令的 SSH 客户端 key , 并将这个 key 添加到 VPS 的 authorized_keys 文件中, 这样就可以向这个 VPS 传送快照备份文件了。 为了达到最好的数据安全性,至少要从两个不同的提供商那里各购买一个 VPS 来进行数据容灾备份。
• 需要注意的是, 这类容灾系统如果没有小心地进行处理的话, 是很容易失效的。最低限度下, 你应该在文件传送完毕之后, 检查所传送备份文件的体积和原始快照文件的体积是否相同。 如果你使用的是 VPS , 那么还可以通过比对文件的 SHA1 校验和来确认文件是否传送完整。
另外, 你还需要一个独立的警报系统, 让它在负责传送备份文件的传送器(transfer)失灵时通知你。

在这里插入图片描述

发布了66 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43272605/article/details/104324433
今日推荐