• Redis AOF 文件重写流程


    Redis 作为一种非常流行的内存数据库,通过将数据保存在内存中,Redis 得以拥有极高的读写性能。但是一旦进程退出,Redis 的数据就会全部丢失。
    为了解决这个问题,Redis 提供了 RDB 和 AOF 两种持久化方案,将内存中的数据保存到磁盘中,避免数据丢失。本文将重点讨论AOF持久化方案,以及其存在的一些问题,并探讨在Redis 7.0 (已发布RC1) 中Multi Part AOF(下文简称为MP-AOF,本特性由阿里云数据库Tair团队贡献)设计和实现细节。

    一  AOF


    AOF( append only file )持久化以独立日志文件的方式记录每条写命令,并在 Redis 启动时回放 AOF 文件中的命令以达到恢复数据的目的。
    由于AOF会以追加的方式记录每一条redis的写命令,因此随着Redis处理的写命令增多,AOF文件也会变得越来越大,命令回放的时间也会增多,为了解决这个问题,Redis引入了AOF rewrite机制(下文称之为AOFRW)。AOFRW会移除AOF中冗余的写命令,以等效的方式重写、生成一个新的AOF文件,来达到减少AOF文件大小的目的。

    二  AOFRW


    图1展示的是AOFRW的实现原理。当AOFRW被触发执行时,Redis首先会fork一个子进程进行后台重写操作,该操作会将执行fork那一刻Redis的数据快照全部重写到一个名为temp-rewriteaof-bg-pid.aof的临时AOF文件中。 
    由于重写操作为子进程后台执行,主进程在AOF重写期间依然可以正常响应用户命令。因此,为了让子进程最终也能获取重写期间主进程产生的增量变化,主进程除了会将执行的写命令写入aof_buf,还会写一份到aof_rewrite_buf中进行缓存。在子进程重写的后期阶段,主进程会将aof_rewrite_buf中累积的数据使用pipe发送给子进程,子进程会将这些数据追加到临时AOF文件中(详细原理可参考[1])。
    当主进程承接了较大的写入流量时,aof_rewrite_buf中可能会堆积非常多的数据,导致在重写期间子进程无法将aof_rewrite_buf中的数据全部消费完。此时,aof_rewrite_buf剩余的数据将在重写结束时由主进程进行处理。
    当子进程完成重写操作并退出后,主进程会在backgroundRewriteDoneHandler 中处理后续的事情。首先,将重写期间aof_rewrite_buf中未消费完的数据追加到临时AOF文件中。其次,当一切准备就绪时,Redis会使用rename 操作将临时AOF文件原子的重命名为server.aof_filename,此时原来的AOF文件会被覆盖。至此,整个AOFRW流程结束。

    图1 AOFRW实现原理

    三  AOFRW存在的问题


    1  内存开销


    由图1可以看到,在AOFRW期间,主进程会将fork之后的数据变化写进aof_rewrite_buf中,aof_rewrite_buf和aof_buf中的内容绝大部分都是重复的,因此这将带来额外的内存冗余开销。
    在Redis INFO中的aof_rewrite_buffer_length字段可以看到当前时刻aof_rewrite_buf占用的内存大小。如下面显示的,在高写入流量下aof_rewrite_buffer_length几乎和aof_buffer_length占用了同样大的内存空间,几乎浪费了一倍的内存。

    aof_pending_rewrite:0
    
    aof_buffer_length:35500
    
    aof_rewrite_buffer_length:34000
    
    aof_pending_bio_fsync:0
    

      

    当aof_rewrite_buf占用的内存大小超过一定阈值时,我们将在Redis日志中看到如下信息。可以看到,aof_rewrite_buf占用了100MB的内存空间且主进程和子进程之间传输了2135MB的数据(子进程在通过pipe读取这些数据时也会有内部读buffer的内存开销)。
    对于内存型数据库Redis而言,这是一笔不小的开销。

    3351:M 25 Jan 2022 09:55:39.655 * Background append only file rewriting started by pid 6817
    3351:M 25 Jan 2022 09:57:51.864 * AOF rewrite child asks to stop sending diffs.
    6817:C 25 Jan 2022 09:57:51.864 * Parent agreed to stop sending diffs. Finalizing AOF...
    6817:C 25 Jan 2022 09:57:51.864 * Concatenating 2135.60 MB of AOF diff received from parent.
    3351:M 25 Jan 2022 09:57:56.545 * Background AOF buffer size: 100 MB
    

     

    AOFRW带来的内存开销有可能导致Redis内存突然达到maxmemory限制,从而影响正常命令的写入,甚至会触发操作系统限制被OOM Killer杀死,导致Redis不可服务。

    2  CPU开销


    CPU的开销主要有三个地方,分别解释如下:

    1. 在AOFRW期间,主进程需要花费CPU时间向aof_rewrite_buf写数据,并使用eventloop事件循环向子进程发送aof_rewrite_buf中的数据:
    1. 在子进程执行重写操作的后期,会循环读取pipe中主进程发送来的增量数据,然后追加写入到临时AOF文件:
    1. 在子进程完成重写操作后,主进程会在backgroundRewriteDoneHandler 中进行收尾工作。其中一个任务就是将在重写期间aof_rewrite_buf中没有消费完成的数据写入临时AOF文件。如果aof_rewrite_buf中遗留的数据很多,这里也将消耗CPU时间。

    AOFRW带来的CPU开销可能会造成Redis在执行命令时出现RT上的抖动,甚至造成客户端超时的问题。

    3  磁盘IO开销


    如前文所述,在AOFRW期间,主进程除了会将执行过的写命令写到aof_buf之外,还会写一份到aof_rewrite_buf中。aof_buf中的数据最终会被写入到当前使用的旧AOF文件中,产生磁盘IO。同时,aof_rewrite_buf中的数据也会被写入重写生成的新AOF文件中,产生磁盘IO。因此,同一份数据会产生两次磁盘IO。

    转载自阿里云公众号

  • 相关阅读:
    asp.net jquery+ajax异步刷新1
    Android自定义组合控件:UIScrollLayout(支持界面滑动及左右菜单滑动)
    南京三星面试准备1--字符串
    如何有效的设立目标
    MySQL 主主复制
    POJ 2914 Minimum Cut 最小割算法题解
    openstack中虚拟机怎么与物理机通信
    SpringMVC+Spring+Mybatis+Mysql项目搭建
    Android面试准备 第二天 第五例 数据存储
    COCOS2D-X 3.0在MAC下创建新IOS项目:
  • 原文地址:https://www.cnblogs.com/lovezhr/p/15886823.html
Copyright © 2020-2023  润新知