Redis的持久化——AOF与RDB

一、概述

         Redis支持AOF与RDB两种持久化机制。持久化可有效的避免因进程退出而造成的数据丢失问题。持久化可以让用户将自己的数据存储在硬盘上,当重启时,根据持久化的数据即可实现数据恢复。

        Redis常用配置说明:https://www.redis.net.cn/tutorial/3504.html。    

 

二、AOF

       AOF(Append Only File),它以独立日志的方式记录的写操作,其实就是记录每次写操作的命令,比如set key value,然后追加到原来文件中。在Redis重启时根据文件的命令达到恢复数据的目的。AOF主要解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。

2.1 使用AOF

        AOF默认不开启,默认配置:appendonly no。AOF持久化后的文件名的配置:appendfilename "appendonly.aof",即默认的文件名为appendonly.aof。文件的保存路径通过dir ./来配置,与RDB的路径一样。

 

2.2  AOF执行流程

       AOF的工作流程,首先写入用户所输入的写入命令(append),然后进行文件同步(sync),再进行文件重写(rewrite),最后重新加载(load)。如下图:

1,所有的用户输入的写入命令追加到aof_buf(缓冲区)中;

2,AOF缓冲区根据对应的策略向硬盘执行同步操作;

3,随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的;

4,当Redis服务器重启时,加载AOF文件进行数据恢复。

Redis的持久化——AOF与RDB_第1张图片

2.2.1 写入命令

       AOF命令写入的内容是文本协议格式。如下图,就本机Redis集群6381节点的AOF持久化文件的内容:

Redis的持久化——AOF与RDB_第2张图片

        为什么格式是这样的,这需要先去了解下客户端的通信协议。客户端与服务端之间的通信协议建立在TCP协议之上,Redis制定了RESP(REdis Serialization Protocol, Redis序列化协议)实现客户端与服务端的正常交互。此文件兼容性好,性能高,可读性强,中文的key也可以直接查看。

        Redis是单线程的,若每次写AOF文件的命令都直接追加到硬盘,那性能完全取决于当前硬盘的负载,而不是光取决于Redis的性能了,根据木桶原理,性能将取决于较短的一块。但若先写入到缓冲区aof_buf中,Redis可以提供多种缓冲同步到硬盘的策略,这样可以很从容的使用各种策略,如此可以在性能和安全方面做出平衡。

 

2.2.2 文件同步

        Redis提供了三种常用的AOF缓冲区同步文件的策略,分别是no, always, everysec。具体含义如下:

策略 说明
no 命令写入到aof_buf缓冲区后,调用系统的write操作,不对AOF文件做同步操作,数据将在内核或操作系统的意愿下提交到磁盘,即在操作系统需要时刷新数据,大多数Linux系统中同步周期为30秒。此策略速度快。
always 命令写入aof_buf后,调用系统的同步操作,将数据同步到AOF文件,同步操作完成后线程返回。此策略最安全(数据完整性好)但慢。
everysec 默认配置,数据将使用write写入文件,并使用fsync每秒一次从内核刷新到磁盘。通常每次返回事件循环时都会执行write调用,但这不能保证。

具体可参考:http://oldblog.antirez.com/post/redis-persistence-demystified.html,也看查询配置文件中的注释。

 

2.2.3 重写

        随着命令的不断写入AOF的文件,文件会越来越大,这是个糟糕的事情。Redis通过AOF重写机制来压缩文件大小,解决了这一问题。AOF文件重写是把Redis进程内的数据转化为写命令并同步到新AOF文件的过程。

        重写后的AOF文件可能比以前小,因为进程内已经超时的数据不会写入文件;而且旧的文件中可能有无效的命令,比如del key,重写时使用进程的数据直接生成,这样以来新的AOF文件只保留了最终数据的写入命令;多条写入命令可以合并为一条,另外为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分成多条。

        AOF重写降低了文件占用空间,而且更小的AOF文件可以更快的被Redis加载。

        AOF重写过程可以手动触发,也可以自动触发。手动通过bgrewriteaof命令来触发。自动触发时,根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发的时机。其中,auto-aof-rewrite-min-size表示运行AOF重写时文件大小的最小值,默认为64M。auto-aof-rewrite-percentage表示当前AOF空间(aof_current_size)和上一次重写后AOF的文件空间(aof_base_size)的比值。

 

