Redis 是一个开源( BSD 许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持的数据类型很丰富,如字符串、链表、集 合、以及散列等,并且还支持多种排序功能。

一、什么叫持久化

将数据(内存中的)保存到可永久保存的设备中。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、 XML 数据文件中等等。

从应用层与系统层理解持久化

同时,也可以从应用层和系统层这两个层面来理解持久化:

应用层:如果关闭( Close )你的应用然后重新启动则先前的数据依然存在。

系统层:如果关闭( Shutdown )你的系统(电脑)然后重新启动则先前的数据依然存在。

二、为什么要持久化

用我个人的话说就是:redis是存在缓存中的,如果不持久化,redis服务宕机或者关闭服务后,再启动服务,数据就恢复不了了,为了能够让数据长期存在redis中,就需要持久化。

三、如何实现持久化

在设计之初,Redis 就已经考虑到了这个问题。官方提供了多种不同级别的数据持久化的方式:

1.RDB(Redis DataBase),能够在指定的时间间隔对redis服务器的数据进行快照存储;

2.AOF(Append Only File),记录每次对redis服务器的写操作,当服务器重启时会重新执行这些命令来恢复原始数据。AOF以redis协议追加保存写操作到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

3.如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。

4.也可以同时开启两种持久化方式,这种情况,redis会优先载入AOF文件来恢复原始数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

四、RDB方式与AOF方式优势对比

4.1 RDB的优点

  • RDB是一个非常紧凑的文件,它保存了服务器某个时间点的数据集。
  • RDB 是一个紧凑的单一文件,很方便传送到另一个远端数据中心,非常适用于灾难恢复。
  • RDB在保存RDB文件时,父进程会fork一个子进程,接下来的备份工作全由子进程进行,父进程不需要再做其他的IO操作,所以RDB持久化方式可以最大化redis的性能。
  • 与AOF相比,在恢复大的数据集的时候,RDB速度会快些。

当RDB需要保存dump.rdb文件时,服务器工作工程:

  • redis调用forks, 同时拥有父进程和子进程
  • 子进程将数据写到一个临时的rdb文件
  • 当子进程完成对新rdb文件的写入时,redis用新的rdb文件代替旧的rdb文件,并删除旧的rdb文件

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。 

4.2 AOF的优点

使用AOF可以使数据保存的更全面

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

正常情况下,将appendonly.aof 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。但在实际开发中,可能因为某些原因导致appendonly.aof 文件格式异常,   从而导致数据还原失败,可以通过命令redis-check-aof --fix appendonly.aof 进行修复。

AOF重写: 1、redis不断的将写命令保存到AOF文件中,导致AOF文件越来越大,当AOF文件体积过大时,数据恢复的时间也是非常长的,因此,redis提供了重写或者说压缩AOF文件的功能。        比如对key1初始值是0,调用incr命,100次,key1的值变为100,那么其实直接一句set key1 100 就可以顶之前的100局调用,AOF重写功能就是干这个事情的。        重写时,可以调用BGREWRITEAOF命令重写AOF文件,与新建子线程bgsave命令的工作原理相似。也可以通过配置文件配置什么条件下对AOF文件重写。      2、重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中。并没有读取旧文件(太大了)。最后替换旧的aof文件      3、重写触发机制:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。这里的“一倍”和“64M” 可以通过配置文件修改。

AOF工作过程: 

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

 4.3 优缺点对比总结

RDB是保存某个时间段的数据,并且保存的是单一文件,可以将文件备份到其他服务器,在恢复大量数据时,RDB要比AOF要快。

AOF 方式默认每秒钟备份1次,频率很高,它的操作方式是以追加的方式记录日志而不是数据,并且它的重写过程是按顺序进行追加,所以它的文件内容非常容易读懂。可以在某些需要的时候打开 AOF 文件对其编辑,增加或删除某些记录,最后再执行恢复操作。

五、RDB方式与AOF方式缺点对比

5.1 RDB方式的缺点

  • 如果你希望服务中断时,保存最多的数据,RDB不适合你,虽然你可以配置不同的save时间点(例如每隔 5 分钟并且对数据集有 100 个写的操作),但是万一在 Redis 意外宕机,你可能会丢失几分钟的数据。
  • RDB需要经常需要fork子进程来保存数据到硬盘,当数据量大的时候,fork过程是非常耗时的,可能导致redis不能毫秒级响应客户端。如果数据集巨大并且 CPU 性能不是很好的情况下,这种情况会持续1秒, AOF重写也需要 fork ,但是你可以调节重写日志文件的频率来提高数据集的耐久度。

5.2 AOF方式的缺点

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

 5.3 缺点对比总结

RDB 由于备份频率不高,所以在回复数据的时候有可能丢失一小段时间的数据,而且在数据集比较大的时候有可能对毫秒级的请求产生影响。

AOF 的文件提及比较大,而且由于保存频率很高,所以整体的速度会比 RDB 慢一些,但是性能依旧很高。

六、RDB与AOF的实现

6.1 RDB 方式持久化的开启与配置

Redis 默认的持久化方式是 RDB ,并且默认是打开的。RDB 的保存有方式分为主动保存与被动保存。主动保存可以在 redis-cli 中输入 save 即可;被动保存需要满足配置文件中设定的触发条件,目前官方默认的触发条件可以在 redis.conf 中看到:

save 900 1
save 300 10
save 60 10000

其含义为:

服务器在900秒之内,对数据库进行了至少1次修改
服务器在300秒之内,对数据库进行了至少10次修改。
服务器在60秒之内,对数据库进行了至少10000次修改。

满足触发条件后,数据就会被保存为快照,正是因为这样才说 RDB 的数据完整性是比不上 AOF 的。

触发保存条件后,会在指定的目录生成一个名为 dump.rdb 的文件,等到下一次启动 Redis 时,Redis 会去读取该目录下的 dump.rdb 文件,将里面的数据恢复到 Redis。

 这个目录在哪?

如下图是我本机运行redis后产生的dump.rdb文件所在目录:

Redis持久化存储的原理 redis持久化有什么用_数据

 所以dump.rdb在redis安装根路径下。

6.1.1 RDB 被动触发保存测试

我将配置改成每10秒修改一次则触发

save 10 1
save 300 10
save 60 10000

 客户端输入:

Redis持久化存储的原理 redis持久化有什么用_Redis持久化存储的原理_02

 服务端出现日志:

Redis持久化存储的原理 redis持久化有什么用_redis_03

 且redis根路劲下dump.rdb文件更新:

Redis持久化存储的原理 redis持久化有什么用_java_04

证明被动保存生效。 

现在将redis进程kill(window版直接关掉服务界面窗口),哪些数据会被保存?
不会触发save命令。

6.1.2 shutdown 保存

shutdown命令也是可以触发保存数据的。

6.2 AOF 方式持久化的开启与配置

1、redis 默认关闭,开启需要手动把no改为yes
      配置:appendonly yes
2、指定本地数据库文件名,默认值为 appendonly.aof
      配置:appendfilename "appendonly.aof"
3、指定更新日志条件
      配置:# appendfsync always 
          appendfsync everysec(默认值)
         # appendfsync no
           配置说明:always:同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)
           everysec:出厂默认推荐,每秒异步记录一次(默认值)
           no:不同步
4、配置重写触发机制
      配置:auto-aof-rewrite-percentage 100
         auto-aof-rewrite-min-size 64mb

      配置说明:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。