• Redis稳定性之战:AOF日志支撑数据持久化


    Redis24篇集合

    1 介绍

    AOF(Append Only File)持久化:以独立日志的方式存储了 Redis 服务器的顺序指令序列,并只记录对内存进行修改的指令。
    当Redis服务发生雪崩等故障时,可以重启服务并重新执行AOF文件中的指令达到恢复数据的目的。也就是说,通过重放(replay),来重新建立 Redis 当前实例的内存数据结构。这种模式有没有很熟悉,可以联想到MySQL主从同步时的relay log。
    相对于咱们上一篇介绍的《RDB内存快照提供持久化能力》定点快照的做法,AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。

    2 AOF实现日志记录

    2.1 开启AOF日志记录

    1、 开启AOF日志记录:在redis.conf文件中,找到 APPEND ONLY MODE 设置

    appendonly yes  # 默认不开启, 为 no
    

    2、配置默认文件名:在redis.conf文件中设置

    appendfilename “appendonly.aof”
    

    2.2 执行流程

    image

    流程如上图所示,我们解析如下:

    2.2.1 将所有的写命令(set、hset)Append 到aof_buf缓冲区中

    Redis 接收到 set keyName someValue 命令的时候,会先将数据写到内存,Redis 会按照如下格式写入 AOF 文件。

    1. *3:表示当前指令分为三个部分,每个部分都是 $ + 数字开头,后面是3部分的具体内容:指令、键、值。
    2. 数字:表示这部分的命令、键、值多占用的字节大小。比如 $3表示这部分包含 3 个字符,也就是 set 的长度。

    我们看看一个典型的aof文件示例,为了清晰表示,下面的注释都是手动加的:

    [root@localhost bin]#vim appendonly.aof
    #  执行 set key value
    *3
    $3           # 这边代表set命令,长度为3
    set
    $9 
    user_name      # 这边代表keyName,长度为9
    $5 
    brand      #  这边代表keyValue,长度为5
    
    
    # 执行 mset key1 1 ,key2 2 ,key33 3
    # aof日志如下:
    *7  # 本批命令需要往下读7行非 $ 开始的命令
    $4  #接着读取4个字节宽度,‘mset’长度为4,记为 $4
    mset
    $4  #接着读取4个字节宽度,‘key1’长度为4,记为 $4
    key1
    $1  #接着读取1个字节宽度,‘1’长度为1,记为 $1
    1
    $4
    key2
    $1
    2
    $5  #接着读取的字节宽度,‘$key33’长度为5,记为 $5
    key33
    $1
    3
    

    2.2.2 AOF缓冲区根据策略向硬盘做sync同步

    AOF为什么把命令append到aof_buf中,然后再进行同步?
    这是因为Redis使用单进程响应命令(参考笔者这篇《深刻理解高性能Redis的本质》),如果每次写AOF文件命令都直接持久化到硬盘,那么操作会是不是被间断,且性能完全取决于硬盘I/O负载。这个跟 MySQL 就没啥区别了。
    先写入缓冲区aof_buf中,Redis可以提供多种缓冲区同步硬盘的策略,在性能、安全、数据可靠性方面做出平衡。

    同步策略需关注以下几个配置:

    1、 appendfsync 模式

    appendfsync always  # 接受写命令后立即写入磁盘,强持久化但执行慢,不推荐
    appendfsync everysec # 每秒写入磁盘一次, 性能和持久化方面做了折中, 推荐
    appendfsync no  #  依赖操作系统自身同步的配置和策略,性能较佳,但是没法保证实时和完全持久化
    

    2、no-appendfsync-on-rewrite
    在 AOF 重写期间是否禁用 fsync。这可以提高重写性能,但可能会增加数据丢失的风险。

    # 默认值:no
    # 可选值:yes 或 no
    no-appendfsync-on-rewrite yes
    

    2.2.3 AOF文件Rewrite实现压缩

    随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩减负的目的,避免AOF文件过大导致性能和数据可靠性问题。
    重写后的AOF文件变小的原因主要有以下几点:
    1、进程内已超时的数据不再写入:在重写过程中,Redis不会将已经超时的数据写入新的AOF文件,这有助于减少不必要的数据记录。
    2、删除无效命令:旧的AOF文件中可能包含无效的命令,如del key1hdel key2srem keysset a111等。重写过程会识别并删除这些无效命令,只保留最终数据的写入命令,从而减小了文件大小。
    3、合并多条写命令:为了进一步优化AOF文件的大小,重写过程会将多条写命令合并为一个。例如,lpush list alpush list blpush list c可以合并为lpush list a b c。这种合并减少了命令的数量,进而减小了AOF文件的大小。
    4、防止单条命令过大:对于某些操作类型(如list、set、hash、zset),为了防止单条命令过大造成客户端缓冲区溢出,重写过程会以64个元素为界拆分多条命令。虽然这在一定程度上可能增加了命令的数量,但它确保了每条命令的大小都在可控范围内,有助于维持整体文件大小的合理性。
    总之AOF重写降低了文件占用空间,同时提升加载性能,因为更小的AOF 文件可以更快地被Redis加载。

    AOF重写关注以下配置:
    1、auto-aof-rewrite-percentage
    触发 AOF 重写的增长百分比。例如,如果当前 AOF 文件大小是 100MB,并且这个值设置为 100,那么当 AOF 文件增长到 200MB 时,说明增长了100%,Redis 会尝试重写 AOF。

    # 默认值:`100`
    `auto-aof-rewrite-percentage 100`
    

    2、auto-aof-rewrite-min-size

    AOF 文件的最小大小,以便触发重写。即使 AOF 文件的增长百分比超过了 auto-aof-rewrite-percentage 设置的值,但如果文件大小小于这个值,Redis 也不会触发重写。

    # 默认值:`64mb`
    auto-aof-rewrite-min-size 64mb
    

    image

    2.2.4 故障重启时的数据恢复

    当Redis服务器重启时,可以加载AOF文件进行数据恢复。
    image

    流程如下:

    1. 当AOF和RDB文件同时存在时,优先加载AOF
    2. 若关闭了AOF(apendonly no),则加载RDB文件
    3. 加载AOF/RDB成功之后,redis重启成功。如果无相关的持久化,则直接启动成功。
    4. 如果AOF/RDB 数据恢复存在错误,则启动失败,并打印输出错误信息

    2.3 RDB和AOF的比较和混合持久化

    咱们上一篇介绍了《RDB内存快照提供持久化能力》定点快照的用户,那RDB跟AOF究竟孰优孰虑?
    现实情况下,无论使用RDB或者AOF都差点意思。使用 rdb 来恢复内存状态,势必会丢失一部分数据。使用 AOF 日志重放,重放对性能有一定的影响,而且在 Redis 实例很大的情况下,需要花费很长的时间。
    Redis 4.0 解决了这个问题,才用了一个新的持久化模式——混合持久化,该 混合模式 默认是关闭状态的。
    将 RDB 文件的内容和 rdb快照时间点之后的增量的 AOF 日志文件存在一起。这时候 AOF 日志不需要再是全量的日志,而是最近一次快照时间点之后到当下发生的增量 AOF 日志,通常这部分 AOF 日志很小。
    所以执行有如下顺序:

    • 查找rdb内容,如果存在先加载 rdb内容再 重放剩余的 aof。
    • 没有rdb内容,直接以aof格式重放整个文件。
      这样快照就不用频繁的执行,同时由于 AOF 只需要记录最近一次快照之后的数据,不需要记录所有的操作,避免了出现单次重放文件过大的问题。

    开启混合持久化模式:

    aof-use-rdb-preamble yes
    

    这个设置告诉Redis在AOF重写时使用混合持久化模式。当这个选项设置为yes时,重写后的AOF文件将包含RDB格式的数据前缀和AOF格式的增量修改操作。

    总结

    • RDB提供了快照模式,记录某个时间的Redis内存状态。RDB设计了 bgsave 和写时复制,尽可能避免执行快照期间对读写指令的影响,但是频繁快照会给磁盘带来压力以及 fork 阻塞主线程。需把握频率。
    • AOF 日志存储了 Redis 服务的顺序指令序列,通过重放(replay)指令来写入日志文件,并通过写回策略来避免高频读写给Redis带来压力。
    • RDB快照的照片时间间隔,必然会带来数据缺失,如果允许分钟级别的数据丢失,可以只使用 RDB。
    • 如果只用 AOF,写回策略优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
    • 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择。
  • 相关阅读:
    CTF-PWN-堆- 【off-by-one】
    基于Spring Boot应用Java原生JDBC操作数据库(查增改删)
    【2. MVCC-多版本并发控制技术】
    搭建免费的ftp服务器
    语义分割的常用方法和评价准则
    Android中focusableInTouchMode会导致第一次点击事件失效
    深入C++ Vector:解密vector的奥秘与底层模拟实现揭秘
    Rust的一些特性
    【机器学习】模型训练:线性模型的公式法与三种梯度下降法求解
    Excel逆向查询的多种方法,赶快学起来
  • 原文地址:https://www.cnblogs.com/wzh2010/p/18049659