Redis持久化之AOF

CodeEclipse
• 阅读 644

AOF(Append Only File):增量持久化方式
与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的,如下图:
Redis持久化之AOF

被写入AOF文件的所有命令都是以Redis的命令请求协议格式(RESP协议REdis Serialization Protocol)保存的,RESP2是纯文本格式。

1、AOF持久化的实现

AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。
(1)命令追加
当AOF持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以RESP协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾:

struct redisServer {
    sds aof_buf; // 使用sds数据结构实现AOF缓冲区
}

命令追加在执行完命令之后,表明AOF是写后日志,采用写后日志的好处:

I) 为了避免额外的检查开销,Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查。所以,如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。
而写后日志这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错。所以,Redis 使用写后日志这一方式的一大好处是,可以避免出现记录错误命令的情况。

II) 除此之外,AOF 还有一个好处:它是在命令执行后才记录日志,所以不会阻塞当前的写操作。但会阻塞之后的写操作。

(2)AOF文件的写入与同步
Redis的服务器主进程就是一个事件循环:
Redis持久化之AOF

Redis的命令追加在主循环(aeMain函数)中的每次处理完写命令的执行后,通过propagate函数触发。

propagate方法将当前命令的内容append到redisServer对象的aof_buf变量中。主循环在下一个迭代进入多路复用的select方法前,Redis会通过flushAppendOnlyFile方法将aof_buf的内容write到AOF对应的文件中。但write操作只是将数据写到缓存中,什么时候从缓存真正落地到磁盘上,取决于操作系统。只有显示调用fsync()方法才能强制地让操作系统落地数据到磁盘。

AOF写入与同步的语义
写入AOF文件指的是:调用write()写到操作系统缓存
同步AOF文件指的是:调用fsync()强制缓存落地到磁盘文件

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项决定:

  • always:主循环的每个迭代的flushAppendOnlyFile函数中都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且直接触发fsync方法同步AOF文件,强制数据落地到磁盘。由于每个命令都在写入磁盘后才返回,故容错能力最高,即使出现故障宕机,也只会丢失一个事件循环中所产生的命令数据。
  • everysec:服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且每隔一秒异步地触发一次fsync方法。fsync方法的执行者是bio线程池中的某个线程。flushAppendOnlyFile函数只是作为生产者将fsync任务放入队列,由bio线程消费并执行
  • no:将aof_buf缓冲区中的所有内容写入到AOF文件,但不显示调用fsync,由操作系统决定什么时候落地磁盘。这种模式下,Redis无法决定增量的落地时间,因此容错能力不可控。

综上,以上3种策略将aof_buf缓冲区中的所有内容写入到AOF文件的时机都一样,不同的是fsync强制落盘的时机。由名字可以看出,appendfsync是同步AOF文件策略。

2、AOF文件的载入与数据还原

Redis会创建一个不带网络连接的伪客户端(fake client):因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令。

3、AOF重写

(1)为了解决AOF文件体积膨胀的问题

AOF 文件过大会带来性能问题。这里的“性能问题”,主要在于以下三个方面:

  • 一是,文件系统本身对文件大小有限制,无法保存过大的文件;
  • 二是,如果文件太大,之后再往里面追加命令记录的话,效率也会变低;
  • 三是,如果发生宕机,AOF 中记录的命令要一个个被重新执行,用于故障恢复,如果日志文件太大,整个恢复过程就会非常缓慢,这就会影响到 Redis 的正常使用。

虽然Redis将生成新的AOF文件替换旧AOF文件的功能命名为“AOF文件重写”,但实际上,AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前的数据器状态来实现的。因为生成的新AOF文件只包含还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何硬盘空间。

(2)作为一种辅佐性的维护手段,Redis不希望AOF重写造成服务器无法处理请求,所以Redis决定将AOF重写程序放到子进程里执行,这样做可以同时达到两个目的:

  • 子进程进行AOF重写期间,服务器进程(父进程)可以继续处理命令请求。
  • 子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性

(3)由于子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,这就可能导致重写后的AOF文件和服务器的当前数据库状态不一致。为了解决此问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区,如下图:
Redis持久化之AOF

这也就是说,在子进程执行AOF重写期间,服务器进程需要执行以下三个工作:

  • 执行客户端发来的命令
  • 将执行后的写命令追加到AOF缓冲区
  • 将执行后的写命令追加到AOF重写缓冲区

这样一来,从创建子进程开始,服务器执行的所有写命令都会被记录到AOF重写缓冲区里面。

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

  • 将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。
  • 对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个AOF文件的替换。

