Redis持久化篇(redis底层分析)

一、AOF日志

1. AOF日志是什么?

如果 Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里,然后重启 Redis 的时候,先去读取且执行这个文件里的命令,这就相当于恢复了缓存数据。这种把写操作命令写入日志中的持久化方式是AOF持久化,这个日志就是AOF日志。 注意:将命令写入到日志的这个操作也是在主进程完成的

下面步骤为AOF日志的具体思路

  1. Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区;
  2. 然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache,等待内核将数据写入硬盘;
  3. 具体内核缓冲区的数据什么时候写入到硬盘,由内核决定。

那么这三种写回策略的根本区别是 fsync()函数(为了将 page cache 中的数据真正落盘,需要执行 fsync / fdatasync 命令来强制刷盘)调用时机不同:

当应用程序向文件写入数据时,内核通常先将数据复制到内核缓冲区中,然后排入队列,再由内核决定何时写入硬盘。也就是由fsync()这个函数何时执行?

  • Always 策略就是每次写入 AOF 文件数据后,就执行 fsync() 函数;
  • Everysec 策略会创建一个异步任务来执行 fsync() 函数;
  • No 策略就是永不执行 fsync() 函数;
4. AOF重写机制
**AOF重写机制**引出:AOF 日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大。当 AOF 日志文件过大就会带来性能问题(重启 Redis 后,读 AOF 文件的内容以恢复数据,如果文件过大,恢复的过程就会很慢)。所以通过**AOF重写机制**避免AOF日志文件过大。

**AOF重写机制思路**:需要<font color="blue">读取所有缓存的键值对数据,并为每个键值对生成一条命令</font>,然后将其写入到新的 		  AOF 文件,重写完后,就<font color="blue">把现在的 AOF 文件替换掉</font>。

了解重写机制的思路之后,就可以对比下 写入AOF文件 所需时间要远小于 对AOF文件重写所需时间,故对AOF文件重写就需要一个 后台子进程 bgrewriteaof 来完成。

此时,应有疑问如下:

  • 子进程要对AOF文件中数据进行重写,那么它怎么知道当前有哪些数据?
  • 子进程重写 AOF 日志过程中,如果主进程修改了已经存在 key-value,此时这个 key-value 数据在子进程的内存数据就跟主进程的内存数据不一致,该怎么办?

疑问一:主进程在通过 fork 系统调用生成 bgrewriteaof 子进程时,操作系统会把主进程的「页表」复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。见图如下:在这里插入图片描述
疑问二:为了解决这种数据不一致问题,Redis 设置了一个 AOF 重写缓冲区。也就是说,在子进程重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 AOF缓冲区AOF重写缓冲区。AOF重写缓冲区中存储的是子进程重写AOF期间父进程已经执行过的写命令
这样以来呢,就会在覆盖原AOF文件时候导致数据丢失,在这次重写完成之后,会向主进程发送一条信号,主进程收到该信号后,会调用一个信号处理函数,这个函数会将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致。之后,新的 AOF 的文件进行改名,覆盖现有的 AOF 文件

二、RDB快照

1. RDB快照简介:

RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据。

2. RDB快照思路:

通过bgsave命令(可选参数,即指定一个条件下,RDB快照就开启)开启RDB快照,RDB快照是在子进程进行的,操作系统把父进程的页表复制给子进程,因此他们指向同一块物理地址,RDB把所有数据记录之后,即RDB创建完毕。那么,下次redis重启时候,进行RDB加载即可,而不是AOF文件的读取与其内容(写命令)的执行。

3. 执行快照时,数据能被修改吗?

答案:执行 bgsave 过程中,Redis 依然可以继续处理操作命令的,也就是数据是能被修改的。
解析如下:
执行 bgsave 命令的时候,会通过 fork() 创建子进程,此时子进程和父进程是共享同一片内存数据的,因为创建子进程的时候,会复制父进程的页表,但是页表指向的物理内存还是一个。
在这里插入图片描述
如果主线程(父进程)要修改共享数据里的某一块数据(比如键值对 A)时,就会发生写时复制,于是这块数据的物理内存就会被复制一份(键值对 A’),然后主线程在这个数据副本(键值对 A’)进行修改操作。与此同时,bgsave 子进程可以继续把原来的数据(键值对 A)写入到 RDB 文件。
所以,主线程刚修改的数据,是没办法在这一时间写入 RDB 文件的,只能交由下一次的 bgsave 快照。

三、AOF + RDB

简介:当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。在这里插入图片描述

好处:重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。 加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。

对于以上所有内容有疑问,请留言~。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值