Redis数据持久化总结笔记
Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以 Redis 提供了持久化功能!
Redis 提供了 2 个不同形式的持久化方式
-
RDB(Redis DataBase)
-
AOF(Append Of File)
1.RDB
1.1 RDB(Redis DataBase)介绍
在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里
Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失
Fork
-
Fork 的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
-
在 Linux 程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会 exec 系统调用,出于效率考虑,Linux 中引入了“写时复制技术”
-
一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程
我们默认的就是RDB,一般情况下不需要修改这个配置!
有时候在生产环境我们会将这个文件进行备份!rdb保存的文件是dump.rdb 都是在我们的配置文件中快照中进行配置的!
1.2 触发机制
-
配置文件中默认的快照配置
-
手动save/bgsave命令
-
执行flushdb/fulshall命令也会产生dump.rdb文件,但是也会将命令记录到dump.rdb文件中,恢复后依旧是空,无意义
-
执行shutdown且没有设置开启AOF持久化
-
主从复制时,主节点自动触发
如何检查修复dump.rdb文件?
进入到redis安装目录,执行redis-check-rdb命令
redis-check-rdb ./redisconfig/dump.rdb
1.3 RDB 持久化流程
1.4 配置文件设置
# 1. dump.rdb 文件 可以修改默认名称
dbfilename dump.rdb
# 2.dump.rdb 文件存放位置 rdb 文件的保存路径,也可以修改。默认为 Redis 启动时命令行所在的目录下
dir "/"
# 3. redis6 默认的快照配置 自动触发
# 格式:save 秒钟 写操作次数
save 900 1 # 15 分钟内改了 1 次
save 300 10 # 5 分钟内改了 10 次
save 60 10000 # 1 分钟内改了 1 万次
# 3. redis7 默认的快照配置 自动触发 表示在 <seconds> 秒内,如果数据有 <changes> 次修改,则会进行一次快照
# 引入了按时间和数据修改次数双重限制的快照保存机制
save <seconds> <changes>
# 4. 当 Redis 无法写入磁盘的话,直接关掉 Redis 的写操作。推荐 yes
stop-writes-on-bgsave-error yes
# 5.rdb文件压缩文件
# 对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis 会采用LZF 算法进行压缩。
# 如果你不想消耗 CPU 来进行压缩的话,可以设置为关闭此功能。推荐 yes
rdbcompression yes
# 6.rdb文件 检查完整性
# 在存储快照后,还可以让 redis 使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
# 推荐 yes
rdbchecksum yes
# 在没有持久化的情况下删除复制中使用的RDB文件。默认情况下no,此选项是禁用的
rdb-del-sync-files no
命令 save VS bgsave
save :在主程序中执行会阻塞当前redis服务器,直到持久化工作完成,执行save命令期间,Redis不能处理其他命令,线上禁止使用
bgsave:redis会在后台异步进行快照操作,不阻塞快照同时还可以相应客户端请求,该触发方式会fork一个子进程由子进程复制持久化过程
lastsave: 可以通过 lastsave 命令获取最后一次成功执行快照的时间
1.5 rdb的备份与还原
备份
-
先通过 config get dir 查询 rdb 文件的目录
-
将*.rdb 的文件拷贝到别的地方 一定要将服务产生的RDB文件备份一份,然后分机隔离,避免生产上物理损坏后备份文件也挂了
还原
-
关闭 Redis
-
先把备份的文件拷贝到redis启动目录下,redis启动的时候会自动检查dump.rdb 恢复其中的数据! cp dump2.rdb dump.rdb
-
启动 Redis, 备份数据会直接加载
1.6 rdb优势与劣势
rdb优势
-
适合大规模的数据恢复
-
按照业务定时备份
-
对数据完整性和一致性要求不高更适合使用
-
节省磁盘空间
-
恢复速度快,RDB文件在内存中的加载速度要比AOF快很多
rdb劣势
-
Fork 的时候,内存中的数据被克隆了一份,大致 2 倍的膨胀性需要考虑
-
虽然 Redis 在 fork 时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
-
在备份周期在一定间隔时间做一次备份,所以如果 Redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。
1.7 动态停止 RDB
动态停止 RDB
redis-cli config set save ""
手动修改配置
save ""
1.8总结
2.AOF
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
2.1 AOF 持久化流程
-
1.Client作为命令的来源,会有多个源头以及源源不断的请求命令。
-
2.在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
-
3.AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件。
-
4.随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称AOF重写),从而起到AOF文件压缩的目的。
-
5.当Redis Server服务器重启的时候会队AOF文件载入数据。
AOF缓冲区三种写回策略
ALways:同步写回,每个写命令执行完立刻同步地将日志写入磁盘
everysec:每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入到磁盘
no:操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
AOF 和 RDB 同时开启,系统默认取 AOF 的数据(数据不会存在丢失)
2.2 配置文件设置
# 1. 开启 AOF
appendonly yes
# 2. redis6 aof文件的名称设置 只有一个 Redis7 Multi Part AOF的设计 有三个
appendfilename "appendonly.aof"
# 保存路径
# 3. redis6 AOF保存文件的位置和RDB保存文件的位置一样,都是通过redis.conf配置文件的dir配置
dir /myredis
# redis 7 aof文件保存的路劲是在/myredis文件下创建appenddirname设置的文件夹下保存 dir + appenddirname
appenddirname 文件名称
# 4.同步频率设置
# 始终同步,每次 Redis 的写入都会立刻记入日志;性能较差但数据完整性比较好
# appendfsync always
# 每秒同步 推荐,每秒记入日志一次,如果宕机,本秒的数据可能丢失 每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区中的内容写入到磁盘
appendfsync everysec
# redis 操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
# appendfsync no
Redis7 Multi Part AOF的设计
aof文件从1个文件到3个文件
MP-AOF实现 方案概述 顾名思义,MP-AOF就是将原来的单个AOF文件拆分成多个AOF文件。在MP-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配置(Redis 7.0新增配置项)决定。
Redis7.0 config 中对应的配置项
2.3 AOF 重写
AOF 采用文件追加方式,文件会越来越大 为避免出现此种情况,新增了重写机制,
当AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令 bgrewriteaof
一句话:启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
AOF重写不仅降低了文件的占用空间,同时更小的AOF也可以更快地被Redis加载。
重写原理
AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写(也是先写临时文件最后再 rename)
# 不写入 aof 文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
no-appendfsync-on-rewrite:yes
# 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)
no-appendfsync-on-rewrite:no
触发机制,何时重写
Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发
重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,
因此设定 Redis 要满足一定条件才会进行重写。
# 设置重写的基准值,文件达到 100%时开始重写(文件是原来重写后文件的 2 倍时触发)
auto-aof-rewrite-percentage:100
# 设置重写的基准值,最小文件 64MB。达到这个值开始重写。
auto-aof-rewrite-min-size:64mb
触发方式
-
自动触发 满足配置文件中的选项后,Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时
-
手动触发 客户端向服务器发送bgrewriteaof命令
重写流程
-
bgrewriteaof 触发重写,判断是否当前有 bgsave 或 bgrewriteaof 在运行,如果有,则等待该命令结束后再继续执行
-
主进程 fork 出子进程执行重写操作,保证主进程不会阻塞
-
子进程遍历 redis 内存中数据到临时文件,客户端的写请求同时写入 aof_buf 缓冲区和 aof_rewrite_buf 重写缓冲区保证原 AOF 文件完整以及新 AOF 文件生成期间的新的数据修改动作不会丢失
-
子进程写完新的 AOF 文件后,向主进程发信号,父进程更新统计信息 主进程把 aof_rewrite_buf 中的数据写入到新的 AOF 文件
-
使用新的 AOF 文件覆盖旧的 AOF 文件,完成 AOF 重写。
2.4 AOF 修复/恢复
AOF 的备份机制和性能虽然和 RDB 不同, 但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载
正常恢复
-
修改默认的 appendonly no,改为 yes
-
将有数据的 aof 文件复制一份保存到对应目录(查看目录:config get dir)
-
恢复:重启 redis 然后重新加载
异常恢复
-
修改默认的 appendonly no,改为 yes
-
如遇到 AOF 文件损坏,通过/usr/local/bin/redis-check-aof--fix appendonly.aof 进行恢复
-
备份被写坏的 AOF 文件
-
恢复:重启 redis,然后重新加载
2.5 优缺点
优势
-
使用AOF Redis 更加持久:您可以有不同的fsync 策略,根本不fsync、每秒 fsync、每次查询时fsync。使用每秒fsync的默认策略,写入性能仍然很棒。fsync 是使用后台线程执行的,当没有fsync正在进行时,主线程将努力执行写入,因此您只能丢失一秒钟的写入。
-
AOF 日志是一个仅附加日志,因此不会出现寻道问题,也不会在断电时出现损坏问题。即使由于某种原因(磁盘已满或其他原因) 日志以写一半的命令结尾,redis-check-aof 工具也能够轻松修复它。
-
当AOF 变得太大时,Redis 能够在后台自动重写AOF。重写是完全安全的,因为当 Redis继续附加到旧文件时,会使用创建当前数据集所需的最少操作集生成一个全新的文件,一旦第二个文件准备就绪,Redis 就会切换两者并开始附加到新的那一个
-
AOF以易于理解和解析的格式依次包含所有操作的日志。您甚至可以轻松导出AOF文件。例如,即使您不小心使用孩FLUSHALL命令刷新了所有内容,只要在此期间没有执行日志重写,您仍然可以通过停止服务器、删除最新命令并重新启动 Redis 来保存您的数据集。
劣势
-
比起 RDB 占用更多的磁盘空间
-
恢复备份速度要慢
-
每次读写都同步的话,有一定的性能压力
-
存在个别 Bug,造成恢复不能
2.6 总结
3.RDB与AOF比较
官方推荐两个都启用。
如果对数据不敏感,可以选单独用 RDB。
不建议单独用 AOF,因为可能会出现 Bug。
如果只是做纯内存缓存,可以都不用
扩展:
1、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储
2、AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis 协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写(命令合并),使得AOF文件的体积不至于过大。
3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化
4、同时开启两种持久化方式 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。 RDB 的数据不实时,同时使用两者时服务器重启也只会找AOF文件
那要不要只使用AOF呢?建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有 AOF可能潜在的Bug,留着作为一个万一的手段。
5、性能建议
因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够 了,只保留 save 900 1 这条规则。
如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据, 启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。
4.RDB-AOF混合持久化
Redis配置文档解答:RDB和AOF共存时会优先加载AOF文件
数据恢复顺序和加载流程
你怎么选?用哪个?
-
RDB持久化方式能够在指定的时间间隔对你的数据进行快照存储。
-
AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。
同时开启两种持久化方式
-
在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
-
RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。但是作者也不建议只使用AOF方式备份,因为RDB更适合用于备份数据库(AOF在不断的变化不好备份),留着RDB作为一个万一的手段
推荐方式
RDB+AOF混合方式
-
开启混合方式设置 设置aof-use-rdb-preamble的值为yes, yes表示开启,设置为no表示禁用
-
RDB+AOF的混合方式--------->结论:RDB镜像做全量持久化,AOF做增量持久化 先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----》AOF包括了RDB头部+AOF混写
5.最后
感谢大家,请大家多多支持!