Redis持久化之RDB
持久化(Persistence)是指将数据写到比如固态硬盘等持久化的存储中。Redis支持以下几种持久化方式:
- RDB:即Redis Database,是指通过在不同的时间点,将数据库的快照(snapshot)以二进制格式保存到文件中,这样Redis重启后直接加载数据。
- AOF:即Append Only File,是指在Redis运行期间,不断将Redis执行的写命令(修改数据的命令)写到文件中,Redis重启后,只要将这些写命令重复执行一遍就可以恢复数据。
- RDB+AOF:同时使用RDB和AOF两种持久化方式。
RDB常用配置
RDB持久化相关的配置如下:
save 60 1000
:如果在60秒内有不少于1000个键发生了变更,那么就生成一个RDB文件。SAVE条件可以配置多个,Redis启动后会把该配置项保存在server.saveparams
中。dbfilename dump.rdb
:RDB文件名,默认为dump.rdb
。dir ./
:RDB文件和AOF文件的保存路径,默认为./
。rdbchecksum yes
:加载RDB文件后校验CRC64校验码,默认为yes,从Redis 5起开始支持。rdbcompression yes
:数据保存到RDB文件前先进行压缩,默认为yes。
RDB持久化的优势
RDB持久化主要有以下几点优势:
- RDB文件是在某个具体时刻对Redis数据库做的一个快照,因此非常适合用来对Redis数据库做备份。比如你可以对过去24小时内每个小时生成的RDB文件进行归档,并且在过去30天内每天都做一次RDB文件备份。这样在Redis数据库因为灾难被损坏时,就可以利用备份将数据恢复到不同时间点的版本。
- 作为一个很容易在不同数据中心之间进行传输的压缩文件,RDB非常适用于灾备恢复。
- RDB持久化是由Redis父进程fork出来的子进程完成的,能够最小化对Redis性能的影响。
- 在数据量比较大时,使用RDB持久化时Redis重启后恢复的速度比AOF更快。
- RDB支持从节点在重启和故障转移后的部分同步。
RDB持久化的缺点
RDB持久化主要有以下劣势:
- 在Redis因为故障或者断电而停止工作时,RDB不能最小化数据丢失量。你可以将RDB配置成在60秒内有不少于1000个键发生了变化就进行一次持久化,然后在发生故障时你还是有可能丢失一分钟左右的数据。
- RDB子进程在进行持久化时需要经常调用fork函数。如果数据量很大,fork函数可能会比较耗时;如果数据集很大并且CPU性能一般,可能会导致Redis在若干毫秒甚至一秒内停止对客户端提供服务。相对而言,AOF调用fork函数的频率更低,并且你也可以人为调整重写AOF日志的频率。
RDB还是AOF?
如果想要达到与PostgreSQL相当的数据安全级别,应该同时使用RDB和AOF两种持久化方法。
如果能够容忍分钟级别的数据量丢失,就可以单独使用RDB持久化。
官方不建议单独使用AOF持久化,因为RDB快照在数据备份和快速重启方面有很大的优势,也能在AOF引擎故障时提供额外的数据安全保障。
快照与写时复制
RDB默认将数据库快照保存在磁盘中的二进制文件dump.rdb
中。可以通过在配置文件中设置save N M
来控制RDB在N秒内有不少于M个键发生变化时生成快照,也可以手动执行SAVE或BGSAVE命令来生成快照文件。
生成快照的流程如下:
- Redis调用fork函数创建一个RDB子进程;
- RDB子进程将数据集写入到临时的RDB文件中;
- 临时的RDB文件写完后,会替换掉旧的RDB文件。
在持久化的过程中,RDB子进程和父进程是共享同一片内存数据的,因为在创建RDB子进程时会复制父进程的页表,但是页表指向的物理内存是相同的。这样能够减少创建子进程时的性能损耗,从而加快创建子进程的速度。由于共享父进程的所有内存数据,RDB子进程可以直接读取主进程的内存数据,并将数据写入到RDB文件。
如果在RDB子进程生成RDB快照的过程中,Redis主进程修改了内存中的某个键,就会发生写时复制(Copy-On-Write, COW),那么这个键对应的物理内存就会被复制一份,主进程在复制出来的内存里进行修改,而RDB子进程就可以继续把未修改的内存数据保存到RDB快照中。也就是说,在生成RDB快照期间被修改的内存数据无法被保存到该RDB快照文件中。
RDB转AOF
如果现在有一个Redis实例使用RDB进行持久化,该怎么切换到AOF持久化?在Redis 2.2及其以后的版本中,这是一个比较简单的操作,并且不需要任何重启动作。
Redis 2.2及其以后的版本
- 备份最新的
dump.rdb
文件; - 将备份转移到安全的地方;
- 执行下面两个命令:
> redis-cli config set appendonly yes
> redis-cli config set save ""
- 确认数据库包含与切换前相同数量的键;
- 确认写命令以正确的方式添加到了AOF文件中。
其中,redis-cli中的第一个CONFIG命令用于开启AOF持久化,第二个CONFIG命令用于关闭RDB持久化(如果你想同时使用两种持久化方式,可以不执行第二个命令)。
🐍 切记一定要修改
redis.conf
配置文件中的对应配置,否则Redis重启后在redis-cli中开启的AOF持久化配置会失效。
Redis 2.2之前的版本
- 备份最新的
dump.rdb
文件; - 将备份转移到安全的地方;
- 停止所有对数据库的写操作;
- 在redis-cli中执行一次BGREWRITEAOF命令。该命令会创建AOF文件;
- 在AOF dump文件生成以后,停止Redis服务;
- 修改
redis.conf
文件来开启AOF持久化; - 重新启动Redis服务;
- 确认数据库包含与切换前相同数量的键;
- 确认写命令以正确的方式添加到了AOF文件中。
RDB与AOF的关联
Redis 2.4及其以后的版本中,会确保在生成RDB快照的过程中不会触发AOF重写,同时在AOF重写的过程中不会允许执行BGSAVE命令。这么做是为了避免生成RDB快照和重写AOF的两个后台进程同时进行大量的磁盘I/O。
在正在创建RDB快照时,如果用户通过执行BGREWRITEAOF命令显示地要求进行AOF重写时,Redis服务将回复一个OK状态代码,告知用户重写操作已安排,并且一旦快照完成,AOF重写就会开始。
在RDB和AOF同时启用的情况下,Redis发生重启后,AOF将优先被用来重建原有的数据集,因为AOF中包含的数据更加完整。
Redis数据备份
Redis对数据备份非常友好,你可以在数据库运行时复制RDB文件。RDB文件一旦生成就不会被修改。Redis在创建RDB文件时会使用一个临时的文件名,只有在快照文件创建完毕后才会被重命名为默认的RDB文件名。
官方的建议如下:
- 创建一个定时任务,将按小时生成的RDB文件保存到一个单独的路径下,并将按天生成的快照文件保存到另一个不同的路径下。
- 每次运行定时任务时,使用find命令来确保过旧的快照文件已被删除。确保在快照文件名称中包含快照生成时的日期和时间信息。
- 确保至少每天一次把RDB快照文件传输到其他数据中心、或者其他物理机上。
REFERENCES
【1】https://redis.io/docs/management/persistence/
【2】https://raw.githubusercontent.com/redis/redis/6.0/redis.conf