暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis的RDB和AOF持久化方案详解

猿视野 2021-06-23
448

Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。所以Redis也可以被看成是一个数据结构服务 器。Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。

由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。那么这两种持久化方式有什么区别呢,改如何选择呢?网上看了大多数都是介绍这两种方式怎么配置,怎么使用,就是没有介绍二者的区别,在什么应用场景下使用。

快照(Snapshot)

4.1.1 特点

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

快照生成方式

客户端方式: BGSAVE 和 SAVE指令
服务器配置自动触发
客户端方式之BGSAVE


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

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




    stop-writes-on-bgsave-error yes
    说明:后台存储过程中如果出现错误现象,是否停止保存操作
    经验:通常默认为开启状态
    客户端方式之SAVE

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

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

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


      save second changes
      作用
      满足限定时间范围内key的变化数量达到指定数量即进行持久化
      参数
      second:监控时间范围
      changes:监控key的变化量
      位置
      在conf文件中进行配置
      范例
      save 900 1
      save 300 10
      save 60 10000


      注意: save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的
      save配置中对于second与changes设置通常具有互补对应关系,尽量不要设置成包含性关系
      save配置启动后执行的是bgsave操作

      服务器接收客户端shutdown指令

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

      配置生成快照名称和位置

      1.修改生成快照名称

      dbfilename dump.rdb


      2.修改生成位置

      dir ./   # 这个表示redis-cli、redis-server这些命令的同级目录

      RDB优点、缺点

      RDB优点

      RDB是一个紧凑压缩的二进制文件,存储效率较高

      RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景

      RDB恢复数据的速度要比AOF快很多

      应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。


      Rdb缺点

      RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据

      bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能

      Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象

      AOF 只追加日志文件

      特点

      这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集.


      dir

      AOF持久化文件保存路径,与RDB持久化文件保持一致即可

      开启AOF持久化

      在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启

        1.开启AOF持久化
        a.修改 appendonly yes 开启持久化
        b.修改 appendfilename "appendonly.aof" 指定生成文件名称

        日志追加频率

        1.always 【谨慎使用】

        说明: 每个redis写命令都要同步写入硬盘,严重降低redis速度

        解释: 如果用户使用了always选项,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少;遗憾的是,因为这种同步策略需要对硬盘进行大量的写入操作,所以redis处理命令的速度会受到硬盘性能的限制;

        注意: 转盘式硬盘在这种频率下200左右个命令/s ; 固态硬盘(SSD) 几百万个命令/s;

        警告: 使用SSD用户请谨慎使用always选项,这种模式不断写入少量数据的做法有可能会引发严重的写入放大问题,导致将固态硬盘的寿命从原来的几年降低为几个月。


        2.everysec 【推荐】

        说明: 每秒执行一次同步显式的将多个写命令同步到磁盘

        解释:为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据。


        3.no 【不推荐】

        说明: 由操作系统决定何时同步 

        解释:最后使用no选项,将完全有操作系统决定什么时候同步AOF日志文件,这个选项不会对redis性能带来影响但是系统崩溃时,会丢失不定数量的数据,另外如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢。

        修改同步频率

          1.修改日志同步频率
          修改appendfsync everysec|always|no 指定

          AOF文件的重写

          AOF带来的问题

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

          AOF重写

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

          触发重写方式

          1.客户端方式触发重写

          执行BGREWRITEAOF命令  不会阻塞redis的服务


          2.服务器配置方式自动触发

          配置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设置为更大

          重写原理

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

          重写流程

          1. redis调用fork ,现在有父子两个进程 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令

          2. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。

          3. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。

          4. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。


          Redis 持久化总结

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

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


          文章转载自猿视野,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论