zoukankan      html  css  js  c++  java
  • Redis AOF日志备份原理

    何为 AOF ?

    AOF 的全称是 Append Only File,表示文件只能追加写。 Redis记日志时,用追加写文件的方式记录写命令操作。Redis 是先执行命令,把数据写入内存,然后才记录日志

    为何要执行后才打日志 ?

    避免出现记录错误命令, 写后日志这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错。

    它是在命令执行后才记录日志,所以不会阻塞当前的写操作

    不过,AOF 也有两个潜在的风险。首先,如果刚执行完一个命令,还没有来得及记日志就宕机了,那么这个命令和相应的数据就有丢失的风险。

    其次,AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。这是因为,AOF 日志也是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。

    当然如果能够控制一个写命令执行完后 AOF 日志写回磁盘的时机,这两个风险就解除了。

    AOF 写回策略

    AOF 机制提供了三种策略,可通过 AOF 配置项 appendfsync 来配置。

    策略 含义 解释
    Always 同步写回 每个写命令执行完,立马同步地将日志写回磁盘。
    Everysec 每秒写回 每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘。
    No 操作系统控制的写回 每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
    上述三种情况都不能同时解决阻塞和数据丢失的问题。

    可以根据自己的业务的特点,评估可靠性和高性能的取舍来选择更合适自己的策略。

    策略 优点 缺点
    Always 性能较差;可靠性高,数据基本不会丢失 每个写操作都要落盘,性能可能受比较大影响
    Everysec 性能中等 可能会丢失一秒的数据
    No 性能较好 可能会丢失较多数据

    AOF 重写机制

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

    所以便引入了 AOF 重写机制。简单来说,就是在重写时,Redis 根据数据库的现状创建一个新的 AOF 文件,也就是说,读取数据库中的所有键值对,然后对每一个键值对用一条命令记录它的写入。

    这时候是把库中的数据都重写一份到磁盘中,那这个操作会不会阻塞到主进程?其实和 AOF 日志由主线程写回不同,重写过程是由后台线程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。

    重写的具体逻辑是:每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。

    过程中会产生一份新的 AOF 日志文件,当过程中有新的数据写入。 这些数据会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,就可以用新的 AOF 文件替代旧文件。

    Redis采用 fork 子进程重写AOF文件时,也会产生潜在的阻塞风险。fork 子进程,fork这个瞬间一定是会阻塞主线程的(fork时并不会一次性拷贝所有内存数据给子进程),fork 采用操作系统提供的写实复制(Copy On Write)机制,为了避免一次性拷贝大量内存数据给子进程造成的长时间阻塞问题,但 fork 子进程需要拷贝进程必要的数据结构,其中有一项就是拷贝内存页表(虚拟内存和物理内存的映射索引表),这个拷贝过程会消耗大量 CPU 资源,拷贝完成之前整个进程是会阻塞的,阻塞时间取决于整个实例的内存大小,实例越大,内存页表越大,fork 阻塞时间越久。拷贝内存页表完成后,子进程与父进程指向相同的内存地址空间,也就是说此时虽然产生了子进程,但是并没有申请与父进程相同的内存大小。

    内存分配是以页为单位进行分配的,默认4k,如果父进程此时操作的是一个 bigkey,重新申请大块内存耗时会变长,可能会产阻塞风险。另外,如果操作系统开启了内存大页机制(Huge Page,页面大小2M),那么父进程申请内存时阻塞的概率将会大大提高,所以在Redis机器上需要关闭Huge Page机制

  • 相关阅读:
    敏捷实践-学习实践资料汇总
    从数据仓库到数据湖—浅谈数据架构演进
    JVM知识点汇总备忘
    Protobuf的使用和原理
    kafka数据定时导入hive便于后续做数据清洗
    Mybatis Mapper接口动态代理实现原理及二次开发
    软考论文-写作大纲-备考思路总结
    css3另一个属性写法
    css3动画效果
    jquery点击鼠标后关闭图片
  • 原文地址:https://www.cnblogs.com/onlyzc/p/13849700.html
Copyright © 2011-2022 走看看