深入学习Redis持久化(AOF)

barzxl
发布于 2022-4-17 10:42
浏览
0收藏

来源:左耳君(ID:qaqzuoer)

作者: 湿兄

上一篇我们说到了Redis持久化的RDB方式,这一篇我们来分析另一种持久化方式AOF,为什么不放在一篇中?因为我有试着放在一篇中,篇幅太长,于是拆分成两篇了,这样大家读起来也更方便记忆 

在Redis中,我们可以将实现高可用技术划分为:持久化、主从复制、哨兵模式和集群(其实也可以不把持久化划分为高可用技术,这都无所谓)

  • 持久化:持久化最容易理解,主要就是将数据备份,将数据备份到硬盘上,不会因为机器宕机停电等造成数据丢失
  • 主从复制:复制主要实现了多个机器的备份,以及对于读操作的负载均衡和简单的故障恢复(哨兵和集群都是在复制的基础上实现高可用的)存在缺陷:存储能力受到单机限制,写操作无法负载均衡,故障无法自动恢复
  • 哨兵模式:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
  • 集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

AOF持久化

我们上篇说到RDB持久化是将进程的数据写入到文件中,而这篇要说的AOF持久化文件则是将Redis执行的命令写入到文件中(有点像MySQL的binlog),当我们重启时可以通过执行AOF文件来恢复数据,与RDB持久化方式相比,AOF持久化具有更好的实时性 

Redis服务器默认开启RDB,关闭AOF,要开启AOF需要在配置文件中修改相应的参数appendonly yes深入学习Redis持久化(AOF)-鸿蒙开发者社区

执行流程

  • 命令追加:将Redis的写命令追加到缓冲区aof_buf中
  • 文件写入和文件同步:根据不同的同步策略同步到文件中
  • 文件重写:定期触发文件重写,达到压缩文件的目的命令追加:

Redis先将写命令追加到缓冲区中,而不是每次都直接写入到文件中,你想啊,如果每次都把用户的命令直接写入到文件中,会有多大的磁盘IO的压力

命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点

文件写入和文件同步

Redis提供了多种AOF缓冲区的同步文件的策略,策略涉及到操作系统的write函数和fsync函数

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

这样的操作虽然提高了效率,但也带来了安全问题

如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性

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

  • always:命令写入aof_buf缓冲区立即调用系统的fsync函数同步到AOF文件中,会造成磁盘IO瓶颈,Redis只能支持大约几百TPS的写入,即使是固态硬盘,每秒也只能处理几万个命令,不建议使用
  • no:命令写入aof_buf缓冲区后调用系统的write函数,不对AOF文件进行同步操作,同步操作由系统来完成,通常是30秒一次,文件时间不可控,缓冲区中命令的大小也是无法控制的,不太建议使用
  • everysenc:命令写入aof_buf后调用系统的write操作,write完成后线程返回,fsync同步操作由专门的线程来调用执行,每秒调用一次。是上面两种方法的平衡,也是性能和数据安全的平衡,也是Redis的默认同步策略文件重写

文件重写

指的是定期重写AOF文件,通过重写来达到减小体积的目的。

至于文件重写,是有一定的触发机制,为什么需要重写呢?你想啊,随着时间的推移,AOF文件越来越大,过大的AOF文件会对服务器造成压力,也会导致系统重启的恢复时间过长

需要注意的是:重写过程是把Redis进程内的数据直接转化为写命令,写入到新的AOF文件中,不会对原有的AOF文件进行任何的读取和写入操作

对于AOF持久化方式,文件重写是强烈推荐的,但是不是必须的,在一些实现中,会自动关闭文件重写,然后通过定时任务在每天的 某一时刻来执行文件重写

文件为什么能够重写?难道开始写入的AOF文件有多余的?

答案是是的,确实AOF文件中有相对“多余”的命令

  • 过期的数据不会再写入到文件中
  • 无效的命令不会入到文件中,比如有些数据被重复赋值set key v1,set key v2,那么set key v1命令便不再有意义,有些数据被删除等
  • 多条命令的合并,如sadd set v1,sadd set v2,sadd set v3则可以合并成sadd set v1 v2 v3这种,不过为了防止单条命令过大造成客户端的缓冲区溢出,所以也不一定完全合并

