Redis:持久化RDB与AOF

参考资料:

《Redis 持久化存储方案》

《Redis持久化》

《Redis基础篇(三)持久化:AOF日志》

《Redis的AOF日志》

《一起看懂Redis两种持久化方式的原理》

《Redis的持久化》

        写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

目录

一、简介

二、RDB

        1、RDB简介

        2、RDB 的触发

        2.1、手动触发

        2.2、自动触发

        3、RDB相关配置

        4、持久化期间的数据同步

二、AOF

        1、AOF简介

        2、AOF 的创建

         3、AOF相关配置

        4、持久化期间的数据同步

        5、AOF重写

        5.1、什么是AOF重写

        5.2、AOF重写过程

三、补充

        RBD与AOF的比较

        RDB与AOF混用

        数据如何恢复

        使用建议


一、简介

        Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上,以防止突然宕机造成的数据丢失。

        在Redis的官网中,明确说明的持久化方案有2种(传送门)

        RDB: 即快照模式,将内存中某一时刻的所有数据都写入到硬盘中。
        AOF :追加文件模式,存储的是Redis中所执行的命令。

        这两种模式在以前只能单独使用,而4.0版本后可以混合使用。

二、RDB

        1、RDB简介

        RDB 就是 Redis DataBase 的缩写,即快照方式,RDB持久化是指将某个时间点的所有 Redis 数据保存到一个经过压缩的二进制文件(RDB 文件)中

        创建 RDB 后,用户可以对 RDB 进行备份,可以将 RDB 复制到其他服务器从而创建具有相同数据的服务器副本,还可以在重启服务器时使用。

        RDB 既可以手动执行,也可以根据服务器配置选项定期执行。该功能可以将某个时间点的数据库状态保存到一个 RDB 文件中。

        2、RDB 的触发

        RDB既可以手动触发也可以自动触发。

        2.1、手动触发

        Redis 提供save和bgsave这两个命令用于生成 RDB 文件。

  • SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 创建完成为止,在阻塞期间,服务器不能响应任何命令请求。
  • BGSAVE 命令会派生出(fork)一个子进程,然后由子进程负责创建 RDB 文件,服务器进程(父进程)继续处理命令请求。

        bgsave流程总结如下:

        1、redis客户端执行bgsave命令或者自动触发bgsave命令。

        2、主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回。

         3、如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作。

        4、子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件。

        5、同时发送信号给主进程,通知主进程rdb持久化完成。

        上文中第2点提到,“主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回”,这是因为 BGSAVE命令执行期间,SAVE、BGSAVE、BGREWRITEAOF 这三个命令会与当前的 BGSAVE 操作产生竞态条件,降低性能,因此会被拒绝。

        另外注意,快照文件只有1个,每次进行RBD持久化都会先写入一个临时文件,在写入完成后再替换旧的快照文件。当然,如果想保存多份快照文件,我们可以创建一个定期任务(cron job),每小时将一个 RDB 文件备份到一个文件夹,以此来实现我们的目的。

        2.2、自动触发

        自动触发的几种方式如下:

  • redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;
  • 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;
  • 执行debug reload命令重新加载redis时也会触发bgsave操作;
  • 执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作;

        这里我们只介绍save配置的方式,在 redis.conf中进行如下配置,当满足如下条件之一时,就会自动执行bgsave。

save 900 1       -- 900 秒内,至少对数据库进行了 1 次修改
save 300 10      -- 300 秒内,至少对数据库进行了 10 次修改
save 60 10000    -- 60 秒内,至少对数据库进行了 10000 次修改

        3、RDB相关配置

# 文件名称
dbfilename dump.rdb

# 文件保存路径
dir /home/work/app/redis/data/

# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes

# 是否压缩
rdbcompression yes

 dbfilename:RDB文件在磁盘上的名称。

dir:RDB文件的存储路径。默认设置为“./”,也就是Redis服务的主目录。