三、RDB

        RDB(Redis DataBase)持久化方法也可以叫快照(snapshotting),它是将存在于某一时刻的所有数据生成快照保存到硬盘RDB也是Redis默认的持久化机制。简单点来说,RDB是在指定的时间段内,当key发生指定次孪生时就会执行写操作,将内存中的数据写入到磁盘——就是生成dump.rdb文件。这样在重启时,Redis会读取dump.rdb文件来恢复数据。

        举例来说,当在windows环境下安装Redis(单机)后,Redis的目录是没有dump.rdb文件的,但当你启动Redis后,通过set key等命令保存了一些数据,会发现Redis的目录下已经有了dump.rdb文件了。打开此文件,就是存储的key和value值。关闭Redis也不会影响此文件的数据。这样Redis就完成了持久化。下图中的文件位于本机搭建的Redis集群中的6381这个节点下。

Redis的持久化——AOF与RDB_第3张图片

        RDB持久化的配置集中放在了redis.conf文件的SNAPSHOTTING后面。

 

3.1 RDB持久化的文件名与路径  dbfilename  dir

         RDB持久化的文件名为什么叫dump.rdb,也是在redis.conf配置文件中配置的,请看下面的配置:dbfilename  dump.rdb。dump.rdb文件的路径也是配置的:dir  ./。可以通过config  set  dir  {dir} 和config  set  dbfilename  {filename}来设置RDB持久化文件的保存路径和文件名,config  set  parameter  value命令可以在运行期修改执行,以动态地调整 Redis 服务器的配置(configuration)而无须重启。

   

Redis的持久化——AOF与RDB_第4张图片

 

3.2 RDB持久化的规则 save

        RDB的配置在redis.conf中可以看出,允许配置时间间隔、次数:save    ,即在多少时间内、多少个key发生变化,就进行持久化。通过下面的配置项的注释可以看出,其意思是:如果在900秒内有1个key发生变化、300秒内有10个key发生变化、60秒内有10000个key发生变化,以上三种情况是的关系,只有其中一种情况发生就会进行持久化操作。下面的配置是redis的默认配置。

Redis的持久化——AOF与RDB_第5张图片

 

3.3 RDB持久化文件是否压缩 rdbcompression

       Redis默认RDB持久化的文件是压缩的:rdbcompression  yes。Redis采用LZF压缩,压缩后的文件远远小于内存大小。压缩后能够减少磁盘的占用,但压缩过程会消耗CPU的资源。若CPU资源较为充足而磁盘空间较少后,建议采用默认配置;若CUP资源很紧张,但硬盘空间却很充足,那就可以不用压缩了。可以通过config  set  rdbcompression  {yes|no}来修改此配置。

 

3.4 RDB校验 rdbcheckrum

          rdbchecksum  yes。对于此配置,我个人的理解是RDB持久化文件默认开启校验,但校验来降低性能。从第5版开始,CRC64校验放在了RDB持久化文件dump.rdb的末尾。

Redis的持久化——AOF与RDB_第6张图片

 

3.5 RDB触发机制

手动触发

       触发RDB持久化有自动和手动两种机制。手动触发对应save命令和bgsave命令

save命令

        会阻塞当前Redis服务器,直到RDB过程完成为止。可以看出save命令是同步操作。对内存比较大的实例则会造成长时间阻塞,线上环境不建议使用。实例操作如下图:

bgsave命令

       Redis进程执行fork操作创建子进程,RDB持久化由创建的子进程负责处理,持久化完成后将自动结束。换句话说bgsave命令是后台异步保存当前数据库的数据到磁盘。所以持久化过程中,若发生阻塞也只是发生在fork阶段,通常时间很短。整个Redis服务不会因持久化而阻塞,因为持久化操作交由其子进程操作了。实例操作如下图:

         可以看出,bgsave是save命令的优化版。因此Redis内部所有涉及RDB的操作都采用bgsave命令,save命令已被废弃。

 

