0
点赞
收藏
分享

微信扫一扫

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!


00 前言

很多小伙伴都用 Redis 做缓存,那如果 Redis 服务器宕机,内存中数据全部丢失,应该如何做数据恢复呢?有人说很简单呀,​直接从 MySQL 数据库再读回来就得了​。

这种方式存在两个问题:一是​频繁访问​ MySQL 数据库,有一定的风险;二是​​,从界面上来看,从 MySQL 读就不如从 Redis 快。

秃头哥,那咋办呀?教教我吧。

我用中指抵着小胖的下吧,说到:傻瓜,我们可以做持久化呀。​Redis 的持久化分两种,一种是 AOF,另一种是 RDB​。来,坐哥哥腿上,我给你好好说道说道。

老规矩先上张脑图:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_持久化

0.1 什么是持久化?


持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML 数据文件中等等。持久化是将程序数据在持久状态和瞬时状态间转换的机制。


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 yes
OK

AOF 持久化功能的实现可以分为​命令追加(append)、文件写回磁盘​两个步骤。

2.0 命令追加

AOF 持久化功能开启时,Redis 在执行完一个写命令之后,会将被执行的写命令追加到服务器状态的 ​aof_buf 缓冲区的末尾,此时缓冲区的记录还没有写入到 appendonly.aof 文件中​。

2.0.1 AOF 的格式

AOF 保存的是 Redis 的​写命令​,比如:执行命令​set testkey testvalue​,它存储的内容如下图所示:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_02

其中,“*3” 表示当前命令有​三个部分​,每部分都是由 ​+数字∗∗开头,后面紧跟着具体的命令、键或值。这里,∗∗数字∗∗表示这部分中的命令、键或值一共有多少字节。例如,∗∗+数字**开头,后面紧跟着具体的命令、键或值。这里,**数字**表示这部分中的命令、键或值一共有多少字节。例如,**+数字∗∗开头,后面紧跟着具体的命令、键或值。这里,∗∗数字∗∗表示这部分中的命令、键或值一共有多少字节。例如,∗∗3 set​ 表示这部分有 3 个字节,也就是​set​命令。

2.0.2 写后日志有啥优缺点?

AOF 记录日志的方式被称为​写后日志,也就是先执行命令再记录​,而 MySQL 中的 redo log、binlog 等都是写前日志。它的写入流程是下图这样的:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_redis_03

写后有什么优点?


  • 记录 AOF 时不会对命令进行语法检查 ,写后就​只记录了执行成功的命令​。(避免保存的错误的命令,恢复的时候就完犊子了)
  • 执行完之后再记录,​不会阻塞当前的写操作

写后有什么缺陷?


  • 如果执行完一个命令还没来得及写日志就宕机了会造成响应数据丢失。
  • AOF 的写入由​主线程​处理,如果写入时出现较长耗时,那就会影响主线程处理后续的请求。

你发现没有?写后的两个缺陷都是 AOF 的写入磁盘时相发生的,我们来看看它是怎么写入的呢?

2.1 AOF 写入磁盘

AOF 提供了三个选择,也就是 AOF 配置项 ​appendfsync​ 的三个可选值。


  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
  • Everysec(默认),每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的​内存缓冲区​,每隔一秒把缓冲区中的内容写入磁盘;
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的​内存缓冲区​,由操作系统决定何时将缓冲区内容写回磁盘。

2.1.0 三种策略的优缺点

针对避免主线程阻塞和减少数据丢失问题,这三种写回策略都无法做到两全其美。主要原因是:


  • Always(同步写回) 基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,影响主线程性能;
  • No(操作系统控制的写回)在写完缓冲区后,继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了;
  • Everysec(每秒写回)采用一秒写回一次的频率,避免了 Always 的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_持久化_04

总结一下就是:想​高性能​,选择 No 策略;想​高可靠性​,选择 Always 策略;​允许数据有一点丢失,又希望性能别受太大影响​,选择 Everysec 策略。

2.2 AOF 恢复数据

不说了,看图:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_05

2.3 AOF 重写

