AOF 持久化和 RDB 持久化的最主要区别在於前者记录了数据的变更,而后者是保存了数据本身本篇主要讲的是AOF 持久化,了解 AOF 的数据组织方式和运作机制Redis 主要在 aof.c 中实现 AOF 的操作。
同样AOF 持久化也会涉及文件的读写,会用到数据结构 rio关于 rio 已经在上一个篇章已经讲述,在此不做展开
假设 redis 内存有「name:Jhon」的键值对,那麼进行 AOF 持久化后AOF 文件有如下内容:
$6 # 第一个参数长度为6 $1 # 第二参数长度为1 $3 # 第一个参数长度为4 $4 # 第二参数长度为4 $4 # 第三个参数长度为4所以对上面的內容进行恢复,能得到熟悉的一条 Redis 命令:SELECT 8;SET name Jhon. 可以想象的是Redis 遍历内存数据集中的每个 key-value 对,依次写入磁盘中;Redis 启动的时候从 AOF 文件中读取数据,恢复数据
AOF 持久化运作机制
和 redis RDB 持久化运作机制不同,redis AOF 有后台执行和边服务边备份两种方式
1)AOF 后台执行的方式和 RDB 有类似的地方,fork 一个子進程主进程仍进行服务,子进程执行AOF 持久化数据被dump 到磁盘上。与 RDB 不同的是后台子进程持久化过程中,主进程会记录期间的所有数据變更(主进程还在服务)并存储在 server.aof_rewrite_buf_blocks 中;后台子进程结束后,Redis 更新缓存追加到 AOF 文件中是 RDB
来说说更新缓存这个东西。Redis 服务器产生数据变更嘚时候譬如 set name Jhon,不仅仅会修改内存数据集也会记录此更新(修改)操作,记录的方式就是上面所说的数据组织方式
更新缓存可以存储茬 server.aof_buf 中,你可以把它理解为一个小型临时中转站所有累积的更新缓存都会先放入这里,它会在特定时机写入文件或者插入到server.aof_-rewrite_buf_blocks 下链表(下面會详述);server.aof_buf 中的数据在 propagrate() 添加在涉及数据更新的地方都会调用propagrate() 以累积变更。更新缓存也可以存储在 server.aof_-rewrite_buf_blocks这是一个元素类型为 struct aofrwblock 的链表,你可以紦它理解为一个仓库当后台有AOF 子进程的时候,会将累积的更新缓存(在 server.aof_buf 中)插入到链表中而当 AOF 子进程结束,它会被整个写入到文件兩者是有关联的。
这里的意图即是不用每次出现数据变更的时候都触发一个写操作可以将写操作先缓存到内存中,待到合适的时机写入箌磁盘如此避免频繁的写操作。当然完全可以实现让数据变更及时更新到磁盘中。两种做法的好坏就是一种博弈了
下面是后台执行嘚主要代码:
// 已经有正在执行备份的子进程 // 脏数据,其实就是子进程所消耗的内存大小 // AOF 最近一次执行的起始时间 // 因为更新缓存都将写入文件要强制产生选择数据集的指令SELECT ,以防出现数据如上子进程执行 AOF 持久化,父进程则会记录一些 AOF 的执行信息下面来看看 AOF 持久化具体是怎么做的?
// 如果设置了自动备份参数将进行设置 // 备份每一个数据集 // 获取数据集的迭代器 // 写入数据集中每一个数据项 // 如果已经过期,放弃存储 // 写入键值对应的写操作2)边服务边备份的方式即 Redis 服务器会把所有的数据变更存储在 server.aof_buf 中,并在特定时机将更新缓存写入预设定的文件(server.aof_filename)特定时机有三种:
Redis 无非是不想服务器突然崩溃终止,导致过多的数据丢失Redis 默认是每隔固定时间进行一次边服务边备份,即隔固定時间将累积的变更的写入文件
下面是边服务边执行 AOF 持久化的主要代码:
// 无数据,无需同步到磁盘 // 创建线程任务主要调用fsync() // 如果没有设置強制同步的选项,可能不会立即进行同步 // 设置延迟冲洗时间选项 // 没有超过2s直接结束 // 否则,要强制写入磁盘 // 取消延迟冲洗时间设置 // 当server.aof_buf 足够尛, 重新利用空间防止频繁的内存分配。 // 相反当server.aof_buf 占据大量的空间,采取的策略是释放空间可见redis上面两次提到了「更新缓存」,它即是 Redis 累积的数据变更
// 向AOF 和从机发布数据更新
// AOF 策略需要打开,且设置AOF 传播标记将更新发布给本地文件
// 设置了从机传播标记,将更新发布给从機
// 将数据更新记录到AOF 缓存中
// 如果已经有AOF 子进程运行redis 采取的策略是累积子进程AOF 备份的数据和
// 创建新的节点,插到尾部
一副可以缓解视力疲勞的图片——AOF 持久化运作机制:
两种数据落地的方式就是 AOF 的两个主线。因此redis AOF 持久化机制有两条主线:后台执行和边服务边备份,抓住這两点就能理解 redis AOF 了
这里有一个疑问,两条主线都会涉及文件的写:后台执行会写一个AOF 文件边服务边备份也会写一个,以哪个为准
因此,确实会产生两个文件但是最后都会变成 server.aof_filename 文件。这里可能还有一个疑问既然有了后台持久化,为什么还要边服务边备份边服务边備份时间长了会产生数据冗余甚至备份过旧的数据,而后台持久化可以消除这些东西看,这里是 Redis 的双保险
AOF 的数据恢复过程设计很巧妙,它模拟一个 Redis 的服务过程Redis 首先虚拟一个客户端,读取 AOF 文件恢复 Redis 命令和参数;接着过程就和服务客户端一样执行命令相应的函数从而恢複数据,这样做的目的无非是提高代码的复用率这些过程主要在 loadAppendOnlyFile() 中实现。
// 加载AOF 文件恢复数据
// 文件大小不能为0
// 正在执行AOF 加载操作,于是暫时禁止AOF 的所有操作以免混淆
// 每循环1000 次,在恢复数据的同时服务器也为客户端服务。
// 可能aof 文件到了结尾
// 必须以“*”开头格式不对,退出
// 执行命令模拟服务客户端请求的过程,从而写入数据
// 释放虚拟客户端空间
// 记录最近AOF 操作的文件大小
如果对数据比较关心分秒必争,可以用 AOF 持久化而且AOF 文件很容易进行分析。