自动触发

       Redis内部存在自动触发RDB的持久化机制。下面列举几种场景:

1,使用save配置(本篇3.2节所述);

2,若从节点执行全量复制操作,主节点自动执行bgsave,生成RDB文件并发送给从节点;

3,执行debug  reload命令重新加载Redis时,也会自动触发save操作;

4,默认情况下执行shutdown命令时,若没有开启AOF持久化,则Redis自动执行bgsave。

 

3.6 流程

      bgsave是主流的触发RDB持久化的方式,其流程如下图:

Redis的持久化——AOF与RDB_第7张图片

1,执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,若存在bgsave命令直接返回;

2,父进程执行fork操作创建子进程,fork操作的过程中父进行阻塞,可通过info stats命令查看结果集中的latest_fork_usec选项,可以获得最近一个fork操作的耗时,单位为微秒;

Redis的持久化——AOF与RDB_第8张图片

3,父进程fork操作完成后,bgsave命令返回“Background saving started”信息,并且此时不再阻塞父进程,可以继续响应其他命令;

4,子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行替换。通过lastsave命令可以查看最后一次生成RDB的时间,也可以通过info命令来查看,但此命令会有很多选项,要看# Persistence下的rdb_last_save_time选项。

Redis的持久化——AOF与RDB_第9张图片

5,进得发送信号给父进程表示完成,父进程更新统计信息,具体可查看info命令的 # Persistence 结果集中的以rdb_开关的选项。

 

四、对比总结

4.1 RDB特点

        优点:RDB持久化后的文件是一个紧凑压缩的二进制文件,代表Redis在某个时间点的数据快照。很适合备份,全量复制等场景。比如每2个小时执行bgsave备份,然后把RDB文件拷贝到远程设备或文件系统中,用于灾难恢复。Redis加载RDB文件恢复数据的速度远远快于AOF的方式。

        缺点:但RDB方式持久化后的数据,不像AOF方式得到的数据那样实时,所以数据的完整性及一致性相对低一些;bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高(单次操作比AOF的成本高)。另外,RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版本RDB格式的问题。

 

4.2 AOF特点

      数据实时性高,一致性和完整性好。因为记得的内容较多,文件会越来越大,虽然会重写,但难免还是很大,数据恢复也越来越慢。

 

4.5 总结

        RDB适合大规模的数据恢复,它的备份通常不如AOF那样频繁;但数据实时性、一致性、完整性比AOF方式得到的数据低,所以不适用于对数据实时性、一致性、完整性要求很高的场合。

        所以若是仅以Redis作为缓存,那默认开启RDB即可,不用开启AOF;但若是做数据持久时,那RDB和AOF都开启较好。两者可以互补。

1,Redis提供了两种持久化机制:RDB和AOF。

2,RDB使用一次性生成内存快照的方式,产生的文件紧凑,压缩比更高,所以文件更小,在读取RDB生成的文件进行数据恢复时速度更快;但由于每次生成RDB文件开销较大,且无法做到实时持久化,所以一般用于数据冷备份和复制传输

3,save命令会阻塞主线程,所以不建议使用,bgsave命令通过fork操作创建子进程生成RDB文件,以避免阻塞。

4,AOF通过追加写命令到文件中以实现持久化,有多种策略。因为会不断的追加写命令,所以AOF产生的文件会越来越大,需要定期执行重写操作以减少文件大小。

5,AOF重写,可以通过auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数来控制自动触发,也可以使用bgrewriteaof命令来手动触发。

6,子进程执行期间,使用copy-on-write机制与父进程共享内存,避免内存消耗翻倍。AOF重写期间,还需要维护重写缓存区,保存新的命令避免数据丢失。

7,持久化阻塞主线程场景有:fork阻塞和AOF追加阻塞。fork阻塞时间跟内存量和系统有关,AOF追加阻塞说明硬盘资源紧张。

8,单机下部署多个实例时,为了防止出现多个子进程执行重写操作,建议做隔离控制,避免CPU和IO资源竞争。

 

注:本文参考了《Redis开发与运维》。

 

你可能感兴趣的:(缓存)