详细分析Redis的持久化操作——RDB与AOF

栏目: IT技术 · 发布时间: 4年前

内容简介:由于疫情的原因,学校还没有开学,这也就让我有了很多的时间。趁着时间比较多,我终于可以开始学习那些之前一直想学的技术了。最近这几天开始学习学习过

一、前言

  由于疫情的原因,学校还没有开学,这也就让我有了很多的时间。趁着时间比较多,我终于可以开始学习那些之前一直想学的技术了。最近这几天开始学习 Redis ,买了本 《Redis实战》 ,看到了第四章,前三章都是讲一些 Redis 的基本使用以及命令,第四章才开始涉及到原理相关的内容。 《Redis实战》 的第四章涉及到了 Redis 的持久化、主从复制以及事务等内容,我个人认为这些应该属于 Redis 中比较重要的部分,也是面试的常考内容。这篇博客就来记录一下 Redis 的持久化机制。

二、正文

2.1 为什么需要持久化

  学习过 Redis 的应该都知道, RedisMySQL 等关系型数据库不同,它的数据不是存储在硬盘中,而是存放在内存,所以 Redis 的速度非常快。而这也就会造成一个问题: 电脑如果宕机,或者由于某些原因需要重启,此时内存中的数据就会丢失Redis 既然把数据存放在内存,自然也就无法避免这个问题。所以,为了在电脑重启后,能够恢复原来的数据, Redis 就需要提供持久化的机制,将 Redis 数据库存储在内存中的数据,在磁盘中进行备份,也就是持久化。而当 Redis 重启后,去磁盘中将持久化的数据重新读取到内存,便能避免数据的丢失。

2.2 Redis 的持久化方式

   Redis 提供了两种持久化的方式,分别是:

  • 快照持久化;
  • AOF持久化;

  下面我就来详细地介绍这两种持久化的方式。

2.3 快照持久化(RDB)

  快照持久化也就做 RDB 持久化。快照持久化的实现方式简单来说就是: Redis将当前内存中存储的数据写入到一个文件中,将这个文件作为Redis当前的一个快照,保存在磁盘中。当Redis重启时,将这个快照文件中存储的内容加载进内存,即可恢复Redis之前的状态 。默认情况下, Redis 将快照保存在一个叫做 dump.rdb 的文件中,我们也可以在配置文件中,通过 dbfilename 选项来设置快照文件的名称;默认情况下快照文件就保存在 Redis 的安装目录下,我们可以在配置文件中,通过 dir 选项来配置快照文件的存储路径(其实也是AOF的路径)。

2.4 执行快照持久化的方式

  执行快照持久化有两种方式:

2.4.1 使用配置文件

  第一种方式就是在 Redis 的配置文件中( windows 下这个文件叫 redis.windows-service.conf )加上 save 配置项,比如像下面这样:

save 60 100:在配置文件中加上这一条的意思是,Redis会每60秒检查一次,若在这60秒中,Redis数据库执行了100次以上的写操作,那Redis就会生成一个快照文件,替换原来的快照文件;若不满足这个条件,则不生成快照,继续等待60秒;

  我们可以根据自己的需求,调整每次等待的时间,以及对写操作次数的要求。而且,我们可以在配置文件中,添加多个 save 选项,比如一个 save 60 100 ,一个 save 5 10 ,则 Redis5 秒以及每 100 秒都会判断一次。需要注意的是,我们不应该让生成快照太过频繁,因为这是一个比较消耗资源的工作,会降低 Redis 的响应速度。

2.4.2 使用指令

  执行快照持久化的第二个方法就是使用 Redis 指令, Redis 提供了两个指令来请求服务器进行快照持久化,这两个指令分别是 SAVEBGSAVE

(a)BGSAVE指令

   BGSAVE 的执行流程如下:

  1. Redis 调用系统的 fork() ,创建出一个子进程;
  2. 子进程将当前 Redis 中的数据,写入到一个临时文件中;同时父进程不受影响,继续执行客户端的请求;
  3. 子进程将所有的数据写入到了临时文件后,于是使用这个文件替换原来的快照文件(默认是 dump.rdb );

  值得一提的是,通过配置文件执行快照持久化的方式,实际上就是 Redis 在判断满足条件时,调用 BGSAVE 指令来实现的。