stop-writes-on-bgsave-error:当配置为yes时,如果快照操作出现异常(例如操作系统用户权限不够、磁盘空间写满等等)时,Redis就会禁止写操作。这个特性的主要目的是使运维人员在第一时间就发现Redis的运行错误,并进行解决。

rdbcompression:该属性将在字符串类型的数据被快照到磁盘文件时,启用LZF压缩算法。Redis官方的建议是请保持该选项设置为yes,因为“it’s almost always a win”。

        4、持久化期间的数据同步

        经过前文介绍我们了解到的主线程只有在fork子进程时才会阻塞,所以在持久化期间依然会提供服务,这就产生了一个问题,RBD持久化要将整个Redis中的数据都拷贝一份进行保存,这个操作必然不是短时间内能够完成的,如果在这个过程中出现了数据的修改,该如何保证数据的一致性?

        当bgsave子进程执行时,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本,主线程的修改就会发生在这个副本上,而原内存中的值不变。然后,bgsave 子进程则会把这个副本数据写入 RDB 文件,同时快照写完后这个副本内的数据还会再同步回原来的内存块中,以此来保证内存与RBD快照中的数据一致性。

 

二、AOF

        1、AOF简介

        AOF是以 文本日志形式 将 所有写命令以 Redis 命令请求协议格式追加到 AOF 文件的末尾,以此来记录数据的变化。当服务器重启时,会重新载入和执行 AOF 文件中的命令,就可以恢复原始的数据。

        需要注意的是,AOF先写内存,后写日志。这么有2个好处:

  • 如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。  
  • 不会阻塞当前的写操作 。

        但这种方式存在潜在风险,如果命令执行完成,但在写日志之前宕机了,会丢失数据。

        2、AOF 的创建

        AOF记录的是Redis中执行的命令,AOF默认是不开启的,要开启的话需要在redis.conf中配置appendonly yes。AOF创建的过程被分为了2步,Redis 命令请求会先保存到内存中的 AOF 缓冲区,再定期写入并同步到 AOF 文件。这两步的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。

  • 命令追加 :当 Redis 服务器开启 AOF 功能时,服务器在执行完一个写命令后,会以 Redis 命令协议格式将被执行的写命令追加到 AOF 缓冲区的末尾。
  • 文件写入和文件同步 :Redis 的服务器根据 appendfsync 选项来判断 AOF 缓冲区内容是否需要写入和同步到 AOF 文件中。

        appendfsync 提供了三种写回策略:

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘; 
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘; 
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

         3、AOF相关配置

# appendonly参数开启AOF持久化
appendonly no

# AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof"

# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./

# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no

# aof重写期间是否同步
no-appendfsync-on-rewrite no

# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

