redis持久化方式(原理 + 例子 + 动图演示)
redis的持久化方式详解
虽然是redis是基于内存的数据库,但是这并不代表着关机之后,redis的数据就会全部消失;因为redis还有自己特有的持久化方式。
redis可以根据设置的不同采用不同的持久化方式将内存中的数据持久化到磁盘;只要磁盘的数据不丢失,redis的数据就可以再现。
下面我们一起来学习下redis的两种持久化方式:
一、AOF
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
在这里有一点需要特别提出的就是,客户端发出的操作命令是先在内存成功执行后,才会记录到AOF文件中。
这是为什么呢?
想想下面这个场景你自然就懂了。
假如是先写进AOF文件,在到内存执行的话,如果是一些语法有误的命令,它就会先被记录到AOF文件中持久化,再到内存中执行,因为语法有误,所以redis报错,该命令无法执行。
此时的问题就是,AOF有记录了多余且没用的记录,这种记录霸占和浪费了AOF文件的有限空间。
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
配置项 | 刷盘时机 | 优点 | 缺点 |
---|---|---|---|
Always | 同步刷盘 | 可靠性高,几乎不丢数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最多丢失1秒数据 |
对AOF记录格式的解读:
一般来说,每一个写命令都包含以上三个部分,比如第一个“$3"它是表示 “set”有 3 个字节。
AOF的重写机制
因为AOF是记录命令用于恢复数据的,而且AOF文件的大小有限,所以在AOF文件中的数据达到一定的阈值的时候,就会除法AOF重写。
AOF重写本质上是将记录复制到新的AOF文件中并用新的AOF文件代替旧的AOF文件的过程。
但是这个记录复制并不是全部都复制,它的复制有一定的讲究——对于操作同一个记录的命令只复制最新的命令。
因为在redis的运行过程中,有可能对同一个地方进行了多次修改,这多次修改的命令都会被记录在AOF文件中,因为AOF文件是用来恢复数据的,之前的命令已经被新的命令覆盖了的,所以在新的AOF文件中只需要记录对该记录操作的最新命令即可。
二、RDB
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
快照文件称为RDB文件,默认是保存在当前运行目录。
触发RDB的机制
到 redis.conf文件中进行以下设置:
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000
当然啦,在redis.conf文件中还可以进行其他配置:
# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes
# RDB文件名称
dbfilename dump.rdb
# 文件保存的路径目录
dir ./
redis中提供了两个命令来生成RDB文件,命令分别是save、 bgsave。
- save命令是让主进程来生成RDB文件的,此时主进程阻塞
- bgsave命令是会fork一个子进程来生成RDB的,主进程不会阻塞
假如此时执行的命令是bgsave,而这时候主线程进行数据修改,就触发了写时复制:
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件
fork采用的是copy-on-write技术:
•当主进程执行读操作时,访问共享内存;
•当主进程执行写操作时,则会拷贝一份数据,执行写操作。
写时复制动图演示:
- 子进程和主进程共享内存中的数据(同一份页表)
- 假如子进程和主进程都是只读数据的话,则不存在问题
- 假如此时主进程执行的是写操作的话,就会对该数据进行copy得到该数据的副本,主进程的写操作则在副本上执行(这个副本只有在下一次bgsave的时候才会被持久化到RDB中)
如果要将副本也同时持久化的话,应该怎么做呢?
这时候应该考虑的就是AOF和RDB的混合使用了。
混合持久化
在配置文件中,打开以下设置
aof-use-rdb-preamble yes
经过以上设置之后,redis中的混合持久化模式将被打开,在AOF重写的时候,fork出来的子进程会以 RDB 的方式将共享的数据写入到 AOF 文件中,接着假如这时候,主线程执行了写命令,该命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,待所有写入完成后,在将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件,就完成了一次redis数据的持久化。
简单点来说:
- 子进程将共享数据记录到AOF文件中(之前是RDB文件)
- 假如这时候主进程需要执行写命令,则该命令进入重写缓冲区(前面提到了AOF重写是将一个文件的数据复制到另外一个文件,而这个过程中会经历一个重写缓冲区);这时候主进程的那个命令就像之前就记录在旧的AOF文件中一样,和旧的AOF文件中的数据一起复制到新的AOF文件中
- 所以这个新的AOF文件,前面一部分是RDB格式的,后面部分是AOF格式的。
转载自:https://juejin.cn/post/7130635668459356196