(b)SAVE指令

   SAVE 指令生成快照的方式与 BGSAVE 不同, Redis 执行 SAVE 指令时,不会创建一个子进程,异步的生成快照文件,而是直接使用 Redis 当前进程。执行 SAVE 指令在创建快照的过程中, Redis 服务器会阻塞所有的 Redis 客户端,直到快照生成完毕,并更新到磁盘之后,才会继续执行客户端发来的增删改查的指令。

  当然,这个指令一般很少使用,因为会阻塞客户端,造成停顿。但是实际上,这个指令的执行效率一般比 BGSAVE 更高,因为不需要创建子进程,而且在这个过程中,其他操作被阻塞, Redis 服务器一心一意地生成快照。在 《Redis实战》 中,作者提到了使用 SAVE 指令的一个案例:

  当前服务器的Redis数据库中保存了大量数据,使用BGSAVE指令生成快照会非常的耗时 ,而且由于所剩内存不多,甚至无法创建子进程,于是作者编写了一个 shell 脚本,这个脚本的内容就是让服务器每天凌晨3点,执行SAVE命令,生成快照,这样就不需要创建子进程,而且由于是凌晨三点,用户较少,SAVE的阻塞机制也不会有太大的影响。

2.5 快照持久化的优缺点

(1)优点:

  1. 快照的 rdb 文件是一个经过压缩的紧凑文件,它保存了 Redis 在某个时间点上的数据集,这个文件非常适合用来备份。我们可以存储 Redis 服务器在不同时间点上的 rbd 文件,比如说一小时存储一次,一个月存储一次,这样就可以在遇到问题或有特殊需求时,将 Redis 恢复到某一个时间点;

  2. RDB非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的服务器上;

  3. RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作,所以不会影响父进程处理客户端的请求;

  4. RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

(2)缺点:

5
BGSAVE

2.6 AOF持久化

   AOF 全称为只追加文件(append-only file),它的实现方式简单来说就是: AOF持久化机制,会将Redis执行的所有写指令,追加到到AOF的末尾,当服务器发生宕机,或者由于某些原因需要重启时,在重启后,读取AOF文件,重新执行其中记录的写操作,以此达到恢复数据的目的。

   AOF 持久化机制默认是关闭的,我们可以在配置文件中,配置 appendonly yes 来开启。同时我们也可以通过配置 appendfsync ,控制写操作追加到 AOF 中的频率,它有如下三种选项:

  • alwaysRedis 每次执行写指令,都会立即将这个写指令同步到 AOF 中;使用这个选项时, Redis 发生异常,则最多只会丢失一次写操作(也就是在同步的过程中宕机,没同步完成),但是这也会导致 Redis 的响应速度变慢,因为此选项会造成频繁的 IO 操作;
  • everysec(默认) :每秒同步一次,使用此选项,速度足够快,而且发生宕机时也只会丢失 1s 内的写操作;
  • no :让操作系统来决定什么时候进行同步,这个选项速度更快,但是不安全,宕机时丢失数据的多少是不确定的;

  推荐(也是默认),使用第二个选项 everysec ,每秒进行一次同步,因为这个选项兼顾了速度与安全性,而第一个选项太慢,第三个选项无法保证安全性。

2.7 AOF的重写机制

   AOF 持久化的执行机制就是,不断地将写指令追加到 AOF 的末尾,这样就会导致 AOF 越来越大。为了解决 AOF 越来越大的问题, Redis 实现了一种优化机制—— AOF重写 。当 Redis 检查到 AOF 已经很大时,就会触发重写机制,优化其中的内容,将它优化为能够得到相同结果的最小的指令集合。

  比如说,我们在 Redis 中使用 SET 指令创建了一个 String 类型的数据,最后使用 DEL 指令将它删除了。如果开启了 AOF 持久化,那么则 AOF 中,将会记录这条 SETDEL 指令。但是,在执行重写的过程中,这个String最后被删除了,那么 Redis 就不会将这两条指令加入新的 AOF 中,因为已经被删除的数据,不需要恢复。再比如说,我们使用 Redis 维护了一个计数器 cnt ,我们使用了 100INCR 指令,让 cnt 自增到了 100 ,而 Redis 重写 AOF 时,可以将这 100incr 修改为一条 SET 指令,直接将 cnt 设置为 100 ,而不是保留 100INCR

  经过了重写后, AOF 的大小将会大大减小,而且也去除了不必要的操作,优化了恢复数据的指令集。而 AOF 重写的过程与生成一个快照文件类似,如下:

  1. Redis 执行 fock() ,创建一个子进程用来执行后续操作,而父进程继续处理发送到 Redis 的执行请求;
  2. 子进程重写旧 AOF 文件,将重写后的内容写入到一个临时文件;
  3. 如果这个过程中,有新的写指令到达,那么 Redis 会将这些写指令依旧追加到旧的 AOF 中,同时也会将这些指令加入到内存的一个缓冲区中。这样做的目的是,如果服务器发生异常, AOF 重写失败,这些指令依然能够保存在旧 AOF ,不会丢失;
  4. 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有写指令追加到新 AOF 文件的末尾;
  5. 使用新 AOF 替换旧的 AOF ,这之后执行的所有写指令都将追加到新的 AOF 中;