appendfsync:AOF写回与同步的策略
no-appendfsync-on-rewrite:AOF 重写时不支持追加命令
auto-aof-rewrite-percentage:AOF 重写百分比
auto-aof-rewrite-min-size:AOF 重写文件的最小大小

        4、持久化期间的数据同步

        在上文介绍RDB的内容中,有介绍过当快照创建过程中数据发生修改时的处理方案,同样的问题AOF也会遇到,这里AOF与RBD的处理方法类似,但也有些区别,下面我们简单解释下。

        当fork子进程时,子进程时会拷贝父进程的页表,即虚实映射关系(虚拟内存和物理内存的映射索引表),而不会拷贝物理内存。

        5、AOF重写

        5.1、什么是AOF重写

        随着 Redis 不断运行,AOF 的体积也会不断增长,这将导致两个问题:

  • AOF 耗尽磁盘可用空间
  • Redis 重启后需要执行 AOF 文件记录的所有写命令来还原数据集,如果 AOF 过大,则还原操作执行的时间就会非常长

        为了解决 AOF 体积膨胀问题,Redis 提供了 AOF 重写功能,来对 AOF 文件进行压缩。

        AOF文件存储的是Redis中所执行过的指令,就比如一个列表经过不断的添加、删除后会产生n条操作记录。但是我们最后恢复数据的时候,必然只要恢复数据的最后状态就可以了,无需关注一个数据过往的状态,所以AOF重写实际上就是合并这些冗余的指令,将他们合并为一条指令,通过这条指令就可以直接获得Redis中数据最后的状态。这样做既可以实现数据的备份,又可以实现AOF文件的压缩。

        5.2、AOF重写过程

        首先,我们在redis.conf中配置auto-aof-rewrite-percentage、auto-aof-rewrite-min-size来设定AOF重写的时机,例如auto-aof-rewrite-percentage设为100,则表示 AOF文件的体积比上一次重写后的体积大了至少 100% 时则重写,auto-aof-rewrite-min-size则表示当AOF文件多大时开始重写(单位为M)。

        在重写时,Redis会fork出一个bgrewriteaof子进程(和bgsave一样,这个操作会造成主线程的阻塞),并把主线程的内存拷贝一份给这个bgrewriteaof子进程然后,bgrewriteaof子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。在重写完成后,再将原来的AOF文件给替换掉。

        当然这里有一个问题就是数据的追加,当我们在重写日志的时候Redis并没有阻塞,因此还是会继续接收修改操作,那么这个操作如何追加到正在重写的AOF日志中呢?这里Redis会为重写进程创建一个AOF重写缓冲区,当有操作产生时,会同时记录到AOF缓冲区与AOF重写缓冲区,等重写日志完成后,再将AOF重写缓冲区中的数据追加进去即可。

        

 

三、补充

        RBD与AOF的比较

        RBD保存的是内存的快照,且使用了LZF压缩算法,因此文件大小不会超过内存的大小,而AOF文件因为会一直追加操作指令,因此会比较大。

        RBD存储的即为内存中的数据,而AOF存储的是指令,因此使用RBD恢复数据会比AOF更快,AOF文件需要通过指令一条条改动记录,可能出现一个列表多次改动才会变为最终状态。

        RBD文件使用二进制流的方式存储,不具备可读性,AOF文件了解其结构的情况下可以手动进行数据修复。

        RDB方式必然产生fork,这种重量级操作会导致主线程的阻塞,且内存复制需要时间,因此无法实现秒级的持久化,而AOF可以。

        RDB与AOF混用

        由上一节我们可以看出,RBD与AOF各有优劣,于是4.0之后允许我们将他们混用。其方式为RBD以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

        这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

        数据如何恢复

       Redis重启时会自动读取持久化文件,过程如下:

  1. Redis重启时判断是否开启AOF,如果开启了AOF,那么就优先加载AOF文件(这是由于AOF最多损失1s的数据,因此持久化文件更加完整)。
  2. 如果AOF存在,那么就去加载AOF文件,加载成功的话Redis重启成功,如果AOF文件加载失败,那么会打印日志表示启动失败,此时可以去修复AOF文件后重新启动。
  3. 若AOF文件不存在,那么Redis就会转而去加载RDB文件,如果RDB文件不存在,Redis直接启动成功。
  4. 如果RDB文件存在就会去加载RDB文件恢复数据,如加载失败则打印日志提示启动失败,如加载成功,那么Redis重启成功,且使用RDB文件恢复数据。

        使用建议

  • 如果Redis中的数据并不是特别敏感或者可以通过其它方式重写生成数据,可以关闭持久化,如果丢失数据可以通过其它途径补回。
  • 自己制定策略定期检查Redis的情况,然后可以手动触发备份、重写数据。
  • 单机如果部署多个实例,要防止多个机器同时运行持久化、重写操作,防止出现内存、CPU、IO资源竞争,让持久化变为串行。
  • 可以加入主从机器,利用一台从机器进行备份处理,其它机器正常响应客户端的命令。
  • RDB持久化与AOF持久化可以同时存在,配合使用。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值