我不知道你发现没有?AOF 文件是​不断地将写命令追加到文件的末尾来记录数据库状态的​。写命令不断增加,AOF 体积也越来越大。

有些命令是执行多次更新同一条数据,但其实它是可以合并成同一条命令的。比如:LPUSH 对列表数据做了 6 次更改,但 AOF 只需要记录最后一次更改。​因为日志恢复时,只需要执行最后一次更改的命令即可​。

为了处理这种情况,Redis 提供了 AOF 的重写机制。它的​多变一​功能,把 6 条写命令合并成一条。如下所示:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_redis_06

如果你的某些键有成百上千次的修改,重写机制节约的空间就很可观了。

2.3.1 触发重写

有两种触发的方法,一个是调用命令 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 #文件的最小体积

2.3.2 重写步骤


  1. 创建子进程进行 AOF 重写
  2. 将客户端的写命令追加到 AOF 重写缓冲区
  3. 子进程完成 AOF 重写工作后,会向父进程发送一个信号
  4. 父进程接收到信号后,将 AOF 重写缓冲区的所有内容写入到新 AOF 文件中
  5. 对新的 AOF 文件进行改名,覆盖现有的 AOF 文件

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_07

2.4 相关配置

# 是否开启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

2.5 优缺点

优点


  1. AOF 文件可读性高,分析容易
  2. AOF 文件过大时,自动进行重写
  3. 追加形式,写入时不需要再次读取文件,直接加到末尾

缺点


  1. 相同数据量下,AOF 一般比 RDB 大
  2. AOF 恢复时需要重放命令,恢复速度慢
  3. 根据 fsync 策略,AOF 的速度可能慢于 RDB

03 RDB 持久化

RDB 持久化是指在客户端输入 ​​save、bgsave​​ 或者达到配置文件自动保存快照条件时,将 Redis 在内存中的数据​生成快照​保存在名字为 ​​dump.rdb​​(文件名可修改)的二进制文件中。

3.1 save 命令

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

3.2 bgsave 命令

bgsave 执行时,​主线程会创建一个子进程,专门用于写入 RDB 文件​,避免了主线程的阻塞,这也是 Redis RDB 文件生成的​默认配置​。

127.0.0.1:6379> bgsave
Background saving started


PS:bgsave 命令执行期间 SAVE 命令会被拒绝;不能同时执行两个 BGSAVE 命令;不能同时执行 BGREWRITEAOF 和 BGSAVE 命令。


3.3 bgsave 时写数据

bgsave 执行时,Redis 主线程能正常读写数据。读操作时,主线程和 bgsave 子线程​互不影响​;写操作时,Redis 会利用​写时复制技术(Copy-On-Write, COW)​,生成被修改数据的副本。然后 bgsave 子线程把副本数据写入 RDB。

比如,bgsave 期间,主线程修改键值对 C,过程如下:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_08

但是在这过程中发生宕机了咋办?比如,T0 时刻做了一次快照,T0+t 时刻又做了一次。但是 t 时间内主线程修改完数据 5 和 9,然后 Redis 宕机了,​RDB 没记录到修改后的数据​。

Redis 重启恢复数据,就会出现数据 5 和 9 丢失的情况,没办法恢复。

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_09

这该咋办?​我们需要记住那些数据被修改了​。

3.4 混合持久化

如下图所示,记录 t 时刻被修改的数据就需要​占用额外的空间​,而 Redis 是内存数据库,空间非常宝贵。所以,​直接记录到内存这种方式不可取​。

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_持久化_10

内存开销比较小的方法是​把 t 时间的增量写操作记录到 AOF 日志中​,这样既保留了 RDB 的快速恢复,也没占用额外的空间。

如图,T1 和 T2 时刻的修改,用 AOF 日志记录,等第二次做全量快照时,清空 AOF 日志,因为此时的修改都记录到快照中了,恢复不用 AOF 日志了。

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_11

庆幸的是 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 持久化?真的菜!_数据_12

3.5 RDB 优缺点

优点


  1. 二进制数据,恢复时比 AOF 快
  2. RDB 的 bgsave 方式主线程不阻塞

