很多小伙伴都用 Redis 做缓存,那如果 Redis 服务器宕机,内存中数据全部丢失,应该如何做数据恢复呢?有人说很简单呀,直接从 MySQL 数据库再读回来就得了。
这种方式存在两个问题:一是频繁访问 MySQL 数据库,有一定的风险;二是慢,从界面上来看,从 MySQL 读就不如从 Redis 快。
远哥远哥,那咋办呀?教教我吧。
我用中指抵着小胖的下吧,说到:傻瓜,我们可以做持久化呀。Redis 的持久化分两种,一种是 AOF,另一种是 RDB。来,坐哥哥腿上,我给你好好说道说道。
老规矩先上张脑图:
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML 数据文件中等等。持久化是将程序数据在持久状态和瞬时状态间转换的机制。
必须声明一点:Redis 的单线程,是指 Redis 的网络 IO 和键值对读写是由一个线程(主线程)完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
基于内存
高效的数据结构
合理的线程模型
I/O 多路复用模型同时监听多个客户端连接;
单线程在执行过程中不需要进行上下文切换,减少了耗时。
AOF(Append Only File) 持久化是通过保存 Redis 服务器所执行的写命令来记录数据库状态,也就是每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。
修改 redis.conf 配置文件,默认是 appendonly no(关闭状态),将 no 改为 yes 即可开启 AOF 持久化:
appendonly yes
在客户端输入如下命令也可,但是 Redis 服务器重启后会失效。
192.168.17.101:6379> config set appendonly yes
OK
AOF 持久化功能的实现可以分为命令追加(append)、文件写回磁盘两个步骤。
AOF 持久化功能开启时,Redis 在执行完一个写命令之后,会将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾,此时缓冲区的记录还没有写入到 appendonly.aof 文件中。
AOF 保存的是 Redis 的写命令,比如:执行命令set testkey testvalue,它存储的内容如下图所示:
其中,“*3” 表示当前命令有三个部分,每部分都是由 $+数字开头,后面紧跟着具体的命令、键或值。这里,数字表示这部分中的命令、键或值一共有多少字节。例如,$3 set 表示这部分有 3 个字节,也就是set命令。
AOF 记录日志的方式被称为写后日志,也就是先执行命令再记录,而 MySQL 中的 redo log、binlog 等都是写前日志。它的写入流程是下图这样的:
写后有什么优点?
写后有什么缺陷?
你发现没有?写后的两个缺陷都是 AOF 的写入磁盘时相发生的,我们来看看它是怎么写入的呢?
AOF 提供了三个选择,也就是 AOF 配置项 appendfsync 的三个可选值。
Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
Everysec(默认),每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
针对避免主线程阻塞和减少数据丢失问题,这三种写回策略都无法做到两全其美。主要原因是:
总结一下就是:想高性能,选择 No 策略;想高可靠性,选择 Always 策略;允许数据有一点丢失,又希望性能别受太大影响,选择 Everysec 策略。
不说了,看图:
我不知道你发现没有?AOF 文件是不断地将写命令追加到文件的末尾来记录数据库状态的。写命令不断增加,AOF 体积也越来越大。
有些命令是执行多次更新同一条数据,但其实它是可以合并成同一条命令的。比如:LPUSH 对列表数据做了 6 次更改,但 AOF 只需要记录最后一次更改。因为日志恢复时,只需要执行最后一次更改的命令即可。
为了处理这种情况,Redis 提供了 AOF 的重写机制。它的多变一功能,把 6 条写命令合并成一条。如下所示:
如果你的某些键有成百上千次的修改,重写机制节约的空间就很可观了。
有两种触发的方法,一个是调用命令 BGREWRITEAOF;一个是修改配置文件参数。
# 方式一
192.168.17.101:6379> BGREWRITEAOF
Background append only file rewriting started
# 方式二
auto-aof-rewrite-percentage 100 #当前AOF文件大小和上一次重写时AOF文件大小的比值
auto-aof-rewrite-min-size 64mb #文件的最小体积
# 是否开启AOF功能
appendonly no
# AOF文件件名称
appendfilename "appendonly.aof"
# 写入AOF文件的三种方式
appendfsync always
appendfsync everysec
appendfsync no
# 重写AOF时,是否继续写AOF文件
no-appendfsync-on-rewrite no
# 自动重写AOF文件的条件
auto-aof-rewrite-percentage 100 #百分比
auto-aof-rewrite-min-size 64mb #大小
# 是否忽略最后一条可能存在问题的指令
aof-load-truncated yes
RDB 持久化是指在客户端输入 save、bgsave
或者达到配置文件自动保存快照条件时,将 Redis 在内存中的数据生成快照保存在名字为 dump.rdb
(文件名可修改)的二进制文件中。
save 命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在 Redis 服务器阻塞期间,服务器不能处理任何命令请求。 在客户端输入 save
127.0.0.1:6379> save
OK
快照生成完毕,会弹出 DB saved ondisk 的提示。
1349:M 25 Apr 13:16:48.935 * DB saved on disk
bgsave 执行时,主线程会创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
127.0.0.1:6379> bgsave
Background saving started
PS:bgsave 命令执行期间 SAVE 命令会被拒绝;不能同时执行两个 BGSAVE 命令;不能同时执行 BGREWRITEAOF 和 BGSAVE 命令。
bgsave 执行时,Redis 主线程能正常读写数据。读操作时,主线程和 bgsave 子线程互不影响;写操作时,Redis 会利用写时复制技术(Copy-On-Write, COW),生成被修改数据的副本。然后 bgsave 子线程把副本数据写入 RDB。
比如,bgsave 期间,主线程修改键值对 C,过程如下:
但是在这过程中发生宕机了咋办?比如,T0 时刻做了一次快照,T0+t 时刻又做了一次。但是 t 时间内主线程修改完数据 5 和 9,然后 Redis 宕机了,RDB 没记录到修改后的数据。
Redis 重启恢复数据,就会出现数据 5 和 9 丢失的情况,没办法恢复。
这该咋办?我们需要记住那些数据被修改了。
如下图所示,记录 t 时刻被修改的数据就需要占用额外的空间,而 Redis 是内存数据库,空间非常宝贵。所以,直接记录到内存这种方式不可取。
内存开销比较小的方法是把 t 时间的增量写操作记录到 AOF 日志中,这样既保留了 RDB 的快速恢复,也没占用额外的空间。
如图,T1 和 T2 时刻的修改,用 AOF 日志记录,等第二次做全量快照时,清空 AOF 日志,因为此时的修改都记录到快照中了,恢复不用 AOF 日志了。
庆幸的是 Redis 4.0 就开始提供了这种RDB + AOF 的持久化方式,开启的配置项是aof-use-rdb-preamble yes
,它需要配合 AOF 的重写机制实现。
# 开启混合持久化
redis> config set aof-use-rdb-preamble yes
OK
# AOF 重写
redis> BGREWRITEAOF
Background append only file rewriting started
在没有第二次做全量快照之前,它的格式是这样的:前半部分是 RDB 格式,后半部分是 AOF 增量日志。如果这个时候宕机,直接拿 appendonly.aof 恢复数据。
本文主要讲解 Redis AOF 、RDB持久化的原理和两者的优缺点,对比两者后,我还给你总结了 Redis 混合持久化的流程。最后给了你一些选择持久化方案的建议,希望看完你能有所收获。
全文将近五千字,12张图,希望能帮到你。好啦,以上就是狗哥关于 Redis 持久化的总结。感谢各技术社区大佬们的付出,尤其是极客时间,真的牛逼。如果说我看得更远,那是因为我站在你们的肩膀上。希望这篇文章对你有帮助,我们下篇文章见~
如果看到这里,喜欢这篇文章的话,请帮点个好看。
初次见面,也不知道送你们啥。干脆就送几百本电子书和2021最新面试资料吧。微信搜索一个优秀的废人回复电子书送你 1000+ 本编程电子书;回复面试送点面试题;回复1024送你一套完整的 java 视频教程。
面试题都是有答案的,如下所示:有需要的就来拿吧,绝对免费,无套路获取。
巨人的肩膀
原文:https://www.cnblogs.com/nasus/p/14702756.html