通俗讲持久化就是将内存中的数据写入非易失介质中,比如机械磁盘和SSD。
在服务器发生宕机时,作为内存数据库Redis里的所有数据将会丢失,因此Redis提供了持久化两大利器:RDB和AOF
-
RDB 将数据库快照以二进制的方式保存到磁盘中。
-
AOF 以协议文本方式,将所有对数据库进行过写入的命令和参数记录到 AOF 文件,从而记录数据库状态。
-
查看RDB配置
[redis@abc]$ cat /abc/redis/conf/redis.conf
save 900 1
save 300 10
save 60 10000
dbfilename "dump.rdb"
dir "/data/dbs/redis/rdbstro"
前三行都是对触发RDB的一个条件, 如第一行表示每900秒钟有一条数据被修改则触发RDB,依次类推;只要一条满足就会进行RDB持久化;
第四行dbfilename指定了把内存里的数据库写入本地文件的名称,该文件是进行压缩后的二进制文件;
第五行dir指定了RDB二进制文件存放目录 ;
-
修改RDB配置
在命令行里进行配置,服务器重启才会生效:
[redis@abc]$ bin/redis-cli
127.0.0.1:6379> CONFIG GET save
1) "save"
2) "900 1 300 10 60 10000"
127.0.0.1:6379> CONFIG SET save "21600 1000"
OK
RDB的SAVE和BGSAVE
RDB文件适合数据的容灾备份与恢复,通过RDB文件恢复数据库耗时较短,可以快速恢复数据。
RDB持久化只会周期性的保存数据,在未触发下一次存储时服务宕机,就会丢失增量数据。当数据量较大的情况下,fork子进程这个操作很消耗cpu,可能会发生长达秒级别的阻塞情况。
SAVE是阻塞式持久化,执行命令时Redis主进程把内存数据写入到RDB文件中直到创建完毕,期间Redis不能处理任何命令。
BGSAVE属于非阻塞式持久化,创建一个子进程把内存中数据写入RDB文件里同时主进程处理命令请求。
如图展示了bgsave的简单流程:

BGSAVE实现细节
RDB方式的持久化是通过快照实现的,符合条件时Redis会自动将内存数据进行快照并存储在硬盘上,以BGSAVE为例,一次完整数据快照的过程:
-
Redis使用fork函数创建子进程;
-
父进程继续接收并处理命令请求,子进程将内存数据写入临时文件;
-
子进程写入所有数据后会用临时文件替换旧RDB文件;
执行fork的时OS会使用写时拷贝策略,对子进程进行快照过程优化。
Redis在进行快照过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是任何时候RDB文件都是完整的。
我们可以通过定时备份RDB文件来实现Redis数据库备份,RDB文件是经过压缩的,占用的空间会小于内存中的数据大小。
除了自动快照还可以手动发送SAVE或BGSAVE命令让Redis执行快照。通过RDB方式实现持久化,由于RDB保存频率的限制,如果数据很重要则考虑使用AOF方式进行持久化。
AOF详解
在使用AOF持久化方式时,Redis会将每一个收到的写命令都通过Write函数追加到文件中类似于MySQL的binlog。换言之AOF是通过保存对redis服务端的写命令来记录数据库状态的。
AOF文件有自己的存储协议格式:
[redis@abc]$ more appendonly.aof
*2 # 2个参数
$6 # 第一个参数长度为 6
SELECT # 第一个参数
$1 # 第二参数长度为 1
8 # 第二参数
*3 # 3个参数
$3 # 第一个参数长度为 4
SET # 第一个参数
$4 # 第二参数长度为 4
name # 第二个参数
$4 # 第三个参数长度为 4
Jhon # 第二参数长度为 4
AOF配置:
[redis@abc]$ more ~/redis/conf/redis.conf
dir "/data/dbs/redis/abcd" #AOF文件存放目录
appendonly yes #开启AOF持久化,默认关闭
appendfilename "appendonly.aof" #AOF文件名称(默认)
appendfsync no #AOF持久化策略
auto-aof-rewrite-percentage 100 #触发AOF文件重写的条件(默认)
auto-aof-rewrite-min-size 64mb #触发AOF文件重写的条件(默认)
当开启AOF后,服务端每执行一次写操作就会把该条命令追加到一个单独的AOF缓冲区的末尾,然后把AOF缓冲区的内容写入AOF文件里,由于磁盘缓冲区的存在写入AOF文件之后,并不代表数据已经落盘了,而何时进行文件同步则是根据配置的appendfsync来进行配置:
appendfsync选项:always、everysec和no:
-
always:服务器在每执行一个事件就把AOF缓冲区的内容强制性的写入硬盘上的AOF文件里,保证了数据持久化的完整性,效率是最慢的但最安全的;
-
everysec:服务端每隔一秒才会进行一次文件同步把内存缓冲区里的AOF缓存数据真正写入AOF文件里,兼顾了效率和完整性,极端情况服务器宕机只会丢失一秒内对Redis数据库的写操作;
-
no:表示默认系统的缓存区写入磁盘的机制,不做程序强制,数据安全性和完整性差一些。
AOF比RDB文件更大,并且在存储命令的过程中增长更快,为了压缩AOF的持久化文件,Redis提供了重写机制以此来实现控制AOF文件的增长。
AOF重写实现的理论基础是这样的:
-
执行set hello world 50次
-
最后执行一次 set hello china
-
最终对于AOF文件而言前面50次都是无意义的,AOF重写就是将key只保存最后的状态。
-
重写期间的数据一致性问题
子进程在进行 AOF 重写期间, 主进程还需要继续处理命令, 而新的命令可能对现有的数据进行修改, 会出现数据库的数据和重写后的 AOF 文件中的数据不一致。
因此Redis 增加了一个 AOF 重写缓存, 这个缓存在 fork 出子进程之后开始启用, Redis 主进程在接到新的写命令之后, 除了会将这个写命令的协议内容追加到现有的 AOF 文件之外, 还会追加到这个缓存中。

当子进程完成 AOF 重写之后向父进程发送一个完成信号, 父进程在接到完成信号之后会调用信号处理函数,完成以下工作:
-
将 AOF 重写缓存中的内容全部写入到新 AOF 文件中
-
对新的 AOF 文件进行改名,覆盖原有的 AOF 文件
-
AOF重写的阻塞性
整个 AOF 后台重写过程中只有最后写入缓存和改名操作会造成主进程阻塞, 在其他时候AOF 后台重写都不会对主进程造成阻塞, 将 AOF 重写对性能造成的影响降到了最低。
AOF 重写可以由用户通过调用 BGREWRITEAOF 手动触发。
服务器在 AOF 功能开启的情况下,会维持以下三个变量:
-
当前 AOF 文件大小
-
最后一次 重写之后, AOF 文件大小的变量
-
AOF文件大小增长百分比
每次当 serverCron 函数执行时, 它都会检查以下条件是否全部满足, 如果是的话, 就会触发自动的 AOF 重写:
-
没有 BGSAVE 命令在进行 防止于RDB的冲突
-
没有 BGREWRITEAOF 在进行 防止和手动AOF冲突
-
当前 AOF 文件大小至少大于设定值 基本要求 太小没意义
-
当前 AOF 文件大小和最后一次 AOF 重写后的大小之间的比率大于等于指定的增长百分比
343

被折叠的 条评论
为什么被折叠?



