2024年Java最新阿里二面:Redis 中的 AOF 文件太大了怎么办?(1),mysql锁面试题

本文介绍了Java面试中的常见问题、多线程和高并发概念,重点讲解了Redis的RDB和AOF持久化机制,包括文件结构、保存策略和AOF重写原理。对于面试准备和技术学习者,提供了系统化的学习资源链接。
摘要由CSDN通过智能技术生成

知其然不知其所以然,大厂常问面试技术如何复习?

1、热门面试题及答案大全

面试前做足功夫,让你面试成功率提升一截,这里一份热门350道一线互联网常问面试题及答案助你拿offer

2、多线程、高并发、缓存入门到实战项目pdf书籍

3、文中提到面试题答案整理

4、Java核心知识面试宝典

覆盖了JVM 、JAVA集合、JAVA多线程并发、JAVA基础、Spring原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm的大量技术点且讲解的非常深入

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

在这里插入图片描述

2.3.1 REDIS

RDB 文件的开头部分是 REDIS 部分,这个部分长度为 5 个字节,保存着 “REDIS” 五个字符。通过这五个字符,程序在载入文件时,可以快速检查该文件是否是 RDB 文件。

2.3.2 db_version

db_version 长度为 4 个字节,值是一个字符串表示的整数,这个整数记录的是 RDB 文件的版本号(不是 Redis 版本号),比如 “0006” 就代表 RDB 文件的版本为第六版。

2.3.3 databases

一个 RDB 文件的 databases 部分可以保存任意多个非空数据库。

例如,如果服务器的 0 号数据库和 3 号数据库非空,那么服务器将创建如下图的 RDB 文件,图中的 database 0 代表 0 号数据库所有键值对数据,而 database 3 代表 3 号数据库所有键值对数据。

在这里插入图片描述

每个非空数据库在 RDB 文件中都可以保存为 SELECTDB、db_number、key_value_pairs 三个部分。如下图所示:

在这里插入图片描述

SELECTDB 常量的长度为 1 个字节,当读入程序遇到这个值的时候,它知道接下来要读入的是一个数据库号码。

db_number 保存着一个数据库号码,根据读入的数据库号码进行数据库切换,使得之后读入的键值对可以载入到正确的数据库中。

key_value_pairs 保存着数据库中所有键值对数据,如果键值对带有过期时间的话,那么键值对的过期时间也会保存在内。

2.3.4 EOF

结束标志

2.3.5 check_sum

校验和,就是看文件是否损坏,或者是否被修改。


最后再来看一下一个完整的 RDB 文件,如下图所示:

在这里插入图片描述

三、AOF


AOF(Append Only File)持久化方式会记录客户端对服务器的每一次写操作命令,并将这些写操作以 Redis 协议追加保存到以后缀为 aof 文件末尾,在 Redis 服务器重启时,会加载并运行 aof 文件的命令,以达到恢复数据的目的。

在这里插入图片描述

AOF 会记录过程,RDB 只管结果。

3.1 开启 AOF 持久化方式

Redis 默认不开启 AOF 持久化方式,我们可以在 redis.conf 配置文件中开启并进行更加详细的配置。

appendonly no # 默认不开启,需要开启的话要改成yes。

appendfilename “appendonly.aof” # aof文件名

dir ./ # AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。

appendfsync always # 写入策略

appendfsync everysec # 写入策略

appendfsync no # 写入策略

no-appendfsync-on-rewrite no # 默认不重写aof文件

3.2 AOF 执行原理

AOF 文件中存储的是 redis 的命令,同步命令到 AOF 文件的整个过程可以分为三个阶段:

  • 命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。

  • 缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。

  • 文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话, fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。

3.2.1 命令传播

当一个 Redis 客户端需要执行命令时, 它通过网络连接, 将协议文本发送给 Redis 服务器。服务器在接到客户端的请求之后, 它会根据协议文本的内容, 选择适当的命令函数, 并将各个参数从字符串文本转换为 Redis 字符串对象(StringObject)。每当命令函数成功执行之后,命令参数都会被传播到 AOF 程序。

3.2.2 缓存追加

当命令被传播到 AOF 程序之后,程序会根据命令以及命令的参数,将命令从字符串对象转换回原来的协议文本。协议文本生成之后,它会被追加到 redis.h/redisServer 结构的 aof_buf 末尾。

redisServer 结构维持着 Redis 服务器的状态,aof_buf 域则保存着所有等待写入到 AOF 文件的协议文本(RESP)。

3.2.3 文件写入和保存

每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile 函数都会被调用,这个函数执行以下两个工作:

  • WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件。

  • SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

为了提高文件写入效率,在现代操作系统中,当用户调用 write 函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。

这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失。因此系统同时提供了 fsync、fdatasync 等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。

3.2.4 AOF 保存模式

AOF 缓存区的同步文件策略由参数 appendfsync 控制,各个值的含义如下:

  • AOF_FSYNC_NO:不保存。

  • AOF_FSYNC_EVERYSEC:每一秒钟保存一次。(默认)

  • AOF_FSYNC_ALWAYS:每执行一个命令保存一次。(不推荐)

3.2.4.1 AOF_FSYNC_NO

在这种模式下, 每次调用 flushAppendOnlyFile 函数, WRITE 都会被执行, 但 SAVE 会被略过。

在这种模式下, SAVE 只会在以下任意一种情况中被执行:

  • Redis 被关闭

  • AOF 功能被关闭

  • 系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)

这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。

3.2.4.2 AOF_FSYNC_EVERYSEC