2.8 AOF的错误处理

   AOF 文件是有可能发生错误的,比如上面提过,如果当前 Redis 正在向 AOF 中追加一个写指令,但是此时服务器宕机,那么这个存入 AOF 中的这个写指令就是不完整的,也就是 AOF 出现了错误。如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。

  那么,当 AOF 发生了错误,应该如何处理呢?我们可以使用如下命令:

redis-check-aof --fix:redis-check-aof用来检测AOF是否存在错误,如果指定了--fix参数,那么Redis在检测到AOF的错误后,会对AOF进行修复。

   redis-check-aof 修复 AOF 的方式非常简单: 扫描AOF文件,寻找其中不正确或不完整的指令,当发现第一个出错的指令后,就将这个指令以及这之后的所有指令删除 。为什么需要删除出错指令之后的所有指令呢?因为当一条指令出错,很有可能影响到后续的操作,导致后续操作的都是脏数据,而 Redis 无法检测哪些指令是受到影响的,所以为了保险起见,就将后续指令全部删除。不过不用担心,因为在大多数情况下,出错的都是 AOF 最末尾的指令。

2.9 AOF的优缺点

(1)优点:

  1. 使用 AOF 持久化会让 Redis 变得非常耐久,意思就是说,当发生异常导致需要重启服务器时,只会丢失很少的一部分数据,因为 AOF 持久化默认 1s 同步一次,也就是说, Redis 最多只会丢失 1s 中所做的修改;
  2. Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。
  3. AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析( parse )也很轻松。
  4. AOF 文件是一个只进行追加操作的日志文件( append only log ), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

(2)缺点:

  1. 对于相同的数据集来说, AOF 文件的体积通常要大于快照 RDB 文件的体积大,因为 RDB 只存储数据,而 AOF 中的写指令,既包含指令,也包含数据;
  2. 如果 AOF 体积太大,那么恢复数据将要花费较长的时间,因为需要重做指令;

2.10 选择快照还是AOF?

  说到这里,可能就有人要问了,在实际生产中,我们应该使用快照持久化还是 AOF 持久化呢?

1、如果希望自己的数据库有很高的安全性,则应该两者同时使用, AOF 用作精确记录,而快照用作数据备份,前面也说过,快照非常适合用来做数据备份,因为它只存储数据库中的数据,并且经过了压缩,而且它恢复 Redis 数据的速度一般要快于 AOF

2、如果可以容忍一段时间内的数据丢失,则可以考虑只使用快照持久化,减小服务器的开销;

  值得一提的是,如果我们同时开启了快照持久化和 AOF 持久化, Redis 在重启后,会优先选择 AOF 来恢复数据,因为一般情况下, AOF 能够更加完整地恢复数据。

三、总结

  快照持久化和 AOF 持久化各有优劣,在实际生产环境中,我们一般是两者配合使用,快照持久化消耗较低,而且适合用于备份,但是会丢失一段时间的数据; AOF 持久化更加地耐久,可靠性更高,但是开销可能相对较高。以上就对 Redis 的持久化机制做了一个比较详细的介绍,相信看完只后,对 Redis 会有一个更加深入的理解。

四、参考


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

敏捷软件开发

敏捷软件开发

Robert C.Martin,、Micah Martin / 邓辉、孙鸣 / 人民邮电出版社 / 2010-12 / 79.00元

要想成为一名优秀的软件开发人员,需要熟练应用编程语言和开发工具,更重要的是能够领悟优美代码背后的原则和前人总结的经验——这正是本书的主题。本书凝聚了世界级软件开发大师Robert C. Martin数十年软件开发和培训经验,Java版曾荣获计算机图书最高荣誉——Jolt大奖,是广受推崇的经典著作,自出版以来一直畅销不衰。 不要被书名误导了,本书不是那种以开发过程为主题的敏捷软件开发类图书。在......一起来看看 《敏捷软件开发》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具