Redis RDB及AOF持久化

2019-03-29  本文已影响0人  心中翼

1、Question1:什么叫持久化?(What)

持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。

2、Question2:Redis不就是数据库吗,为什么要持久化?(Why)

Redis确实是一个数据库,但它是基于内存的数据库。
类似于你用代码写了个变量String a = 123 这个a在程序运行时存入内存中,等程序停止,你还能找到a吗?显然是不行的。
所以Redis需要有一个持久化的功能,将它存储的数据记到硬盘上。

3、Question3:Redis如何进行持久化?(How)

Redis为了能把数据写到硬盘中,它提供了两种持久化功能,分别是RDB (redis database)、AOF (append only file)。下面是对两种方法的说明。

3.1、RDB持久化是什么?

RDB持久化是将Redis数据库中的数据快照进行备份,将内存中的数据库状态保存至磁盘,避免数据丢失。


image.png
RDB

3.2、RDB持久化怎么做?

RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行。

1、手动执行

手动执行有两个命令可以选择,save bgsave
save 命令会阻塞Redis服务器进程,直到RDB文件创建完毕。阻塞期间,服务器不能处理任何命令。这个命令估计没人敢用。

save命令

bgsave 命令是非阻塞的,它会创建一个子进程,由子进程负责创建RDB文件,服务器进程继续处理命令请求,这个命令看着比较靠谱。

bgsave

很明显,bgsave命令执行后,客户端会收到"Background saving started",并且可以执行命令。bgsave命令执行期间,客户端发送的savebgsave命令会被服务器拒绝。
用伪代码表示:

def SAVE():
      # 创建RDB文件
       rdbSave()

def BGSAVE():
      # 创建子进程
     pid = fork() ;
     if pid ==  0 :
         # 子进程负责创建RDB文件
         rdbSave()
         # 完成后向父进程发送信号
         signal_parent()
     elif pid > 0:
         # 父进程继续处理命令请求,并通过轮询等待子进程的信号
         handle_request_and_wait_signal() 
     else:
         # 处理出错情况
          handle_fork_error()
2、服务器配置

Redis允许用户通过设置服务器配置的save选项(这个不是指save命令),让服务器每隔一段时间自动执行一次bgsave命令。 save选项可以被配置多个,只要有一个条件满足,就会执行bgsave命令。配置文件为redis.conf。在文件中可以找到以下配置:

save 900 1
save 300 10
save 60 10000

该配置表示只要满足以下三个条件中的任意一个,bgsave命令就会被执行:

3、RDB文件如何载入?

将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可,redis在启动时就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。查看启动日志。


log
4、RDB持久化的优势与劣势

优势:

劣势:

5、RDB持久化的原理

Redis有个服务器状态结构:

struct redisService{
     //1、记录保存save条件的数组
     struct saveparam *saveparams;
     //2、修改计数器
     long long dirty;
     //3、上一次执行保存的时间
     time_t lastsave;
}
struct saveparam{
     //秒数
     time_t seconds;
     //修改数
     int changes;
};

saveparams属性是一个数组,数组中的每个元素都是一个saveparam结构,当设置save选项为以下条件时:

save 900 1
save 300 10
save 60 10000

saveparams数组是如下结构:

saveparams
dirty计数器记录距离上次执行save命令或者bgsave命令后,服务器进行了多少次修改(写入、删除、更新等)
lastsave属性是一个UNIX时间戳,记录上一次成功执行save或者bgsave 命令的时间。
通过这两个属性,服务器没执行一次修改,就将dirty计数器加一。成功执行save或者bgsave命令后,将执行时间记录到lastsave属性中。
服务器有个周期性函数serverCron默认每隔100毫秒就会执行一次。它有一项工作就是检查save选项所保存的条件是否满足,满足的话,就执行一次bgsave命令。
伪代码表示:
def serverCron():
      #....
      #遍历所有保存条件
      for saveparam in server.saveparams:
            #计算距离上次保存操作有多少秒
            save_interval = unixtime_now() - server.lastsave ;
            # 如果数据库状态的修改次数超过条件所设置的次数
            # 并且距离上次保存的时间超过条件所设置的时间
            # 那么执行操作
            if server.ditry >= serverparam.changes and 
                save_interval > server.seconds:
                BGSAVE()
#....

3.3、AOF持久化是什么?

AOF(Append only file) 持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。


aof

3.4、AOF持久化怎么做

将redis.conf配置项appendonly no改为appendonly yes,重启redis即可。

image.png

3.5、AOF原理

AOF持久化分为三个步骤 命令追加(append)、文件写入、文件同步(sync)
这里有很多人会迷惑,文件写入跟文件同步的区别两个难道不是一个操作吗?

对用户而言,是一个操作,就是将内容写入文件。但是操作系统为了提高效率,会将写入数据暂时保存在一个内存缓存中,等到缓存区被填满或者到了一定时间时,才将数据写入到磁盘中。所以,如果只是将数据写入文件而不同步,还是存在丢失数据的风险。

当AOF持久化功能打开后,服务器在执行完一个写命令后,会以协议格式将命令保存至redisServer的aof_buf缓冲区中。

struct redisServer{
   //aof缓冲区
    sds aof_buf ;
}

AOF有个配置参数appendfsync是决定什么时候将aof_buf缓冲区的数据写入和保存到AOF文件里面。有三个参数可选:


image.png
参数 描述
always 将aof_buf缓冲区的所有内容写入并同步到AOF文件中。每个事件循环都执行效率最慢,安全性最高。宕机时丢失数据会最少,会丢一个事件循环的数据。
everysec 默认选项。将aof_buf缓冲区的所有内容写入到AOF文件中,如果距离上次同步AOF文件超过一秒钟,再次同步。宕机时,有可能会丢失一秒钟数据。
no 这个配置项不是说不保存数据,而是每个事件循环都将aof_buf缓冲区的所有内容写入到AOF文件,是否同步取决于操作系统。速度最快,宕机时丢的数据最多。

3.5、AOF存在的问题

1. AOF存在的问题

AOF不同于RDB持久化,RDB保存的都是有效数据,而AOF保存的是执行命令,随着服务器运行,AOF文件会越来越大,这是它的一个弊端。
例如,RPUSH list "a" "b" RPUSH list "c" "d"
RDB只会保存数据list a b c d一条记录,AOF会保存两条命令。

2. AOF重写,解决AOF文件过大问题

redis提供一种方式可以解决上面的问题:AOF重写
就是每隔一段时间重新生成新的AOF文件代替现有的AOF文件。新的AOF文件不需要去对现有的AOF文件进行任何操作,它是通过读取数据库状态实现的。有两个参数会触发AOF重写,当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF重新会从数据库中读取键现有的值,然后用一条命令去记录键值对。
例如,RPUSH list "a" "b" RPUSH list "c" "d"
现有的AOF是保存了两条命令,AOF重写文件会用一条命令代替上面的两条命令,所以新的AOF文件会比现有的AOF文件占用空间小。

3. AOF重写问题

redis将AOF重新程序放到子进程里进行,不至于影响主线程,但随之而来会存在一个问题,子进程在AOF重新期间,新的命令无法进入子线程被写入AOF文件中。

4. AOF重写缓存区,解决AOF重写过程中无法保存新命令问题

redis为了解决重写的这个问题,设置了一个AOF重写缓冲区,它会记录AOF重写期间的命令,在子进程完成重写后,将AOF重写缓冲区的命令写入新的AOF文件中,并替换现有的AOF文件。

上一篇下一篇

猜你喜欢

热点阅读