redis系列(五)持久化

来源:互联网 发布:淘宝网品牌旗舰店 编辑:程序博客网 时间:2024/05/16 01:13
  • RDB持久化
  • AOF持久化

          redis 是一个键值对的数据库服务器,在它里面有任意多个非空数据库以及其下的键值对,我们将这两者合称为数据库状态。redis 是一种内存数据库,所有的数据主状态都存储在内存中,这就需要考虑一种情况,如果服务器崩掉了,那么存储在内存中的 redis 的数据库状态也就消失了。为了解决这一问题 redis 提供了两种持久化方法,即 RDB 持久化和 AOF 持久化。

    1.  RDB 持久化

  • RDB 文件的创建和载入

           redis 创建 RDB 文件的工作实际上是由 rdb.c/rdbSave 函数来实现的。 下面 rdbSave 函数的定义。

         

         

         

          其实我们在rdb.c文件的最后还会发现两个函数 saveCommand 和 bgsaveCommand

         

          我们可以看到,这两个函数是以 command (命令)结尾的,其实 redis 创建 RDB 文件的命令就是 SAVE 和 BGSAVE 。

          SAVE 命令

          save 命令会阻塞 redis 服务器进程,知道 RDB 文件创建完成为止,在服务器进程阻塞期间,服务器不能处理任何命令请求

          BGSAVE 命令

          bgsave 命令和 save 命令不同,它不会去阻塞 redis 服务器的进程,而是会创建一个新的子进程,让这个子进程去创建 RDB 文件,而 redis 的服务器进程继接受命令。

          RDN 文件的载入

          以上是 RDB 文件的创建,是将数据库状态持久化到硬盘中的过程。那么,redis 又是如何将硬盘中的数据返回到数据库中的呢?就是通过载入的方式,和创建 RDB 文件不同,redis 中并没有载入的命令,RDB 文件的载入工作是在服务器启动的时候自动执行的,只要 redis 服务器在启动的时候检测到了 RDB 文件,就会自动载入 RDB 文件。

          注意:这里有一点要提前说明一下,由于 redis 中 AOF 文件的更新频率通常要比 RDB 文件的更新频率要高,所以,如果你开启的 AOF 持久化功能,那么服务器会优先选择 AOF 文件来还原数据库状态。

          载入 RDB 文件的工作是由 rdb.c/rdbLoad 函数实现的

         

         

         

  • RDB 文件的内容的保存

           由于 bgSave 命令不会阻塞 redis 服务器的进程,所以,redis 允许用户自己设置服务器的 save  选项来设置保存条件,只要满足其中的一个条件,服务器就会自动执行bgSave 命令。

           save 的配置在之前的内容中已经介绍过了,这里就不做多的说明了,我们直接用 redis 默认的设置就可以。

           save   900   1

           save   300   10

           save   60      1000

          

           ......

          

           saveparam 属性是一个数组,数组中的每个元素都是一个 saveparam 结构,每个 saveparam 结构都保存了一个 save 选项设置的保存条件。

          

           seconds 秒数

           changes 修改次数

  • RDB 文件的内容

           说了这么多 RDB 文件,那么 RDB 文件到底是什么样子呢?

           RDB 文件的结构

          

           REDIS 部分:RDB 文件的最开头部分,表明这是一个 RDB 文件,这个部分的长度为 5 字节,保存着 “REDIS” 

           db_version :其值是一个字符串表示的整数,记录了 RDB 文件的版本号,其长度为 4 个字节

           databases: 它包含了零个或者任意多个数据库,以及各个数据库中的键值对数据。

           EFO:其标志着 RDB 文件正文的结束。

           check_sum:是一个校验和,这个校验和是程序根据 REDIS、db_version、database、EFO 计算出来的,服务器在载入 RDB 文件的时候,会将载入数据所计算出来的值和check_sum 进行比较,以此来判断 RDB 文件是否损坏或者出错的情况。

           databases  部分

            一个 RDB 文件中的 database 部分可以保存任意多个非空数据库。每个非空数据库在 RDB 文件中都可以保存为 SELECTDB、db_number、key_value_pairs 三部分

           

           SELECTDB:标志着这是一个数据库的开始,其字节长度为1。

           db_number:表示数据库的号码,其字节长度为 1, 2 或者 5,当程序读到这的之后,服务器会调用 SELECT 命令,切换数据库,使得之后读到的数据可以导入到正确的数据库中。

           key_value_pairs:保存了数据库中所有的所有键值对数据。

           key_value_pairs 部分

           RDB 文件中每一个 key_value_pairs 部分一个或者多个键值对,不带过期键的键值对在 RDB 文件中由 TYPE、key、value 三部分组成,Type 记录了 value 的类型,长度为一字节(具体的可以自己查一下),key 和 value 就不用多说了。如果这个键值对带有过期时间的话,除了有上面的三部分之外,还有 EXPIRETIME_MS 和 ms 这两个部分。EXPIRETIME_MS 是一个常量,程序读到这里,就会知道接下来的值就是一个以毫秒为单位的过期时间,其长度为一字节。ms 很明显就是这个键值对的过期时间,是一个八字节的符号整数。

           不带过期时间

          

           带过期时间

          

    2.  AOF 持久

         redis 除了 RDB 持久化之外,还有 AOF 持久化,与 RDB 持久化通过保存数据库键值对来记录数据库状态不同,AOF 是通过保存 redis 服务器的所有写命令来记录数据库状态的。

  • AOF 实现持久化

          要实现 AOF 持久化,首先需要开发 AOF 功能,只需要在配置文件中将 no 改成 yes 即可。

         

          命令追加

          当 AOF 持久化功能开启后,服务器在执行完一个写命令之后,会以协议格式将执行的写命令追加到服务器状态的 aog_buf 缓冲区的末尾:

         

         

          我们来通过一个实际的例子 进行说明:

          当我们执行 SET NAME WULI,那么服务器会在执行完这个命令之后,会将一下协议内容追加到 aof_buf 缓冲区的末尾:

          *3\r\n$3\r\nSET\r\n$4\r\nNAME\r\n$4\r\nWULI\r\n

          可能你会看不懂这样的协议,其实很简单,* 代表一条新的命令的开始,3 代表这条命令有三个字符,\r\n 代表换行回车,$4 代表当前这个字符的长度

          它在 aof 文件中是如下的样子

         

          AOF 文件的写入和同步

          redis 的服务器进程就是一个时间循环 ,这个循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复。

          服务器在处理文件事件的时候可能会执行写命令,使得一些内容被追加到aof_buf 缓冲区里面,所以服务器在每次结束一个事件循环之前,它都会调用flushAppendOnlyFile 函数,考虑是否需要将aof_buf 缓冲区中的内容写到 AOF 文件中。

          

          

          

          

          

  • AOF 文件的载入和还原

          现在我们已经知道,AOF 文件中保存的都是一条条的命令,所以,服务器只要读取并重新执行一遍 AOF 文件中的命令,就可以恢复服务器的数据库状态。其步骤如下:

  1. 首先,由于 redis 命令只能在客户端上下文中执行,而载入 AOF 文件时所使用的命令来源于 AOF 文件,而不是客户端,所以,需要先创建一个没有网络连接的伪客户端来执行 AOF 文件中的命令。
  2. 我们上面也看到 AOF 文件中的内容格式了,是没办法直接执行的,所以,需要先进行分析,解析成程序可以执行的命令格式。
  3. 使用伪客户端来执行命令
  4. 一直执行2 和 3 步骤,知道全部执行完。

        

  • AOF 重写

          我们想一个问题,服务器如果一直在同一个 AOF 文件中追加命令,那么这个文件一定会非常大的,这样会对 redis 服务器和整个主机有影响。为了解决这一问题,redis 提供了 AOF 重写功能,redis 服务器会创建一个新的 AOF 文件来代替原来的旧的 AOF 文件,两者的数据库状态是相同的,但是新的 AOF 文件不会有任何浪费空间的冗余命令。

          重写的原理:这里的重写不是对原来的 AOF 文件进行读取、分析,重新写入,而是直接读取当前的数据库状态,直接将最新的数据库状态写到新的 AOF 文件。

          AOF 重写是在aof.c/rewriteAppendOnlyFile 函数实现的,如下

         

         

                 

          我们在来想一个问题,即使是这样实现的重写,依然要进行大量的写入,而我们也知道 redis 对于命令的请求是单线程的(和memchache不同),所以,如果服务器直接调用这个函数的话,服务器会很长时间处于阻塞状态,服务器将无法再接受其他的命令。所以,redis 服务决定将 AOF 重写程序放到后台进行。这样又会带来另一个问题,假如在重写的时候,又有新的命令执行的话,会让 AOF 文件中记录的数据库状态和服务器中的数据库状态不同步。所以,redis 会在这个子进程启动的时候开辟一个 AOF 缓冲区, 当程序执行完重写之后,会将 AOF 缓冲区内的数据写到新的 AOF 文件中去。

         源码如下:

        

0 0
原创粉丝点击