在这种模式中,SAVE 原则上每隔一秒钟就会执行一次,因为 SAVE 操作是由后台子进程(fork)调用的,所以它不会引起服务器主进程阻塞。

3.2.4.3 AOF_FSYNC_ALWAYS

在这种模式下,每次执行完一个命令之后, WRITE 和 SAVE 都会被执行。

另外,因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。

对于三种 AOF 保存模式, 它们对服务器主进程的阻塞情况如下:

在这里插入图片描述

四、AOF 重写


4.1 AOF 文件重写的原理

前面了解完 RDB 和 AOF 两种持久化方式的原理后,我们再来来看我那粉丝读者的阿里面试题:Redis 中的 AOF 文件太大了怎么办?

这就要用到 AOF 的重写机制了。因为 AOF 持久化是通过保存被执行的写命令来记录数据库状态的,随着 AOF 文件内容越来越多,文件的体积也越来越大。如果不对 AOF 文件加以管控的话,可能会对 Redis 服务器产生影响。

举个例子,如果客户端执行了以下命令:

rpush list 1 2 // [1,2]

rpush list 3 // [1,2,3]

rpush list 4 5 6 // [1,2,3,4,5,6]

lpop list 1 // [2,3,4,5,6]

lpop list 2 // [3,4,5,6]

rpush list 7 // [3,4,5,6,7]

那么光记录 list 这个状态,AOF 文件就需要保存六条命令。实际线上的应用,写命令肯定比这频繁而且体积更大,更何况线上要记录很多个 key 的状态。

为了解决 AOF 文件体积膨胀的问题,Redis 提供了文件重写(rewrite)功能。通过该功能,Redis 服务器可以创建一个新的 AOF 文件来代替旧的 AOF 文件,重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 所谓的“重写”其实是一个有歧义的词语,实际上,AOF 重写并不需要对原有旧的 AOF 文件进行任何写入和读取,新旧两个 AOF 文件所保存的数据库状态相同,但新的 AOF 文件不会包含任何浪费空间的冗余命令,所以新的 AOF 文件体积通常比旧的 AOF 文件体积小得多。

从上面可以看到,为了记录 list 这个状态,AOF 文件就需要保存六条命令。如果服务器想要用尽量少的命令来记录 list 键的状态,那么最简单高效的办法不是去读取和分析现有 AOF 文件的内容,而是直接从数据库中读取键 list 的值,然后用 rpush list 3 4 5 6 7 命令来代替保存在 AOF 文件中的六条命令,这样就可以将保存在 list 键所需的命令从六条减到一条了。

除了上面的集合键以外,其它所有类型的键都可以用同样的方法去减少 AOF 文件中的命令数量。首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是 AOF 重写功能的实现原理。

4.2 AOF 后台重写

上面的 AOF 重写功能是通过 aof_rewrite 函数来实现的,但这个函数会进行大量的写操作,所以调用这个线程将被长时间阻塞,因为 Redis 服务器使用单线程来处理命令请求,所以如果服务器直接调用 aof_rewrite 函数的话,那么重写 AOF 文件期间,服务器将无法处理客户端发来的命令请求。

Redis 不希望 AOF 重写造成服务器无法处理请求, 所以 Redis 决定将 AOF 重写程序放到后台子进程里执行, 这样处理的最大好处是:

  • 子进程进行 AOF 重写期间,主进程可以继续处理命令请求。

  • 子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性。

不过,使用子进程也有一个问题需要解决:因为子进程在进行 AOF 重写期间,主进程还需要继续处理 命令,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的 AOF 文件中的数 据不一致。

为了解决这个问题,Redis 增加了一个 AOF 重写缓存,这个缓存在 fork 出子进程之后开始启用,Redis 主进程在接到新的写命令之后,除了会将这个写命令的协议内容追加到现有的 AOF 文件之外,还会追加到这个缓存中。

在这里插入图片描述

4.3 重写过程分析

Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生 停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到 新 AOF 文件,并开始对新 AOF 文件进行追加操作。

当子进程在执行 AOF 重写时, 主进程需要执行以下三个工作:

  • 处理命令请求

  • 将写命令追加到现有的 AOF 文件中

  • 将写命令追加到 AOF 重写缓存中

这样一来可以保证:

  • 现有的 AOF 功能会继续执行,即使在 AOF 重写期间发生停机,也不会有任何数据丢失。

  • 所有对数据库进行修改的命令都会被记录到 AOF 重写缓存中。

  • 当子进程完成 AOF 重写之后,它会向父进程发送一个完成信号,父进程在接到完成信号之后,会调用 一个信号处理函数,并完成以下工作:

  • 将 AOF 重写缓存中的内容全部写入到新 AOF 文件中。

  • 对新的 AOF 文件进行改名,覆盖原有的 AOF 文件。

这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接受命令请求了。在整个 AOF 后台重 写过程中,只有最后的写入缓存和改名操作会造成主进程阻塞,在其他时候,AOF 后台重写都不会对主进程造成阻塞,这将 AOF 重写对性能造成的影响降到了最低。

以上就是 AOF 后台重写,也即是 BGREWRITEAOF 命令的工作原理。

4.4 触发方式

4.4.1 配置触发

在 redis.conf 中配置

表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为准

auto-aof-rewrite-percentage 100

限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化

auto-aof-rewrite-min-size 64mb

最后

这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

64mb

最后

这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)

[外链图片转存中…(img-S3go5x6q-1714993519794)]

[外链图片转存中…(img-DcH67If8-1714993519795)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值