00 前言
很多小伙伴都用 Redis 做缓存,那如果 Redis 服务器宕机,内存中数据全副失落,应该如何做数据恢复呢?有人说很简略呀,间接从 MySQL 数据库再读回来就得了。
这种形式存在两个问题:一是频繁拜访 MySQL 数据库,有肯定的危险;二是慢,从界面上来看,从 MySQL 读就不如从 Redis 快。
远哥远哥,那咋办呀?教教我吧。
我用中指抵着小胖的下吧,说到:傻瓜,咱们能够做长久化呀。Redis 的长久化分两种,一种是 AOF,另一种是 RDB。来,坐哥哥腿上,我给你好好说道说道。
老规矩先上张脑图:
0.1 什么是长久化?
长久化(Persistence),即把数据(如内存中的对象)保留到可永恒保留的存储设备中(如磁盘)。长久化的次要利用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML 数据文件中等等。长久化是将程序数据在长久状态和刹时状态间转换的机制。
0.2 往期精彩
1、小胖问我:select 语句是怎么执行的?
2、女朋友问我:MySQL 索引的原理是怎么的?
3、小胖问我:MySQL 日志到底有啥用?
4、老王问我:MySQL 事务与 MVCC 原理是怎么的?
5、女朋友问我:MySQL 的锁机制是怎么的?
6、万字长文,38 图爆肝 Redis 根底!
01 怎么了解 Redis 的单线程?
必须申明一点:Redis 的单线程,是指 Redis 的网络 IO 和键值对读写是由一个线程(主线程)实现的,这也是 Redis 对外提供键值存储服务的次要流程。但 Redis 的其余性能,比方长久化、异步删除、集群数据同步等,其实是由额定的线程执行的。
1.0 Redis 快的起因?
基于内存
- 数据都存储在内存里,缩小了一些不必要的 I/O 操作,操作速率很快。
高效的数据结构
- 底层多种数据结构反对不同的数据类型,反对 Redis 存储不同的数据;
- 不同数据结构的设计,使得数据存储工夫复杂度降到最低。
正当的线程模型
- I/O 多路复用模型同时监听多个客户端连贯;
- 单线程在执行过程中不须要进行上下文切换,缩小了耗时。
02 AOF 长久化
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 yesOK
AOF 长久化性能的实现能够分为命令追加(append)、文件写回磁盘两个步骤。
2.0 命令追加
AOF 长久化性能开启时,Redis 在执行完一个写命令之后,会将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的开端,此时缓冲区的记录还没有写入到 appendonly.aof 文件中。
2.0.1 AOF 的格局
AOF 保留的是 Redis 的写命令,比方:执行命令set testkey testvalue,它存储的内容如下图所示:
其中,“*3” 示意以后命令有三个局部,每局部都是由 $+数字**结尾,前面紧跟着具体的命令、键或值。这里,**数字**示意这部分中的命令、键或值一共有多少字节。例如,**$3 set 示意这部分有 3 个字节,也就是set命令。
2.0.2 写后日志有啥优缺点?
AOF 记录日志的形式被称为写后日志,也就是先执行命令再记录,而 MySQL 中的 redo log、binlog 等都是写前日志。它的写入流程是下图这样的:
写后有什么长处?
- 记录 AOF 时不会对命令进行语法查看 ,写后就只记录了执行胜利的命令。(防止保留的谬误的命令,复原的时候就完犊子了)
- 执行完之后再记录,不会阻塞以后的写操作
写后有什么缺点?
- 如果执行完一个命令还没来得及写日志就宕机了会造成响应数据失落。
- AOF 的写入由主线程解决,如果写入时呈现较长耗时,那就会影响主线程解决后续的申请。
你发现没有?写后的两个缺点都是 AOF 的写入磁盘时相产生的,咱们来看看它是怎么写入的呢?
2.1 AOF 写入磁盘
AOF 提供了三个抉择,也就是 AOF 配置项 appendfsync 的三个可选值。
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec(默认),每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统管制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
2.1.0 三种策略的优缺点
针对防止主线程阻塞和缩小数据失落问题,这三种写回策略都无奈做到两败俱伤。次要起因是:
- Always(同步写回) 根本不丢数据,然而它在每一个写命令后都有一个慢速的落盘操作,影响主线程性能;
- No(操作系统管制的写回)在写完缓冲区后,继续执行后续的命令,然而落盘的机会曾经不在 Redis 手中了,只有 AOF 记录没有写回磁盘,一旦宕机对应的数据就失落了;
- Everysec(每秒写回)采纳一秒写回一次的频率,防止了 Always 的性能开销,尽管缩小了对系统性能的影响,然而如果产生宕机,上一秒内未落盘的命令操作依然会失落。
总结一下就是:想高性能,抉择 No 策略;想高可靠性,抉择 Always 策略;容许数据有一点失落,又心愿性能别受太大影响,抉择 Everysec 策略。
2.2 AOF 复原数据
不说了,看图:
2.3 AOF 重写
我不晓得你发现没有?AOF 文件是一直地将写命令追加到文件的开端来记录数据库状态的。写命令一直减少,AOF 体积也越来越大。
有些命令是执行屡次更新同一条数据,但其实它是能够合并成同一条命令的。比方:LPUSH 对列表数据做了 6 次更改,但 AOF 只须要记录最初一次更改。因为日志复原时,只须要执行最初一次更改的命令即可。
为了解决这种状况,Redis 提供了 AOF 的重写机制。它的多变一性能,把 6 条写命令合并成一条。如下所示:
如果你的某些键有成千盈百次的批改,重写机制节约的空间就很可观了。
2.3.1 触发重写
有两种触发的办法,一个是调用命令 BGREWRITEAOF;一个是批改配置文件参数。
# 形式一192.168.17.101:6379> BGREWRITEAOFBackground append only file rewriting started# 形式二auto-aof-rewrite-percentage 100 #以后AOF文件大小和上一次重写时AOF文件大小的比值auto-aof-rewrite-min-size 64mb #文件的最小体积
2.3.2 重写步骤
- 创立子过程进行 AOF 重写
- 将客户端的写命令追加到 AOF 重写缓冲区
- 子过程实现 AOF 重写工作后,会向父过程发送一个信号
- 父过程接管到信号后,将 AOF 重写缓冲区的所有内容写入到新 AOF 文件中
- 对新的 AOF 文件进行改名,笼罩现有的 AOF 文件
2.4 相干配置
# 是否开启AOF性能appendonly no# AOF文件件名称appendfilename "appendonly.aof"# 写入AOF文件的三种形式appendfsync alwaysappendfsync everysecappendfsync no# 重写AOF时,是否持续写AOF文件no-appendfsync-on-rewrite no# 主动重写AOF文件的条件auto-aof-rewrite-percentage 100 #百分比auto-aof-rewrite-min-size 64mb #大小# 是否疏忽最初一条可能存在问题的指令aof-load-truncated yes
2.5 优缺点
长处
- AOF 文件可读性高,剖析容易
- AOF 文件过大时,主动进行重写
- 追加模式,写入时不须要再次读取文件,间接加到开端
毛病
- 雷同数据量下,AOF 个别比 RDB 大
- AOF 复原时须要重放命令,复原速度慢
- 依据 fsync 策略,AOF 的速度可能慢于 RDB
03 RDB 长久化
RDB 长久化是指在客户端输出 save、bgsave
或者达到配置文件主动保留快照条件时,将 Redis 在内存中的数据生成快照保留在名字为 dump.rdb
(文件名可批改)的二进制文件中。
3.1 save 命令
save 命令会阻塞 Redis 服务器过程,直到 RDB 文件创建结束为止,在 Redis 服务器阻塞期间,服务器不能解决任何命令申请。 在客户端输出 save
127.0.0.1:6379> saveOK
快照生成结束,会弹出 DB saved ondisk 的提醒。
1349:M 25 Apr 13:16:48.935 * DB saved on disk
3.2 bgsave 命令
bgsave 执行时,主线程会创立一个子过程,专门用于写入 RDB 文件,防止了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
127.0.0.1:6379> bgsaveBackground saving started
PS:bgsave 命令执行期间 SAVE 命令会被回绝;不能同时执行两个 BGSAVE 命令;不能同时执行 BGREWRITEAOF 和 BGSAVE 命令。
3.3 bgsave 时写数据
bgsave 执行时,Redis 主线程能失常读写数据。读操作时,主线程和 bgsave 子线程互不影响;写操作时,Redis 会利用写时复制技术(Copy-On-Write, COW),生成被批改数据的正本。而后 bgsave 子线程把正本数据写入 RDB。
比方,bgsave 期间,主线程批改键值对 C,过程如下:
然而在这过程中产生宕机了咋办?比方,T0 时刻做了一次快照,T0+t 时刻又做了一次。然而 t 工夫内主线程批改完数据 5 和 9,而后 Redis 宕机了,RDB 没记录到批改后的数据。
Redis 重启复原数据,就会呈现数据 5 和 9 失落的状况,没方法复原。
这该咋办?咱们须要记住那些数据被批改了。
3.4 混合长久化
如下图所示,记录 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 yesOK# AOF 重写redis> BGREWRITEAOFBackground append only file rewriting started
在没有第二次做全量快照之前,它的格局是这样的:前半部分是 RDB 格局,后半局部是 AOF 增量日志。如果这个时候宕机,间接拿 appendonly.aof 复原数据。
3.5 RDB 优缺点
长处
- 二进制数据,复原时比 AOF 快
- RDB 的 bgsave 形式主线程不阻塞
毛病
- Redis 意外宕机 时,会失落局部数据(混合长久化可解决)
- 当数据量比拟大时,fork 的过程是十分耗时的,fork 子过程时是会阻塞的,在这期间 Redis 是不能响应客户端的申请的。
04 如何抉择?
- 数据不能失落时,抉择内存快照和 AOF 混合应用;
- 如果容许分钟级别的数据失落,能够只应用 RDB;
- 如果只用 AOF,优先应用 everysec 的配置选项,因为它在可靠性和性能之间取了一个均衡。
05 数据恢复流程
07 总结
本文次要解说 Redis AOF 、RDB长久化的原理和两者的优缺点,比照两者后,我还给你总结了 Redis 混合长久化的流程。最初给了你一些抉择长久化计划的倡议,心愿看完你能有所播种。
全文将近五千字,12张图,心愿能帮到你。好啦,以上就是狗哥对于 Redis 长久化的总结。感激各技术社区大佬们的付出,尤其是极客工夫,真的牛逼。如果说我看得更远,那是因为我站在你们的肩膀上。心愿这篇文章对你有帮忙,咱们下篇文章见~
08 大厂面试题 & 电子书
如果看到这里,喜爱这篇文章的话,请帮点个难看。
初次见面,也不晓得送你们啥。罗唆就送几百本电子书和2021最新面试材料吧。微信搜寻一个优良的废人回复电子书送你 1000+ 本编程电子书;回复面试送点面试题;回复1024送你一套残缺的 java 视频教程。
面试题都是有答案的,如下所示:有须要的就来拿吧,相对收费,无套路获取。
伟人的肩膀
- 《Redis设计与实现》
- juejin.cn/post/6844903648976175118
- time.geekbang.org/column/article/272852
- blog.csdn.net/wsdc0521/article/details/106765809
- blog.csdn.net/weixin_33810006/article/details/90394921