文件重写的触发

文件重写触发分为手动触发和自动触发两种

手动触发:直接调用bgrewriteaof命令,该命令和bgsave有些类似,底层都是fork子进程,由子进程来完成相应的工作,且只有fork子进程的时候对客户端是阻塞的深入学习Redis持久化(AOF)-鸿蒙开发者社区

看下服务端日志:深入学习Redis持久化(AOF)-鸿蒙开发者社区

自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数,以及aof_current_size和aof_base_size状态确定触发时机

  • auto-aof-rewrite-min-size:执行AOF重写时,文件的最小体积,默认值为64MB
  • auto-aof-rewrite-percentage:执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值只有当上面说的这两个参数同时满足的时候,才会自动触发AOF的重写机制

我们可以通过config get xxx来查看相应参数信息:深入学习Redis持久化(AOF)-鸿蒙开发者社区

可以通过info persistence查看状态:深入学习Redis持久化(AOF)-鸿蒙开发者社区

文件重写流程图: 深入学习Redis持久化(AOF)-鸿蒙开发者社区

解释:

  • Redis父进程首先判断当前是否正在执行bgsave/bgrewriteaof的子进程,如果存在则bgrewriteaof命令直接返回,如果存在bgsave命令则等待执行完再执行(主要是基于性能考虑).
  • 父进程fork子进程,此过程父进程阻塞
  • 父进程fork后,bgrewriteaof命令返回父进程,此时父进程不再阻塞,并可以响应其它命令,Redis的所有写命令依然写入AOF缓冲区,并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确。
  • fork采用的是写时复制技术,子进程只能fork操作时刻的内存数据,之后的数据需要另行复制(父进程在响应,Redis重写缓冲区保存这部分命令,防止新的AOF文件丢失这部分数据),也就是Redis写命令同时追加到aof_buf和aof_rewrite_buf两个缓冲区中
  • 子进程根据内存快照,按照命令合并写入到新的AOF文件中
  • 子进程写完之后通知父进程,父进程把aof_rewrite_buf缓冲区数据写入到新的AOF文件,保持和数据库状态一致
  • 新老AOF文件替换,完成AOF的重写

启动时加载

当AOF开启时,Redis启动时会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会载入RDB文件恢复数据

当AOF开启,且AOF文件存在时,Redis加载AOF文件;但AOF文件不存在时,即使RDB文件存在也不会加载

文件校验:与载入RDB文件类似,Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败。但如果是AOF文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且aof-load-truncated参数开启,则日志中会输出警告,Redis忽略掉AOF文件的尾部,启动成功

aof-load-truncated参数默认是开启的深入学习Redis持久化(AOF)-鸿蒙开发者社区

伪客户端:因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时命令是直接从文件中读取的,并不是由客户端发送;因此Redis服务器在载入AOF文件之前,会创建一个没有网络连接的客户端,之后用它来执行AOF文件中的命令,命令执行的效果与带网络连接的客户端完全一样

RDB常用配置总结:

下面是RDB常用的配置项,以及默认值

1、appendonly no:是否开启AOF

2、appendfilename "appendonly.aof":AOF文件名

3、appendfsync everysec:fsync持久化策略

4、no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡

5、auto-aof-rewrite-percentage 100:文件重写触发条件之一

6、auto-aof-rewrite-min-size 64mb:文件重写触发提交之一

7、aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

RDB和AOF对比

RDB持久化:

优点:RDB文件体积小,适合于全量复制,恢复速度比AOF文件快,对性能的影响小

缺点:无法做到实时持久化

AOF持久化:

优点:支持秒级持久化,兼容性好

缺点:文件大,恢复速度慢,对性能影响较大其实一种持久化的缺点就是另一个的优点啦,自古的套路

分类
标签
收藏
回复
举报
回复
    相关推荐