litterfrog 2020-06-14
持久化的功能:Redis是内存数据库,数据都是存储在内存中的,为了避免进程退出导致数据的永久丢失,要定期将Redis中的数据以某种形式从内存保存到硬盘,当下次Reids重启时,利用持久化文件实现数据恢复。
RDB:将当前数据保存到硬盘
AOF:将每次执行的写命令保存到硬盘(类似MySQL的binlog)
RDB持久化是将当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。
触发条件
SAVE 执行期间,AOF 写入可以在后台线程进行,BGREWRITEAOF 可以在子进程进行,所以这三种操作可以同时进行 ,为了避免性能问题,BGSAVE 和 BGREWRITEAOF 不能同时执行
自动触发
save m n
在配置文件中通过 save m n 命令,指定当前m秒内发生n次变化时,触发bgsave。
? 其中save 900 1的含义是:当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave;save 300 10和save 60 10000同理。当三个save条件满足任意一个时,都会引起bgsave的调用.
Redis的save m n,是通过serverCron函数、dirty计数器、和lastsave时间戳来实现的-
save m n的原理如下:每隔100ms,执行serverCron函数;在serverCron函数中,遍历save m n配置的保存条件,只要有一个条件满足,就进行bgsave。对于每一个save m n条件,只有下面两条同时满足时才算满足:
当前时间-lastsave > m
dirty >= n
在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点。
在执行shutdown命令时,自动执行rdb持久化
- 配置文件:dir配置指定目录,dbfilename指定文件名。默认是Redis根目录下的dump.rdb文件 - 动态设置:
config set dir {newdir} /// config set dbfilename {newFileName}
RDB文件 是经过压缩的二进制文件,默认采用LZF算法对RDB文件进行压缩,虽然压缩耗时,但是可以大大减小文件体积,默认是开启的,可以通过命令关闭:
config set rdbcompression no
RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行
格式:
字段说明:
REDIS常量,保存‘REDIS‘5个字符
db_version RDB文件的版本号
SELECTDB 表示一个完整的数据库(0号数据库),同理SELECTDB 3 pairs
表示完整的3号数据库;只有当数据库中有键值对时,RDB文件中才会有该数据库的信息(上图所示的Redis中只有0号和3号数据库有键值对);如果Redis中所有的数据库都没有键值对,则这一部分直接省略。其中:SELECTDB是一个常量,代表后面跟着的是数据库号码;0和3是数据库号码;
KEY-VALUE-PAIRS: pairs则存储了具体的键值对信息,包括key、value值,及其数据类型、内部编码、过期时间、压缩信息等等
EOF 标志着数据库内容的结尾(不是文件的结尾),值为 rdb.h/EDIS_RDB_OPCODE_EOF (255)
CHECK-SUM RDB 文件所有内容的校验和,一个 uint_64t 类型值, REDIS 在写入 RDB 文件时将校验和保存在 RDB 文件的末尾,当读取时,根据它的值对内容进行校验
。如果这个域的值为 0 ,那么表示 Redis 关闭了校验和功能。
? RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止
AOF(Append Only File) 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF
文件,以此达到记录数据库状态的目的
Redis服务器默认开启RDB,关闭AOF;要开启AOF,需要在配置文件中配置:
appendonly yes
//缓冲区的定义 是一个SDS, 可以兼容C语言的字符串 struct redisServer { // AOF缓冲区, 在进入事件loop之前写入 sds aof_buf; };
命令传播: Redis将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中
缓存追加: AOF程序根据接收到的命令命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存
条件被满足的话,fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。
为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。
AOF保存模式:
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入AOF重写机制压缩文件体积,AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。
重写后的AOF文件为什么可以变小?
AOF重写可以手动触发也可以自动触发:
流程说明:
1)执行AOF重写请求。
如果当前进程正在执行AOF重写,请求不执行。
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行。
2)父进程执行fork创建子进程,开销等同于bgsave过程。
3.1)主进程fork操作完成后,继续响应其它命令。
所有修改命令依然写入AOF文件缓冲区并根据appendfsync策略同步到磁盘,保证原有AOF机制正确性。
3.2)由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据
由于父进程依然响应命令,Redis使用“AOF”重写缓冲区保存这部分新数据,防止新的AOF文件生成期间丢失这部分数据。
4)子进程依据内存快照,按照命令合并规则写入到新的AOF文件。
每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞。
5.1)新AOF文件写入完成后,子进程发送信号给父进程,父进程调用一个信号处理函数,并执行以前操作更新统计信息。
5.2)父进程把AOF重写缓冲区的数据写入到新的AOF文件。这时新 AOF 文件所保存的数据库状态将和服务器当前的数据库状态一致。
5.3)对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧文件的替换。
在整个 AOF 后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,其他时候,AOF 后台重写都不会阻塞父进程,这将 AOF 重写对服务器性能造成的影响降到了最低
流程说明:
1)AOF持久化开启且存在AOF文件时,优先加载AOF文件。
2)AOF关闭或者AOF文件不存在时,加载RDB文件。
3)加载AOF/RDB文件成功后,Redis启动成功。
4)AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。
数据还原的详细步骤:
加载损坏的AOF文件会拒绝启动,并打印错误信息。
注意:对于错误格式的AOF文件,先进性备份,然后采用redis-check-aof --fix
命令进行修复,修复后使用diff -u对比数据差异,找到丢失的数据,有些可以进行人工补全。
AOF文件可能存在结尾不完整的情况,比如机器突然掉电导致AOF尾部文件命令写入不全。
Redis为我们提高了aof-load-truncated
配置来兼容这种情况,默认开启