踢一场足球需要很长的时间,那么就需要充足的体力来支撑。那么redis中的持久化机制是怎么样的?接下来就来聊一聊。
每一个足球运动员的身体是真的强,为了胜利,在大草原上奔跑,那个路程我感觉比我一年都跑的多。

持久化机制

      • 1 快照(Snapshot)
        • 1.1. 特点
        • 1.2.快照生成方式
        • 工作原理
        • 1.3.配置生成快照名称和位置
        • 1.4优缺点
      • 2 AOF 只追加日志文件
        • 2.1.特点
        • 2.2.开启AOF持久化
        • 2.3.日志追加频率
        • 2.4.修改同步频率
        • 2.5. 修复配置文件
      • RDB和AOF的不同
      • 3 AOF文件的重写
        • 3.1. AOF带来的问题
        • 3.2. AOF重写
        • 3.3. 触发重写方式
        • 3.4. 重写原理
      • 4 持久化总结

client redis[内存] —–> 内存数据- 数据持久化–>磁盘

Redis官方提供了两种不同的持久化方法来将数据存储到硬盘里面分别是:

  • 快照(Snapshot)
  • AOF (Append Only File) 只追加日志文件

1 快照(Snapshot)

1.1. 特点

这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是redis的默认开启持久化方式,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式

RDB:在指定时间间隔后,将内存中的数据集快照写入数据库 ;在恢复时候,直接读取快照文件,进行数据的恢复 ;

默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。文件名可以在配置文件中进行自定义。

1.2.快照生成方式

  • 客户端方式: BGSAVE 和 SAVE指令

  • 服务器配置自动触发

  • 客户端方式是BGSAVE

  • 客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。

名词解释:fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,在类Lunix系统中创建子进程的操作会进行优化:在刚开始的时候,父子进程共享相同内存,直到父进程或子进程对内存进行了写之后,对被写入的内存的共享才会结束服务。

工作原理


在进行 RDB 的时候,redis 的主线程是不会做 io 操作的,主线程会 fork 一个子线程来完成该操作;

  1. Redis 调用forks。同时拥有父进程和子进程。
  2. 子进程将数据集写入到一个临时 RDB 文件中。
  3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

客户端方式SAVE
客户端还可以使用SAVE命令来创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令。

  • 注意: SAVE命令并不常用,使用SAVE命令在快照创建完毕之前,redis处于阻塞状态,无法对外服务

服务器配置方式之满足配置自动触发
如果用户在redis.conf中设置了save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,当任意一个save配置选项条件满足。

触发机制

  1. save的规则满足的情况下,会自动触发rdb原则
  2. 执行flushall命令,也会触发我们的rdb原则
  3. 退出redis,也会自动产生rdb文件

如何恢复rdb文件

  1. 只需要将rdb文件放在redis启动目录即可,redis启动的时候会自动检查dump.rdb恢复其中的数据
  2. 查看需要存在的位置
$ config get dir"dir""/usr/local/bin"

服务器接收客户端shutdown指令

当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器

1.3.配置生成快照名称和位置

# 1.修改生成快照名称$ dbfilename dump.rdb# 2.修改生成位置$ dir ./

1.4优缺点

优点:

  1. 适合大规模的数据恢复
  2. 对数据的完整性要求不高

缺点:

  1. 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
  2. fork进程的时候,会占用一定的内容空间。

2 AOF 只追加日志文件

2.1.特点

这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集。(将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍)

2.2.开启AOF持久化

在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启,默认是不开启的,我们需要手动配置,然后重启redis,就可以生效了!

开启AOF持久化

  1. 修改 appendonly yes 开启持久化
  2. 修改 appendfilename “appendonly.aof” 指定生成文件名称

2.3.日志追加频率

  1. always 【谨慎使用】
  • 说明: 每个redis写命令都要同步写入硬盘,严重降低redis速度
  • 解释: 如果用户使用了always选项,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少;遗憾的是,因为这种同步策略需要对硬盘进行大量的写入操作,所以redis处理命令的速度会受到硬盘性能的限制;
  • 注意: 转盘式硬盘在这种频率下200左右个命令/s ; 固态硬盘(SSD) 几百万个命令/s;
  • 警告: 使用SSD用户请谨慎使用always选项,这种模式不断写入少量数据的做法有可能会引发严重的写入放大问题,导致将固态硬盘的寿命从原来的几年降低为几个月。
  1. everysec 【推荐,默认】
  • 说明: 每秒执行一次同步显式的将多个写命令同步到磁盘
  • 解释: 为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据。
  1. no 【不推荐】
  • 说明: 由操作系统决定何时同步
  • 解释:最后使用no选项,将完全有操作系统决定什么时候同步AOF日志文件,这个选项不会对redis性能带来影响但是系统崩溃时,会丢失不定数量的数据,另外如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢。

2.4.修改同步频率

修改日志同步频率

  • 修改appendfsync everysec|always|no 指定
# appendfsync alwaysappendfsync everysec# appendfsync no

2.5. 修复配置文件

如果这个aof文件有错位,这时候redis是启动不起来的,我需要修改这个aof文件

redis给我们提供了一个工具 直接运行这个就行redis-check-aof --fix

如果文件正常,重启就可以直接恢复了

优点

  1. 每一次修改都会同步,文件的完整性会更加好
  2. 默认开启的是每秒同步一次,可能会丢失一秒的数据
  3. 从不同步,效率最高

缺点

  1. 相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢!
  2. Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化

RDB和AOF的不同

RDB是日志,而AOF是记录写操作的

RDB 和 AOF 对比

RDBAOF
启动优先级
体积
恢复速度
数据安全性丢数据根据策略决定

如何选择使用哪种持久化方式?

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。


3 AOF文件的重写

3.1. AOF带来的问题

因为是无限追加 ,AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写(ReWriter)机制。

3.2. AOF重写

用来在一定程度上减小AOF文件的体积

3.3. 触发重写方式

  1. 客户端方式触发重写
  • 执行BGREWRITEAOF命令 不会阻塞redis的服务
  1. 服务器配置方式自动触发
  • 配置redis.conf中的auto-aof-rewrite-percentage选项
  • 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大

3.4. 重写原理

注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。

重写流程

  1. redis调用fork ,现在有父子两个进程 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
  2. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
  3. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
  4. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。

4 持久化总结

两种持久化方案既可以同时使用(aof),又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定。

无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)。

AOF和RDB同时存在的话,会优先考虑AOF,因为它全,而且丢失数据不会超过2s。

部分图片参考了网络上的内容,有问题请联系。