缺点


  1. Redis 意外宕机 时,会丢失部分数据(混合持久化可解决)
  2. 当数据量比较大时,fork 的过程是非常耗时的,fork 子进程时是会阻塞的,在这期间 Redis 是不能响应客户端的请求的。

04 如何选择?


  1. 数据不能丢失时,选择内存快照和 AOF 混合使用;
  2. 如果允许分钟级别的数据丢失,可以只使用 RDB;
  3. 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。

05 数据恢复流程

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_13

一直想整理出一份完美的面试宝典,但是时间上一直腾不开,这套一​千多道面试题宝典​,结合今年金三银四各种大厂面试题,以及 ​GitHub 上 star 数超 30K+ 的文档​整理出来的,我上传以后,毫无意外的短短半个小时点赞量就达到了 13k,说实话还是有点不可思议的。

一千道互联网 Java 工程师面试题

内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、SpringBoot、SpringCloud、RabbitMQ、Kafka、Linux等技术栈(485页)

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_14

初级—中级—高级三个级别的大厂面试真题

阿里云——Java 实习生/初级


List 和 Set 的区别 HashSet 是如何保证不重复的

HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?

HashMap 的扩容过程

HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?

对象的四种引用

Java 获取反射的三种方法

Java 反射机制

Arrays.sort 和 Collections.sort 实现原理 和区别

Cloneable 接口实现原理

异常分类以及处理机制

wait 和 sleep 的区别

数组在内存中如何分配


答案展示:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_15

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_16

美团——Java 中级


BeanFactory 和 ApplicationContext 有什么区别

Spring Bean 的生命周期

Spring IOC 如何实现

说说 Spring AOP

Spring AOP 实现原理

动态代理(cglib 与 JDK)

Spring 事务实现方式

Spring 事务底层原理

如何自定义注解实现功能

Spring MVC 运行流程

Spring MVC 启动流程

Spring 的单例实现原理

Spring 框架中用到了哪些设计模式

为什么选择 Netty

说说业务中,Netty 的使用场景

原生的 NIO 在 JDK 1.7 版本存在 epoll bug

什么是 TCP 粘包/拆包

TCP 粘包/拆包的解决办法

Netty 线程模型

说说 Netty 的零拷贝

Netty 内部执行流程


答案展示:

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_17

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_18

蚂蚁金服——Java 高级

题 1:



  1. jdk1.7 到 jdk1.8 Map 发生了什么变化(底层)?
  2. ConcurrentHashMap
  3. 并行跟并发有什么区别?
  4. jdk1.7 到 jdk1.8 java 虚拟机发生了什么变化?
  5. 如果叫你自己设计一个中间件,你会如何设计?
  6. 什么是中间件?
  7. ThreadLock 用过没有,说说它的作用?
  8. Hashcode()和 equals()和==区别?
  9. mysql 数据库中,什么情况下设置了索引但无法使用?
  10. mysql 优化会不会,mycat 分库,垂直分库,水平分库?
  11. 分布式事务解决方案?
  12. sql 语句优化会不会,说出你知道的?
  13. mysql 的存储引擎了解过没有?
  14. 红黑树原理?


题 2:



  1. 说说三种分布式锁?
  2. redis 的实现原理?
  3. redis 数据结构,使⽤场景?
  4. redis 集群有哪⼏种?
  5. codis 原理?
  6. 是否熟悉⾦融业务?记账业务?蚂蚁⾦服对这部分有要求。


好啦~展示完毕,大概估摸一下自己是青铜还是王者呢?

前段时间,在和群友聊天时,把今年他们见到的一些不同类别的面试题整理了一番,于是有了以下面试题集,也一起分享给大家~

如果你觉得这些内容对你有帮助,可以加入​​csdn进阶交流群​​,领取资料

基础篇

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_java_19

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_redis_20

JVM 篇

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_持久化_21

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_22

MySQL 篇

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_23

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_数据_24

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_redis_25

Redis 篇

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_redis_26

工作三年半,小胖问我:什么是 Redis 持久化?真的菜!_持久化_27



由于篇幅限制,详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!


需要的小伙伴,可以一键三连,下方获取免费领取方式!




举报

相关推荐

0 条评论