Redis持久化之RDB

前言

  由于Redis是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存总,与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失。

  为了解决这个缺点,Redis提供将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis支持两种形式的持久化,一种是RDB快照(snapshotting),另一种是AOF(append-only-file)。本章对RDB快照进行介绍。

简介

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

  Redis会单独创建(Fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

Fork:Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量等)数值和原进程一致,但是它是一个全新的进程,并作为原进程的子进程。

   RDB保存的是dump.rdb文件

如何触发RDB快照

被动触发

 1. 设置配置文件触发RDB持久化条件save,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave(这个命令下面介绍)

 Redis持久化之RDB

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

 2. 打开客户端 redis-cli,添加几条记录

Redis持久化之RDBRedis持久化之RDB

然后发现redis - server短的日志窗口中出现了如下的提示

Redis持久化之RDB

意思是:保存在磁盘上的DB,并且在目录内看到有dump.rdb文件生成

现在将redis进程kill,会发现Redis重启后,少了一些最后几个记录,所以印证了RDB方式的数据完整性是不可靠的,除非断掉的那一刻正好是满足触发条件的条数。

主动触发

  就是通过命令主动保存rdb数据文件。savebgsave

  当在redis - cli 客户端执行save或bgsave命令,Redis便执行RDB持久化保存数据。

   Redis 提供了savebgsave这两种不同的保存方式,并且这两个方式在执行的时候都会调用rdbSave函数,

但它们调用的方式各有不同:

  • save 直接调用 rdbSave方法 ,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。

  • bgsave 则 fork 出一个子进程,子进程负责调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。因为 rdbSave 在子进程被调用,所以 Redis 服务器在 bgsave 执行期间仍然可以继续处理客户端的请求。

  save 是同步操作,bgsave是异步操作。bgsave命令的使用方法和save命令的使用方法是一样的。

Redis持久化之RDB

  shutdown命令也会触发RDB持久化

Redis持久化之RDB

Redis持久化之RDB

然后Redis服务就关闭掉了。重启Redis服务,发现RDB持久化生效。

Redis持久化之RDB

 注意:RDB持久化必须在RDB开启的情况。

总结:

什么情况下会触发RDB持久化保存:

1. 设置配置文件,处于RDB模式开启下,根据我们的 save m n 配置规则自动触发;Redis一定操作下触发持久化保存;

2. 执行save或bgsave命令,触发持久化保存;

3. 执行shutdown命令,触发持久化保存。

4. 执行 debug reload 时;

由于 save 基本不会被使用到,我们重点看看 bgsave 这个命令是如何完成RDB的持久化的。

Redis持久化之RDB

 

 

  这里注意的是 fork 操作会阻塞,导致Redis读写性能下降。我们可以控制单个Redis实例的最大内存,来尽可能降低Redis在fork时的事件消耗。以及上面提到的自动触发的频率减少fork次数,或者使用手动触发,根据自己的机制来完成持久化。

恢复数据

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

  Redis持久化之RDB

停止RDB持久化

  有些情况下,我们只想利用Redis的缓存功能,并不像使用 Redis 的持久化功能,那么这时候我们最好停掉 RDB 持久化。可以通过上面讲的在配置文件 redis.conf 中,可以注释掉所有的 save 行来停用保存功能或者直接一个空字符串来实现停用:save ""

  也可以通过命令:redis-cli config set save ""

RDB的优势和劣势

优势

1.RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。

2.生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

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

劣势

 1、RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)

2、RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)

3、在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)

RDB自动保存原理

Redis有个服务器状态结构:

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

①、首先看记录保存save条件的数组 saveparam,里面每个元素都是一个 saveparams 结构:

struct saveparam{
     //秒数
     time_t seconds;
     //修改数
     int changes;
};

前面我们在redis.conf 配置文件中进行了关于save的配置:

save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存

save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存 save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

那么服务器状态中的saveparam 数组将会是如下的样子:

Redis持久化之RDB

② dirty 计数器和lastsave 属性

  dirty计数器:记录距离上一次成功执行 save 命令或者 bgsave 命令之后,Redis服务器进行了多少次修改(包括写入、删除、更新等操作)。

  lastsave属性:是一个时间戳,记录上一次成功执行 save 命令或者 bgsave 命令的时间。

  通过这两个命令,当服务器成功执行一次修改操作,那么dirty 计数器就会加 1,而lastsave 属性记录上一次执行save或bgsave的时间,Redis 服务器还有一个周期性操作函数 severCron ,默认每隔 100 毫秒就会执行一次,该函数会遍历并检查 saveparams 数组中的所有保存条件,只要有一个条件被满足,那么就会执行 bgsave 命令。

  执行完成之后,dirty 计数器更新为 0 ,lastsave 也更新为执行命令的完成时间。

 

上一篇:redis常见报错


下一篇:redis快照关闭了导致不能持久化的问题