4、何时触发AOF重写?

  1. 手动发送“bgrewriteaof”指令;
  2. 有两个配置项在控制AOF重写的触发时机:
    1)auto-aof-rewrite-min-size: 表示运行AOF重写时文件的最小大小,默认为64MB
    2)auto-aof-rewrite-percentage: 这个值的计算方法是:当前AOF文件大小和上一次重写后AOF文件大小的差值,再除以上一次重写后AOF文件大小。也就是当前AOF文件比上一次重写后AOF文件的增量大小,和上一次重写后AOF文件大小的比值。
    AOF文件大小同时超出上面这两个配置项时,会触发AOF重写。
参考资料
1、redis设计与实现
2、redis深度历险
点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
Redis持久化RDB和AOF实现原理
Redis持久化RDB和AOF为什么Redis需要持久化?因为Redis属于内存型数据库,数据是储存在内存当中的,当遇到不可抗力因素,比如断电,那么储存在内存中的数据就会丢失。所以为了保证数据的完整性,我们需要做持久化操作,来保证数据的完整性。Redis中都有哪些持久化机制?Redis早
Stella981 Stella981
3年前
Hibernate映射关系及CRUD操作
Hibernate对象的三种状态的概念及互相转化:1.瞬时状态或临时状态(Transient):用new创建的对象,它没有持久化,没有处于Session中;2.持久状态(Persistent):已经持久化,加入到了Session缓存中。如通过hibernate语句保存的对象;3.三脱管状态或游离状态(Detached):持久化对象
Stella981 Stella981
3年前
Redis单实例数据迁移到集群
迁移步骤:(1)停掉项目,停止对redis单实例的数据写入。(2)登录单实例redis客户端通过命令keys\查看当前单实例缓存的所有数据条数,记录下来。(3)假如单实例redis同时开启了RDB和AOF,只要AOF文件就可以了,因为当AOF和RDB同时存在的时候,Redis还是会先加载AOF文件的,在单实例redis上执行BGREW
Stella981 Stella981
3年前
NoSQL数据库Redis和MongoDB
redis简介一些特点:Redis的读写性能极高,并且有丰富的特性(发布/订阅、事务、通知等)。Redis支持数据的持久化(RDB和AOF两种方式),可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis支持多种数据类型,包括:string、hash、list、set,zset、bitm
Stella981 Stella981
3年前
051. Redis 持久化机制
1\.持久化介绍Redis的数据存在在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。!image20200511165351687(https://oscimg.oschina.net/os
Stella981 Stella981
3年前
Redis——持久化数据
Redis被称为是内存数据库,那是因为它会将其所有数据存储在内存里,因此Redis具有强劲的速度性能,但是,也正因为数据存储在内存中,当Redis重启后,所有存储在内存的数据就会丢失。为了使得数据持久化,Redis提供了两种方式:RDB方式和AOF方式。一、RDB方式RDB方式的持久化是通过快照(snapshotting)完成的,
Stella981 Stella981
3年前
Redis—持久化
一、持久化简介Redis的数据全部存储在内存中,如果突然宕机,数据就会全部丢失,因此必须有一套机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制,它会将内存中的数据库状态保存到磁盘中。持久化发生了什么|从内存到磁盘
Stella981 Stella981
3年前
Redis 持久化(10)
持久化机制Redis速度快,很大一部分原因是因为它所有的数据都存储在内存中。如果断电或者宕机,都会导致内存中的数据丢失。为了实现重启后数据不丢失,Redis提供了两种持久化的方案,一种是RDB快照(RedisDataBase),一种是AOF(AppendOnlyFile)。RDBRDB是Redis默认的持久化方案。当满足一定条
Stella981 Stella981
3年前
Redis持久化问题定位与优化技巧
今天主要分享继Redis持久化方式RDB、AOF之后的一些常用的Redis问题定位于优化方式。Redis持久化方式RDB(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzU3OTc1MDM1Mg%3D%3D%
Stella981 Stella981
3年前
Redis持久化存储详解(一)
为什么要做持久化存储?持久化存储是将Redis存储在内存中的数据存储在硬盘中,实现数据的永久保存。我们都知道Redis是一个基于内存的nosql数据库,内存存储很容易造成数据的丢失,因为当服务器关机等一些异常情况都会导致存储在内存中的数据丢失。持久化存储分类在Redis中,持久化存储分为两种。一种是aof日志追加的方式
子非鱼 子非鱼
3年前
Redis高级
第一章Redis的持久化由于redis是一个内存数据库,所有的数据都是保存在内存当中的,内存当中的数据极易丢失,所以redis的数据持久化就显得尤为重要,在redis当中,提供了两种数据持久化的方式,分别为RDB以及AOF,且Redis默认开启的数据持久化方式为RDB方式。1、RDB持久化方案Redis会定期保存数据快照至一个rbd文件中,并在启动时自动