心门守卫免安装绿色中文版
2.9G · 2025-10-27
Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。
Redis提供了一系列持久化选项:
RDB(Redis DataBase:内存快照):将某一时刻的内存数据,以二进制的方式写入磁盘;AOF(Append Only File:增量日志):每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;Redis 4.0新增的方式,集成了AOF和RBD的优点;RDB(Redis DataBase),指的是在指定的时间间隔内将内存中的数据集快照写入磁盘,RDB是内存快照(内存数据的二进制序列化形式)的方式持久化,每次都是从Redis中生成一个快照进行数据的全量备份。
RDB持久化方案进行备份时,Redis会单独fork一个子进程来进行持久化,会将数据写入一个临时文件中,持久化完成后替换旧的RDB文件。在整个持久化过程中,主进程(为客户端提供服务的进程)不参与IO操作,这样能确保Redis服务的高性能,RDB持久化机制适合对数据完整性要求不高但追求高效恢复的使用场景。
下面展示RDB持久化流程:
上面说到了RDB持久化过程中,主进程会fork一个子进程来负责RDB的备份,这里简单介绍一下fork。
Linux操作系统中的程序,fork会产生一个和父进程完全相同的子进程。子进程与父进程所有的数据均一致,但是子进程是一个全新的进程,与原进程是父子进程关系;Linux操作系统中使用COW(Copy On Write:写时复制机制),fork子进程一般情况下与父进程共同使用一段物理内存,只有在进程空间中的内存发生修改时,内存空间才会复制一份出来。在Redis中,RDB持久化就是充分的利用了这项技术,Redis在持久化时调用glibc函数fork一个子进程,全权负责持久化工作,这样父进程仍然能继续给客户端提供服务。fork的子进程初始时与父进程(Redis的主进程)共享同一块内存;当持久化过程中,客户端的请求对内存中的数据进行修改,此时就会通过COW机制对数据段页面进行分离,也就是复制一块内存出来给主进程去修改。
RDB触发的规则分为两大类,分别是手动触发和自动触发:
自动触发:
shutdown触发flushall触发手动触发:
save命令bgsave命令以下介绍Redis的RDB持久化机制中的自动触发机制中的配置触发规则来触发RDB,涉及到RDB规则的配置、文件存储路径配置、文件名配置、文件压缩配置、文件完整性校验配置。
Redis安装目录下的redis.conf配置文件中,默认注释了下面三行数据,通过配置规则来触发RDB的持久化,需要开启或者根据自己的需求按照规则来配置。# RDB核心规则配置
# 满足条件就将内存中的数据同步到硬盘中。若不想用RDB方案,可以把save ""的注释打开,下面三个注释
# save ""
# save <指定时间间隔> <执行指定次数更新操作>
save 3600 1 # 3600秒内有1个key被修改,触发RDB
save 300 100 # 300秒内有100个key被修改,触发RDB
save 60 10000 # 60秒内有10000个key被修改,触发RDB
# 数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
dir /usr/local/redis/var
我们可以在Redis的安装目录下看到dump.rdb文件,如果没看到,连接到客户端执行一次shutdown,这个是后面shutdown自动触发规则,后续会讲述。
RDB文件的名称# 指定本地数据库文件名,一般采用默认的 dump.rdb
dbfilename dump.rdb
RDB文件压缩Redis默认会使用LZF算法对Redis的RDB文件进行压缩,这会消耗一定的CPU计算资源,但是会带来空间上的节省。
RDB文件完整性校验Redis默认使用CRC64的算法,对RDB文件完整性进行校验,以此来保证RDB文件的完整。
shutdown触发Redis的RDB持久化机制非常简单,我们在客户端执行shutdown即可。
flushall命令是清空redis内存中的数据,并且同时清空dump.rdb文件。所以这个命令就相当于删库跑路,此处只是说明该命令会触发rdb,实际使用中千万不要执行。
此时查看dump.rdb。
执行flushall命令,后再次查看,rbd文件被清空。
手动触发RDB持久化的方式可以使用save命令和bgsave命令,这两个命令的区别如下:
save:执行save指令,阻塞Redis的其他操作,会导致Redis无法响应客户端请求,不建议使用。bgsave:执行bgsave指令,Redis后台异步进行快照的保存操作,此时Redis仍然能响应客户端的请求。在实际的生产环境中,我们一般不会使用主节点Master来进行持久化备份,我们会通过在Redis的多个从服务器上进行RDB持久化备份,这样是为了对Redis数据的多次备份,防止出现网络分区或者部分节点宕机甚至是硬件损坏的情况发生。
优点:
缺点:
Redis服务器中变化的数据;RDB通过fork子进程对内存快照进行全量备份,是一个重量级操作,频繁执行成本高;fork子进程,虽然共享内存,但是如果备份时内存被修改,最大可能膨胀到2倍大小。AOF(Append Only File)是把所有对内存进行修改的指令(写操作)以独立日志文件的方式进行记录,重启时通过执行AOF文件中的Redis命令来恢复数据。AOF能够解决数据持久化实时性问题,是现在Redis持久化机制中主流的持久化方案(后续会谈到4.0以后的混合持久化)。
Redis配置文件中开启,AOF持久化方案进行备份时,客户端所有请求的写命令都会被追加到AOF缓冲区(service.aof_buf)中,缓冲区中的数据会根据Redis配置文件中配置的同步策略来同步到磁盘上的AOF文件中,同时当AOF的文件达到重写策略配置的阈值时,Redis会对AOF日志文件进行重写,给AOF日志文件瘦身。Redis服务重启的时候,通过加载AOF日志文件来恢复数据。
AOF默认不开启,默认为appendonly no,开启则需要修改为appendonly yes。
AOF配置文件的名称默认为appendonly.aof。
配置文件的地址可以通过在redis客户端执行config get dir获取,其保存路径与RDB一致。
AOF日志是以文件的形式存在的,当程序对AOF日志文件进行写操作时,实际上将内容写到了内核为文件描述符分配的一个内存缓冲区中,随后内核会异步的将缓冲区中的数据刷新到磁盘中。如果缓冲区中的数据没来得及刷回磁盘时,服务器宕机了,这些数据就会丢失。
因此Redis通过调用Linux操作系统的glibc提供的fsync(int fid)来将指定文件的内容强制从内核缓冲区刷回磁盘,以此来保证缓冲区中的数据不会丢失。不过这是一个IO操作,相比Redis的性能来说它是非常慢的,所以不能频繁的执行。
Redis配置文件中有三种刷新缓冲区的配置:
每次Redis写操作,都写入AOF日志,这种配置理论上Linux操作系统扛不住,因为Redis的并发远远超过了Linux操作系统提供的最大刷新频率,就算Redis写操作比较少的情况,这种配置也是非常耗性能的,因为涉及到IO操作,所以这个配置基本上不会用
每秒刷新一次缓冲区中的数据到AOF文件,这个Redis配置文件中默认的策略,兼容了性能和数据完整性的折中方案,这种配置,理论上丢失的数据在一秒钟左右
Redis进程不会主动的去刷新缓冲区中的数据到AOF文件中,而是直接交给操作系统去判断,这种操作也是不推荐的,丢失数据的可能性非常大。
| 写回策略 | 写回时机 | 优点 | 缺点 |
|---|---|---|---|
| always | 同步写回 | 可靠性高、最大程度保证数据不丢失 | 每个写命令都要写回硬盘,性能开销大 |
| everysec | 每秒写回 | 性能适中 | 宕机时会丢失1秒内的数据 |
| no | 由操作系统控制写回 | 性能好 | 宕机时丢失的数据可能很多 |
在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。
如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。
设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的默认fsync策略是30秒,可能丢失30秒数据。
no-appendfsync-on-rewrite no
AOF持久化机制正常恢复与RDB持久化机制的恢复是一样的,都只需要将备份文件放置到Redis的工作目录下,Redis启动时就会自动的加载。AOF持久化机制提供了AOF文件异常时恢复的功能,这个功能在AOF文件损坏的场景中经常被使用到。
测试
清空Redis服务中的数据。
写入数据。
AOF日志文件每秒会被刷新一次数据,此时数据已经写入了appendonly.aof文件。
打开文件我们可以非常清除的阅读AOF的文件内容,看到Redis的指令序列。
此时人为的进行数据破坏。
再次启动发现无法启动(我配置的别名启动)。
执行redis-check-aof --fix ../appendonly.aof对AOF日志文件进行修复。
修复过程中会有部分数据丢失。
连接客户端查看数据。
前面提到AOF的缺点时,说过AOF属于日志追加的形式来存储Redis的写指令,这会导致大量冗余的指令存储,从而使得AOF日志文件非常庞大,比如同一个key被写了10000次,最后却被删除了,这种情况不仅占内存,也会导致恢复的时候非常缓慢,因此Redis提供重写机制来解决这个问题。Redis的AOF持久化机制执行重写后,保存的只是恢复数据的最小指令集,我们如果想手动触发可以使用如下指令:
bgrewriteaof
Redis 4.0后的重写使用的是RDB快照和AOF指令拼接的方式,在AOF文件的头部是RDB快照的二进制形式的数据,尾部是快照产生后发生的写入操作的指令。
由于重写AOF文件时,会对Redis的性能带来一定的影响,因此也不能随便的进行自动重写,Redis提供两个配置用于自动进行AOF重写的指标,只有这两个指标同时满足的时候才会发生重写:
AOF重写流程如下:
bgrewriteaof触发重写,判断是否存在bgsave或者bgrewriteaof正在执行,存在则等待其执行结束再执行;fork子进程,防止主进程阻塞无法提供服务,类似RDB;Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf和aof_rewrite_buf两个重写缓冲区,前者是为了写会旧的AOF文件,后者是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失;AOF文件写入后,通知主进程;3中的aof_rewirte_buf缓冲区中的数据写入到子进程生成的临时AOF文件中;AOF文件替换旧AOF文件,完成整个重写过程。优点:
AOF可操作性更强,可通过操作日志文件进行修复。缺点:
AOF日志记录在长期运行中逐渐庞大,恢复起来非常耗时,需要定期对AOF日志进行重写(瘦身处理);AOF与RDB对比
| RDB | AOF | |
|---|---|---|
| 持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
| 数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
| 文件大小 | 会有压缩,文件体积小 | 记录命令,文件体积大 |
| 宕机恢复速度 | 很快 | 慢 |
| 数据恢复优先级 | 低,因为数据完整性不如AOF | 高,因为数据完整性更高 |
| 系统资源占用 | 高,大量CPU和内存消耗 | 低,主要是磁盘IO资源 但AOF重写时会占用大量CPU和内存消耗 |
| 使用场景 | 可以容忍数分钟的数据丢失,追求更快的启用速度 | 对数据安全性要求较高 |
RDB数据恢复虽然快,但是快照的频率不好把握。频率太低,会丢失比较多的数据,频率太高,会影响性能;AOF虽然能尽可能保证数据完整性,但是性能确实是一个诟病,比如重放恢复数据。
为了集合两者的优点,Redis 4.0提出了混合使用RDB和AOF来做持久化,既保证了Redis重启速度,又降低数据丢失风险。
混合持久化工作在AOF日志重写过程,当开启了混合持久化时,在AOF重写日志时,fork出来的重写子进程会先将与主线程共享的内存数据以RDB方式写入到AOF文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以AOF方式写入到AOF文件,写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。
也就是说,使用了混合持久化,AOF文件的前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据。其日志文件结构如下:
混合持久化通过aof-use-rdb-preamble yes开启,Redis 4.0以上版本默认开启。
我们先插入一些key,然后执行bgrewriteaof触发AOF持久化后,再插入一些key。
此时将会看到如下的效果,验证了混合持久化的方式。
混合持久化优点:
RDB和AOF持久化的优点,开头为RDB的格式,使得Redis可以更快的启动,同时结合AOF的优点,有减低了大量数据丢失的风险。混合持久化缺点:
AOF文件中添加了RDB格式的内容,使得AOF文件的可读性变得很差;AOF文件,就不能用在Redis 4.0之前版本了。最后来总结这两者,到底用哪个更好呢?
RDB;AOF,因为可能会出现Bug;RDB持久化的方式。AOF的持久化方式,而至于采用那种回写策略,则取决于你对数据完整性的要求程度。Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。