Redis是把所有数据都存储在内存中的,但由于内存属于易失存储器,在系统掉电后其中的数据就会丢失。因此,redis提供了持久化功能,把内存中存储的数据以文件形式存储到磁盘上,服务器可以根据这些文件进行数据恢复。
为了满足不同的持久化需求,Redis提供了RDB持久化、AOF持久化和RDB-AOF混合持久化等多种持久化方式以供用户选择。
一、RDB持久化
RDB(Redis DataBase)持久化,以创建一个包含了服务器中数据的二进制压缩文件进行持久化,这些文件都以rdb后缀结尾。
1、创建rdb文件
Redis提供了多种创建RDB文件的方法,既可以使用SAVE命令或者BGSAVE命令手动创建RDB文件,也可以通过设置save配置选项让服务器在满足指定条件时自动执行BGSAVE命令。
BGSAVE命令与SAVE命令的区别在于BGSAVE不会直接使用Redis服务器进程创建RDB文件,而是使用子进程创建RDB文件,因此服务器在创建RDB文件期间也可以为其他客户端提供服务。 当Redis服务器接收到用户发送的BGSAVE命令时,将执行以下操作: 1)创建一个子进程。 2)子进程执行SAVE命令,创建新的RDB文件。 3)RDB文件创建完毕之后,子进程退出并通知Redis服务器进程(父进程)新RDB文件已经完成。 4)Redis服务器进程使用新RDB文件替换已有的RDB文件。
save seconds changes,其中seconds用于指定触发持久化操作所需的市场,changes用于指定触发持久化操作所需的修改次数,也就是说如果在seconds秒内发生了changes次修改,那么服务器就会自动执行一次BGSAVE命令。
Redis允许同时配置多个save选项,当其中任意一个条件被满足时,服务器就会执行一次BGSAVE命令,但由于避免出现同时满足多个触发条件而使服务器过于频繁地执行BGSAVE命令,Redis服务器在每次成功创建RDB文件之后,将会重置计数。
save配置项的默认值为: ave 60 10000 save 300 100 save 3600 1
也可以设置 sava “” 来关闭持久化
2、RDB文件结构
RDB文件总体包含7个部分:RDB文件标识符、版本号、设备附加信息、数据库数据、Lua脚本缓存、EOF、CRC64校验和
-
RDB文件标识符 文件最开头的部分为RDB文件标识符,这个标识符的内容为"REDIS"这5个字符。Redis服务器在尝试载入RDB文件的时候,可以通过这个标识符快速地判断该文件是否为真正的RDB文件。 -
版本号 版本号是一个字符串格式的数字,长度为4个字符。 -
设备附加信息 设备附加信息部分记录了生成RDB文件的Redis服务器及其所在平台的信息,比如服务器的版本号、宿主机器的架构、创建RDB文件时的时间戳、服务器占用的内存数量等。 -
数据库数据 数据库数据部分记录了Redis服务器存储的0个或任意多个数据库的数据,当这个部分包含多数个数据库的数据时,各个数据库的数据将按照数据库号码从小到大进行排列,比如,0号数据库的数据将排在最前面,紧接着是1号数据库的数据,然后是2号数据库的数据,以此类推。 -
Lua脚本缓存 如果Redis服务器启用了复制功能,那么服务器将在RDB文件的Lua脚本缓存部分保存所有已被缓存的Lua脚本。 -
EOF EOF部分用于标识RDB正文内容的末尾,实际值为0xFF,当Redis服务器读取到EOF的时候,它知道RDB文件的正文部分已经全部读取完毕了。 -
CRC64校验和 CRC64校验和是一个无符号64位校验和,比如5097628732947693614。Redis服务器在读入RDB文件时会通过这个校验和来快速地检查RDB文件是否有出错或者损坏的情况出现。
3、Redis服务器载入RDB文件过程
当Redis服务器启动时,它会在工作目录中查看是否有RDB文件出现,如果有就打开读取文件的内容并执行以下载入操作:
- 检查文件开头的标识符是否为“REDIS”,如果是则继续执行后续的载入操作,不是则抛出错误并终止载入操作;
- 检查文件的RDB版本号,以此来判断当前Redis服务器能否读取这一版的RDB文件;
- 根据文件中记录的设备附加信息,执行相应的操作和设置;
- 检查文件的数据库数据部分是否为空,如果不为空就执行以下子操作;
(1)根据文件记录的数据库号码,切换至正确的数据库; (2)根据文件记录的键值对总数量以及带有过期时间的键值对数量,设置数据库底层数据结构; (3)一个接一个地载入文件记录的所有键值对数据,并在数据库中重建这些键值对。 - 如果服务器启用了复制功能,那么将之前缓存的Lua脚本重新载入缓存中;
- 遇到EOF标识,确认RDB正文已经全部读取完毕;
- 载入RDB文件末尾记录的CRC64校验和,把它与载入数据期间计算出的CRC64校验和进行对比,以此来判断被载入的数据是否完好无损;
- RDB文件载入完毕
4、RDB的数据丢失问题
RDB数据持久化方式为时间点快照,也就是说RDB文件记录的是服务器在开始创建文件的那一刻,服务器中包含的所有键值对数据。因此在系统停机时将丢失最后一次成功实施持久化之后的所有数据。
因为SAVE命令是一个同步操作,它的开始和结束都位于同一个原子时间之内,所以如果使用SAVE命令进行持久化,那么服务器在停机时将丢失最后一次成功执行SAVE命令之后产生的所有数据。
BGSAVE命令是一个异步命令,它的开始和结束并不位于同一个原子时间之内,所以如果用户使用BGSAVE命令进行持久化,那么服务器在停机时丢失的数据量将取决于最后一次成功执行的BGSAVE命令的开始时间。
总的来说,无论使用SAVE命令还是BGSAVE命令,停机时服务器丢失的数据量将取决于创建RDB文件的时间间隔:间隔越长,停机时丢失的数据也就越多。 但创建RDB文件时需要存储整个服务器包含的所有数据,并因此消耗大量计算资源和内存资源,所以通过增大RDB文件的生成频率来保证数据安全的也并不可取。
二、AOF持久化
与RDB持久化不同,AOF持久化是一种增量式的持久化,服务器每次执行完写命令之后,都会以协议文本的方式将被执行的命令追加到AOF文件的末尾。服务器在停机后,只需要重新执行AOF文件中保存的Redis命令,就可以将数据库恢复至停机之前的状态。
1、启用AOF持久化功能
可通过 appendonly 配置项来决定是否启用AOF持久化功能,该配置项的值可以是 yes 或者 no,当AOF持久化功能处于打开状态时,Redis服务器在默认情况下将创建一个名为appendonly.aof文件。
为了提高程序的写入性能,现代化的操作系统通常会把针对硬盘的多次写操作优化为一次写操作。这种优化机制虽然提高了程序的性能,但是也给程序的写操作带来了不确定性,因此Redis提供了 appendfsync 配置项,以此来控制系统对 AOF文件的flush频率,appendfsync选项有三个可选值:
- always
每执行一个写命令,就对AOF文件执行一次flush操作,服务器在停机时最多只会丢失一个命令的数据,但使用这种冲洗方式将使Redis服务器的性能降低至传统关系数据库的水平; - everysec
每隔一秒,就对AOF文件执行一次flush操作,服务器在停机时最多只会丢失1s之内产生的命令数据; - no
不主动对AOF文件执行flush操作,由操作系统决定何时对AOF进行flush。
Redis使用everysec作为appendfsync选项的默认值。
2、AOF重写
如果服务器对相同的键执行过多次修改操作,那么AOF文件中就会出现多个冗余命令,因为我们只需要最终的结果就行了。冗余命令的存在不仅增加了AOF文件的体积,并且因为Redis服务器在停机之后需要通过重新执行AOF文件中保存的命令来恢复数据,所以AOF文件中的冗余命令越多,恢复数据时耗费的时间也会越多。为了减少冗余命令,让AOF文件保持“苗条”,并提供数据恢复操作的执行速度,Redis提供了AOF重写功能,该功能能够生成一个全新的AOF文件,并且文件中只包含恢复当前数据库所需的尽可能少的命令。
- 通过 BGREWRITEAOF 命令触发AOF重写
BGREWRITEAOF是一个无参数命令,直接执行即可。BGREWRITEAOF是一个异步命令,Redis在收到该命令之后会创建出一个子进程,由它扫描整个数据库并生成新的AOF文件,当新的AOF文件生成完成,子进程就会通知Redis服务器并退出,由Redis服务器使用新的AOF文件代替已有的AOF文件。
Redis中可以通过以下两个配置选项让Redis自动触发BGREWRITEAOF命令: auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage ,其中auto-aof-rewrite-min-size用于设置触发自动AOF文件重写所需的最小AOF文件大小,默认值为64mb,只有当超过该设置值时可能会触发重写;而auto-aof-rewrite-percentage用于设置AOF文件增大达到多少比列时才触发重写,该配置项默认值为100,也就是说,在AOF文件的大小增加一倍时将会自动执行一次BGREWRITEAOF命令。
AOF持久化的优缺点
AOF的优点是数据安全性高,可以将数据丢失的时间窗口限制在1秒以内。但是,其也有几个缺点:
- 因为AOF文件存储的是协议文本,所以它的体积会比包含相同数据、二进制格式的RDB文件要大得多,并且生成AOF文件所需的时间也会比生成RDB文件所需的时间更长。
- RDB持久化可以直接通过RDB文件恢复数据库数据,而AOF持久化则需要通过执行AOF文件中保存的命令来恢复数据库(前者是直接的数据恢复操作,而后者则是间接的数据恢复操作),所以RDB持久化的数据恢复速度将比AOF持久化的数据恢复速度快得多,并且数据库体积越大,这两者之间的差距就会越明显。
- AOF重写使用的BGREWRITEAOF命令与RDB持久化使用的BGSAVE命令一样都需要创建子进程,所以在数据库体积较大的情况下,进行AOF文件重写将占用大量资源,并导致服务器被短暂地阻塞。
三、RDB与AOF搭配使用
Redis从4.0版本开始引入了RDB-AOF混合持久化模式,但主要基于的是AOF持久化模式,需要先打开Redis服务器的AOF持久化功能,再将 aof-use-rdb-preamble 配置项设置为yes,就可以启用混合模式。混合模式下,Redis服务器在执行AOF重写操作时,就会像执行BGSAVE命令一样,生成相应的RDB数据写入新建的AOF文件中,同时也会以协议文本的方式将AOF重写开始之后执行的Redis命令追加到新AOF文件的末尾,即已有的RDB数据的后面。
当开启混合模式的Redis服务器载入AOF文件时,会先检查AOF文件的开头是否包含了RDB格式的内容,如果包含,就会先载入开头的RDB数据,然后再载入之后的AOF数据;如果AOF文件只包含AOF数据,那么服务器将直接载入AOF数据。
四、在关闭Redis服务器时指明是否持久化
SHUTDOWN 命令用于关闭Redis服务器,在默认情况下,执行SHUTDOWN时会有以下几步操作:
- 停止处理客户端发送的命令请求;
- 根据服务器的持久化配置选项,决定是否执行数据保存操作;如果服务器启用了RDB持久化功能,并且数据库距离最后一次成功创建RDB文件之后已经发生了改变,那么服务器将执行SAVE命令,创建一个新的RDB文件。如果服务器启用了AOF持久化功能或者RDB-AOF混合持久化功能,那么它将冲洗AOF文件,确保所有已执行的命令都被记录到了AOF文件中。
- 服务器进程退出。
因此只要服务器启用了持久化功能,那么使用SHUTDOWN命令来关闭服务器就不会造成任何数据丢失。
在有需要时,也可以使用SHUTDOWN命令提供的save选项或者nosave选项,显式地指示服务器在关闭之前是否需要执行持久化操作。
|