【redis】关于写后日志、混合持久化

2023-05-11  本文已影响0人  Bogon

AOF写后日志,避免宕机数据丢失

写前日志(WAL,Write Ahead Log):在实际写数据之前,将修改的数据写到日志文件中,故障恢复得以保证。
比如 MySQL Innodb 存储引擎中的 redo log(重做日志)便是记录修改的数据日志,在实际修改数据前先记录修改日志再执行修改数据。

写后日志:先执行“写”指令请求,将数据写入内存,再记录日志。

1.什么是AOF写后日志?

AOF(Append Only File)写后日志,AOF 持久化就是将修改数据库状态的命令保存到 AOF 文件中,被写入的命令都是以 Redis 的命令请求协议格式保存的,Redis 的命令请求协议是纯文本格式。

假设 AOF 日志记录了 Redis 实例创建以来所有的修改指令序列,那么就可以通过一个空的 Redis 实例顺序执行所有的指令,也就是“重放”,来恢复Redis当前实例的内存数据结构的状态。

image.png

日志格式

当 Redis 接收到 “set key value” 命令将数据写入到内存之后,会按照如下格式写入 AOF 文件:

image.png

写后日志的好处

写后日志避免了额外的检查开销,不需要对执行的命令进行语法检查。
如果使用写前日志的话,就需要先检查语法是否有误,否则日志记录了错误的命令,在使用日志恢复的时候就会报错。
另外,写后记录日志,避免了阻塞当前“写”指令的执行。

2.写回策略

使用 AOF 也不是万无一失的,假如 Redis 刚执行完指令,还没记录日志就宕机了,就有可能丢失这个命令的相关数据;还有, AOF 避免了当前命令的阻塞,但是可能会给下一个命令带来阻塞的风险。
AOF 日志是主线程执行的,将日志写入磁盘过程中,如果磁盘压力过大就会导致磁盘写操作很慢,导致后续的“写”指令阻塞。

发现了没?这两个问题与磁盘写回有关。
如果能合理控制“写”指令执行完后 AOF 日志写回磁盘的时机,问题就可以迎刃而解。

为了提高文件的写入效率,当用户调用 write 函数,将一些数据写入到文件时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里,等到缓冲区的空间被填满或者超过了制定的限制之后,才真正将缓冲区中的数据写入到磁盘里面。

这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里的写入数据将会丢失。

为此系统提供了 fsync 和 fdatasync 两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里,从而确保写入数据的安全性。

与之相对应 Redis 提供了 AOF 配置项 appendfsync 写回策略来控制 AOF 持久化功能的效率和安全性。

# 同步写回,写指令执行完毕立即将 aof_buf 缓冲区中的内容写到 AOF 文件
appendfsync always     

# 每秒写回,写指令执行完毕,把日志写到 aof_buf 缓冲区,每隔一秒同步到磁盘,该策略为AOF的默认策略
appendfsync everysec   

# 操作系统控制,写指令执行完毕,把日志写到 aof_buf 缓冲区,由操作系统决定何时写回磁盘
appendfsync no         

3.AOF重写机制

由于 AOF 记录的是一个个指令的内容,这就会导致保存的文件太大,另外,故障恢复的时候需要执行每一个指令,如果日志文件太大,整个恢复过程就会非常慢。为此,Reids 设计了 AOF 重写机制,提供了 bgrewriteaof 命令用于对 AOF 文件进行瘦身。

其原理就是:开辟一个子进程对内存进行遍历转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件中,序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后立即替换旧的 AOF 日志文件,瘦身工作就完成了。

重写机制有“多变一”的功能,将旧日志中的多条指令,在重写后就变成了一条指令。

如下所示:三条 lpush 命令,经过 AOF 重写后生成一条,对于多次修改的场景,缩减效果明显。

image.png

重写过程

和 AOF 日志由主线程写回不同,重写过程实际是由后台子进程 bgrewriteof 完成的,这也是为了避免阻塞主线程,导致性能下降。

总的来说,一共出现两个日志,一次内存数据拷贝,分别是旧的 AOF 日志和新的 AOF 重写日志和Redis 数据拷贝。

大致流程如下图所示:

image.png

在上图中,Redis 会将重写过程中接收到的“写”指令操作同时记录到旧的 AOF 缓冲区和新的 AOF 重写缓冲区,这样重写日志也保存了最新的操作,等到拷贝数据的所有操作记录重写完成后,重写缓冲区记录的最新操作也会写到新的 AOF 文件中。

每次 AOF 重写时,Redis 会先执行一次内存拷贝,用于遍历数据生成重写记录,防止 AOF 重写过程失败,导致原 AOF 文件被污染,无法做恢复使用。

使用两个日志可以保证在重写过程中,新写入的数据不会丢失,并且保持数据的一致性。

4.AOF 的优点和缺点

优点

缺点

混合日志模型

重启 Redis 时,我们很少使用 RDB 来恢复内存状态,因为可能丢失大量数据。
通常采用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB 来说要慢很多,在Redis实例很大的情况下,启动需要花费很长时间。

Redis 4.0 为了解决这个问题,提供了一个新的持久化选项--混合持久化,将 RDB 文件的内容和增量 AOF 日志文件存放到一起,这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分日志很小。

image.png

在 Redis 重启的时候,先加载 RDB 的内容,然后再重放增量 AOF 日志,这样的操作既保证了 Redis 重启速度,又降低数据丢失风险。

总结

参考

Redis持久化:RDB和AOF
https://mp.weixin.qq.com/s/IaJrBwUuJt_DFjIynIzF5g

Redis设计与实
https://weread.qq.com/web/reader/d35323e0597db0d35bd957bk73532580243735b90b45ac8

Redis核心技术与实战
https://time.geekbang.org/column/intro/329

上一篇 下一篇

猜你喜欢

热点阅读