🎈 持久化策略
RDB(内存快照)
AOF(追加文件)
🎈 RDB
-
内存快照(默认开启)
-
就是把某一时刻的数据和状态以文件的方式写到磁盘上,就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
-
这个快照文件称为 RDB 文件(dump.rdb),其中,RDB 就是 Redis DataBase 的缩写
分为自动触发和主动触发
-
自动触发:通过服务端的配置文件(redis.conf)指定触发 RDB 条件,本质是通过达到一定条件后自动触发持久化,这个条件规则就是 M 秒内 N 个 key 发生了变化。
-
主动触发:
save
和bgsave
命令让服务器生成 rdb 文件;
1、redis.conf 配置文件
#是否压缩rdb文件
rdbcompression yes
#rdb文件的名称
dbfilename redis-6379.rdb
#rdb文件保存目录,物理恢复,一定服务和备份分级隔离
dir ~/redis/
2、save
save 命令是同步操作,同步数据到磁盘上,阻塞
-
当客户端向服务器发送 save 命令请求进行持久化时,服务器会阻塞 save 命令之后的其他客户端的请求,直到数据同步完成
-
如果数据量太大,同步数据会执行很久,而这期间 Redis 服务器也无法接收其他请求,所以,最好不要在生产环境使用
save
命令。
3、bgsave
bgsave 命令是异步操作,异步将数据同步到磁盘上,不阻塞
-
当客户端发服务发出 bgsave 命令时,Redis 服务器主进程会 forks 一个子进程来数据同步,在将数据保存到 rdb 文件之后,子进程会退出。
-
所以,与 save 命令相比,Redis 服务器在处理 bgsave 采用子线程进行 IO 写入,而主进程仍然可以接收其他请求,但 forks 子进程是同步的,所以 forks 子进程时,一样不能接收其他请求,这意味着,如果 forks 一个子进程花费的时间太久(一般是很快的),bgsave 命令仍然有阻塞其他客户的请求的情况发生
fork:在 Linux 系统中,调用 fork() 时,会创建出一个新进程,称为子进程,子进程会拷贝父进程的 page table。如果进程占用的内存越大,进程的 page table 也会越大,那么 fork 也会占用更多的时间。如果 Redis 占用的内存很大,那么在 fork 子进程时,则会出现明显的停顿现象
4、哪些情况会触发 RDB 快照
-
配置文件中默认的快照配置(redis.conf);
-
手动
save
和bgsave
命令; -
执行
flushall/flushdb
命令也会产生 dump.rdb 文件,但是里面是空的,无意义; -
执行
shutdown
且没有设置开启 AOF 持久化; -
主从复制时,主节点自动;
5、快照生成期间, 数据被修改了, 怎么同步最新的数据
Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作, 新写的数据会 copy 一份副本出来, 最终写进 RDB 中
6、RDB 文件生成流程
-
生成临时 rdb 文件,并写入数据。
-
完成数据写入,用临时文代替代正式 rdb 文件。
-
删除原来的 rdb 文件。
7、怎么禁用快照
使用命令:redis-cli config set save""
8、其他配置文件了解
#默认yes #如果配置成no,表示你不在乎数据不一致或者其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确 #保redis继续接受新的请求 stop-writes-on-bgsave-error yes #默认yes #对于存储到磁盘中的快照,可以设置是否进行压缩存储,如果是的话,redis会采用LZF算法进行压缩。如果你不想 #消耗CPU来进行压缩的话,可以设置为关闭此功能 rdbcompression yes #默认yes #在存储快照后,还可以让redis使用CRC64算法进行数据效验,但是这样做会增加大约10%的性能消耗。如果希望获取#到最大的性能提升,可以关闭此功能 #在没有持久性的情况下删除复制中使用的RDB文件启用。默认情况下no,此选项是禁用的。 rdb-del-sync-files
9、优点和缺点
✔优点:
-
与 AOF 方式相比,通过 rdb 文件恢复数据比较快。(因为是二进制压缩文件)
-
rdb 文件非常紧凑,适合于数据备份。(因为是二进制压缩文件)
❌缺点:
-
如果服务器宕机的话,采用 RDB 的方式会造成某个时段内数据的丢失,比如我们设置 10 分钟同步一次或 5 分钟达到 1000 次写入就同步一次,那么如果还没达到触发条件服务器就死机了,那么这个时间段的数据会丢失。
-
使用 save 命令会造成服务器阻塞,直接数据同步完成才能接收后续请求。
-
使用 bgsave 命令在 forks 子进程时,如果数据量太大,forks 的过程也会发生阻塞,另外,forks 子进程会耗费内存。
10、注意和补充
❓怎么恢复:
-
将备份文件(dump.rdb)移动到 redis 安装目录并启动服务即可
❗注意:
-
不可以把备份文件 dump.rdb 和生产 redis 服务器放在同一台机器,必须分开各自存储,以防上产机物理损坏后备份文件也挂了
🔹其他:
-
可以通过
lastsave
命令获取最后一次成功执行快照的时间,值是时间戳 -
通过
date -d@时间戳
命令转换成日期格式
🎈 AOF
AOF 是 append olny file 的缩写
以日志的形式来记录每个写操作,将 Redis 执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,追加保存到以后缀 aof 文件的末尾(redis7 会有三个文件),在 redis 启动会读取该文件,会加载运行 aof 文件的命令,达到恢复数据的工作
AOF 持久化功能的实现可以分为三个步骤:命令追加、文件写入、文件同步
1、AOF 持久化流程
-
客户端作为命令的来源,会有多个源头以及源源不断的请求命令
-
在这些命令到达服务端以后并不是直接写入 AOF 文件,会将这些命令先放入 AOF 缓存中进行保存,这里的 AOF 缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后在写入磁盘,避免频繁的磁盘 IO 操作,这也就是为什么会有文件写入和文件同步俩个操作的主要原因
-
AOF 缓冲会根据 AOF 缓冲区同步文件的三种策略将命令写入磁盘的 AOF 文件
-
随着写入 AOF 内容的增加为了避免文件膨胀,会根据规则进行命令的合并(又称 AOF 重写),从而祈祷 AOF 文件压缩的目的
-
当 redis server 服务器重启的时候会从 AOF 文件载入数据
-
命令追加:服务器在执行完一个命令之后,会将执行的写命令追加到服务器状态的 AOF 缓冲区(aof_)的末尾
-
Linux 操作系统中为了提升性能,使用了页缓存(page cache)。当我们将 aof_buf 的内容写到磁盘上时,此时数据并没有真正的落盘,而是在 page cache 中,为了将 page cache 中的数据真正落盘,需要执行 fsync / fdatasync 命令来强制刷盘。这边的文件同步做的就是刷盘操作,或者叫文件刷盘可能更容易理解一些
2、开启 AOF 持久化
Redis 默认是不开启 AOF 持久化的,可以更改配置文件进行开启,如下面图中所示
3、三种写入策略
以上三种写入策略只是在不同时机去调用 OS 的 fsync()函数
-
Always
同步写回,每个写命令执行完立主线程就会执行 fsync()函数立刻同步地将日志写回磁盘 -
Everysec
每秒写回,每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔 1 秒把缓冲区中的内容写入磁盘,会创建一个异步线程来执行 fsync()函数 -
No
不执行 fsync()函数,执行 write()函数写入到 OS chache,至于什么时候刷盘,交给 OS 自己决定
-
write 只要把日志记录写到内核缓冲区,就返回了, 并不需要等待日志实际写回到磁盘;
-
fsync 需要把日志记录写回到磁盘后才能返回,时间较长。
4、Redis7.0 核心特性 AOF
MP-AOF 就是将原来的单个 AOF 文件拆分成多个 AOF 文件,主要分为三种类型
-
BASE:表示基础 AOF,它一般由子进程通过重写产生,该文件最多只有一个
-
INCR:表示增量 AOF,它一般会在 AOFRW 开始执行时被创建,该文件可能存在多个
-
HISTORY:表示历史 AOF,它有 BASE 和 INCR AOF 变化而来,每次 AOFRW 成功完成时,本次 AOFRW 之前对应的 BASE 和 INCR AOF 都将变为 HISTORY,HISTORY 类型的 AOF 会被 Redis 自动删除。
为了管理这些 AOF 文件,引入了一个 manifest(清单)文件来跟踪、管理这些 AOF。同时,为了便于 AOF 备份和拷贝,我们将所有的 AOF 文件和 manifest 文件放入一个单独的文件目录中,目录名有 appenddirname 配置
5、AOF 文件重写
-
由于 AOF 持久化是 Redis 不断将写命令记录到 AOF 文件中,随着 Redis 不断地进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求的时间越长
-
为了解决这个问题,Redis 新增了重写机制,当 AOF 文件的大小超过所制定的峰值时,Redis 就会自动启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集
-
同样也可以手动命令
bgrewriteaof
来重写
比如对一个 key 多次执行 incr 命令,这时候 aof 保存每一次命令到文件中,文件就会越来越大。
为了解决这个问题,Redis 支持 aof 文件重写,通过重写 aof,可以生成一个恢复当前数据的最少命令集,比如上面的例子中那么多条命令,可以重写为
5.1、重写的时机
-
默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍并且文件大于 64M 后
-
客户端向服务器发送
bgrewriteaof
命令
5.2、重写流程
AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。
-
在重写开始前,redis 会创建(fork)一个“重写子进程”,这个子进程会读取现有的 AOF 文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
-
与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的 AOF 文件中,这样做是保证原有的 AOF 文件的可用性,避免在重写过程中出现意外。
-
当"重写子进程"完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新 AOF 文件中,
-
当追加结束后,redis 就会用新 AOF 文件来代替旧 AOF 文件,之后再有新的写指令,就都会追加到新的 AOF 文件中了。
-
重写 AOF 文件的操作,并没有读取旧的 AOF 文件,而是将整个内存中的数据库内容用命令的方式重写一个新的 AOF 文件,这点和快照有点类似
5.3 AOF 后台重写存在的问题
❗问题:
AOF 后台重写使用子进程进行重写,解决了主进程阻塞的问题,但是仍然存在另一个问题:子进程在进行 AOF 重写期间,服务器主进程还需要继续处理命令请求,新的命令可能会对现有的数据库状态进行修改,从而使得当前的数据库状态和重写后的 AOF 文件保存的数据库状态不一致。
✔解决方案:
为了解决上述问题,Redis 引入了 AOF 重写缓冲区(aof_rewrite_buf_blocks),这个缓冲区在服务器创建子进程之后开始使用,当 Redis 服务器执行完一个写命令之后,它会同时将这个写命令追加到 AOF 缓冲区和 AOF 重写缓冲区。
6、怎么禁用 AOF
#禁用aof持久化模式下,我们仍然可以使用命令bgrewriteafo生成aof文件 appendonly no
7、AOF 优点
-
AOF 只是追加日志文件,因此对服务器性能影响较小,速度比 RDB 要快,消耗的内存较少
-
AOF 更加持久化,只会丢失一秒钟的写入
-
AOF 日志是一个仅附加日志,因此不会出现寻道问题,不会出现断电时出现损坏问题,即使由于某种原因日志以协议班的命令结尾,
redis-check-afo
工具也能够轻松修复它 -
AOF 重写机制,缩小内存
-
AOF 以易于理解和解析的格式依次包含所有操作的日志,甚至可以轻松导出 AOF 文件
-
即使不小心使用了 FLUSHALL 命令刷新了所有内容,只要在此期间没有执行日志重写,仍然可以通过停止服务器、删除最新命令并重新启动 Redis 来保存数据集
8、AOF 缺点
-
AOF 方式生成的日志文件太大,即使通过 AOF 重写,文件体积仍然很大。
-
恢复数据的速度比 RDB 慢,需要解析语句
-
如果配置的是 always 策略, 需要持久化成功后才返回成功, 性能更慢
🎈 混合持久化
一般生产环境采用新特性:混合持久化
1、描述
-
混合持久化并不是全新的持久化格式,而是对已有方式的优化,混合持久化只发生于 AOF 重写过程。使用了混合持久化,重写后的新 AOF 文件前半段是 RDB 格式的全量数据,后半段是 AOF 格式的增量数据。
-
整体格式:RDB file + AOF tail
-
结论:RDB 镜像做全量持久化,AOF 做增量持久化
-
白话:先使用 RDB 进行快照存储,然后使用 AOF 持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的 RDB 记录
2、开启
更给配置文件aof-use-rdb-preamble yes
开启混合持久化,在 redis4.0 刚引入时,默认是关闭混合持久化,redis5 中默认是开启的。
3、流程
-
混合持久化本质是通过 AOF 后台重写(bgrewriteaof 命令)完成的,不同的是当开启混合持久化时,fork 出的子进程先将当前全量数据以 RDB 方式写入新的 AOF 文件,然后再将 AOF 重写缓冲区(aof_rewrite_buf_blocks)的增量命令以 AOF 方式写入到文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。
-
在数据恢复过程中,如果 AOF 文件开始是 RDB 格式,则先加载 RDB 格式内容,再加载 AOF 格式内容。如果 AOF 文件开头不是 RDB 格式,则直接用 AOF 格式加载整个文件
🎈 持久化文件损坏
在写入 aof 日志文件时,如果 Redis 服务器宕机了,则 aof 日志文件会出现格式错误,在重启 Redis 服务器时,就会拒绝载入这个 aof 文件,同样 rdb 文件也可能出现损坏。
✔解决方案:
-
备份现在的 aof 和 rdb 文件以防万一
-
通过
redis-check-rdb
命令可以修改损坏的 rdb 文件(在 redis 安装 bin 目录下) -
通过
redis-check-aof -fix file.aof
命令可以修改损坏的 aof 文件(在 redis 安装 bin 目录下)
🎈 RDB 和 AOF 总结
-
RDB 优点:采用⼦进程生成 RDB ⽂件,减少对 Redis 主线程的阻塞,保证 Redis 性能;RDB 是内存快照,恢复效率⾼。
-
RDB 不⾜:RDB 是间隔⼀段时间⽣成⼀次,两次 RDB 创建之前,如果 Redis 发⽣故障,会发⽣数据丢失。
-
AOF 优点:采用 always 配置项时,可以每个命令做⼀次持久化,可靠性相比 RDB 更⾼。
-
AOF 不足:AOF ⽂件较⼤,会触发 AOF 重写,重写时会竞争内存资源;AOF 恢复是回放命令操作,恢复速度慢于 RDB。
当 RDB 与 AOF 两种方式都开启时,Redis 会优先使用 AOF 日志来恢复数据,因为 AOF 保存的文件比 RDB 文件更完整