redis基础4——RDB持久化、AOF持久化全面深入解读

news2024/9/19 10:49:25

文章目录

  • 一、redis持久化机制
    • 1.1 持久化的背景
    • 1.2 两种持久化概念
      • 1.2.1 快照方式(RDB)
      • 1.2.2 文件追加方式(AOF)
    • 1.3 rdb持久化(Redis Database)
      • 1.3.1 快照原理
      • 1.3.2 触发机制
        • 1.3.2.1 手动触发
          • 1.3.2.1.1 save手动触发
          • 1.3.2.1.2 bgsave手动触发
          • 1.3.2.1.2 flushall手动触发
          • 1.3.2.1.3 shutdown手动触发
        • 1.3.2.2 自动触发
          • 1.3.2.2.1 “save m n”实现原理
          • 1.3.2.2.2 配置策略自动触发
          • 1.3.2.2.3 主从同步自动触发
      • 1.3.3 rdb文件细节介绍
        • 1.3.3.1 文件位置
        • 1.3.3.2 文件名称
        • 1.3.3.3 参数设定方式
      • 1.3.4 快照恢复
      • 1.3.5 优缺点
    • 1.4 AOF持久化(Append Only File)
      • 1.4.1 AOF机制实现原理
      • 1.4.2 AOF持久化流程
        • 1.4.2.1 命令追加
          • 1.4.2.1.1 AOF文件内容解析
          • 1.4.2.1.2 AOF文件内容修复
        • 1.4.2.2 文件写入
        • 1.4.2.3 文件同步
          • 1.4.2.3.1 三种策略比较
      • 1.4.3 重写机制
        • 1.4.3.1 重写机制原理
        • 1.4.3.2重写机制流程(瘦身运动)
        • 1.4.3.3 重写机制触发
          • 1.4.3.3.1 手动触发
          • 1.4.3.3.2 自动触发(策略)
      • 1.4.4 AOF持久化配置参数详解
        • 1.4.4.1 AOF持久化开启与关闭
        • 1.4.4.2 修改日志文件名
        • 1.4.4.3 持久化策略
        • 1.4.4.4 自动重写触发策略
        • 1.4.4.5 日志重写时是否开启命令追加
        • 1.4.4.6 是否忽略最后有问题的命令
        • 1.4.4.7 是否开启混合持久化
      • 1.4.5 优缺点
        • 1.4.5.1 优点
        • 1.4.5.2 缺点

一、redis持久化机制

1.1 持久化的背景

  • redis的读写操作都是在内存中进行的,但是内存中的数据会因为服务器的异常宕机或断电情况而丢失,这对生产环境来说,是极其恶劣的情况。那么要保证这种情况下数据不丢失,redis官方就研究了数据持久化机制。这也是 Redis 和 Memcached 的主要区别之一,因为 Memcached 不具备持久化功能。

先简单聊一下redis持久化,持久化机制有两种,第一种是RDB快照,第二种是 AOF 日志。

  • 快照是一次全量备份,AOF 日志是连续的增量备份。
  • 快照是内存数据的二进制序列化形式,在存储上非常紧凑,而AOF 日志记录的是内存数据修改的指令记录文本。前者记录执行后的结果,或者记录执行命令(对数据进行修改的命令,查询命令不记录)。
  • AOF 日志在长期的运行过程中会变的无比庞大,数据库重启时会优先加载 AOF 日志进行指令重放,这个时间就会无比漫长。所以需要定期进行 AOF 重写,给 AOF 日志进行瘦身。

在这里插入图片描述

1.2 两种持久化概念

  • Redis 持久化拥有以下三种方式。
  • 每种持久化方案都有自己的优缺点,所以在项目中需视情况去选取哪种方式使我们的服务运行最高效、数据最安全。

1.2.1 快照方式(RDB)

快照方式(RDB, Redis DataBase),是指在指定的时间间隔内将内存中的数据集快照写入磁盘,将内存中数据以快照的方式写入到二进制文件中,跟VMware的快照机制一样。同时也是默认的持久化方式,这一点可以在redis.conf配置文件里体现("save n m "规则,rdb持久化规则是默认开启的),而aof持久化默认关闭状态。

1.2.2 文件追加方式(AOF)

文件追加方式(AOF, Append Only File),记录所有的对数据进行修改的操作命令,并以文本的形式追加到文件落盘。

1.3 rdb持久化(Redis Database)

1.3.1 快照原理

Redis在研发之初就是“高效”的代名词,但作为单线程的它,要同时负责多个客户端请求的并发读写,还要兼顾内存数据结构的逻辑读写。换句话说,不仅要处理服务线上的请求,还要备份内存数据。但在备份过程中redis是必须进行文件IO读写,而IO读写操作又会影响服务器的性能,这样一来就达不到“高效”的目的了,那该怎么办呢?创始人就想到操作系统的多进程COW(Copy On Write)机制来实现快照的持久化。

  1. rdb实际上是redis内部的一个定时器事件,通过bgsave触发机制(手动触发或自动触发)去调用操作系统glibc的fork()函数产生一个子进程。在子进程产生之前的这段时间,主进程一直处于阻塞状态。执行bgsave命令的时候,Redis主进程会检查是否有子进程在执行RDB/AOF持久化任务,如果有的话,直接返回。
  2. 如果没有持久化任务就会产生一个子进程。当子进程产生时,Linux操作系统机制会让父子进程共享内存里面的代码段和数据段(数据段是由很多操作系统页面组合而成,见下图),这是属于操作系统层面上的内存调优,可以节约内存资源。此时我们可以把两个进程比作“连体婴儿”,两进程分离时的数据几乎是一样的。
  • 分离背景:
    • fork 函数会让父子进程同时返回结果,在父进程里返回子进程的 pid,在子进程里返回零。如果操作系统内存资源不足,pid 就会是负数,则表示 fork 失败。
    • 子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改,这样才符合redis之初的设计理念——高效。
  • 分离逻辑:
    • 在子进程产生的同时,操作系统内核COW机制会把主进程中的所有内存页权限设为read-only状态。
    • 当主进程有写内存的操作时(应对客户端新请求,会有对内存数据结构修改的写操作),cpu会检测到主进程的内存页是read-only的,从而触发页异常中断(page-fault),形成内核的一个中断例程,此时系统内核就会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。此时子进程自己的页面是没有发生变化的,还是进程产生时那一瞬间的数据,因为在子进程是完全不知道主进程发生了什么,主进程也不知道子进程在做什么,可以理解为父子进程分开之后做各自工作时是不知道对方在做什么。
  1. 子进程因为数据没有变化,它能看到的内存数据,就只是在它产生的那一瞬间就凝固不变了,这也是为什么 redis 的持久化叫「快照」的原因。接下来子进程就可以非常安心的遍历数据进行序列化写入磁盘了。将内存数据进行扫描读取并写入到一个临时rdb文件中,等所有的数据写入完成后就会原子性地替换之前的rdb文件,从而将数据保存到磁盘中。
  2. 就此,一个rdb持久化流程走完,子进程退出。
  3. 子进程工作的同时,父进程依然在接受客户端的请求,随着写操作的持续进行,越来越多的共享页面被分离出来,内存就会持续增长。但是也不会超过原有数据内存的 2 倍大小。另外一个 Redis 实例里冷数据占的比例往往是比较高的,所以很少会出现所有的页面都会被分离,被分离的往往只有其中一部分页面。每个页面的大小只有 4K,一个 Redis 实例里面一般都会有成千上万的页面。

在这里插入图片描述

1.3.2 触发机制

触发机制可以分为,手动触发和自动触发。

1.3.2.1 手动触发

  • 手动触发,顾名思义就是可以通过我们敲命令去实现。
  • 有三个命令,save、bgsave和flushall,前两个命令执行过程有点相似,但又有些不同,所以优缺点也有些不同。
1.3.2.1.1 save手动触发
  • 在客户端执行save命令后,触发rdb持久化,将当前redis内存里的所有数据快照以rdb文件的形式保存在指定目录。save命令输入回车开始,到rdb文件创建完毕的这段时间内会阻塞redis主线程,使其被挂起,在没有得到rdb文件没有创建完之前的这段时间内不能响应处理其他客户端发来的请求。所以数据量越大的情况下,阻塞时间越长。
  • 这在项目上是禁止使用的。

进程阻塞为什么不消耗CPU?

  • 进程执行的过程的确是在内核CPU中执行的,会消耗CPU。但是当进程阻塞变成等待态的时候,会被加入该socket的等待队列中,并不会出现在内核中了,而是在socket的等待队列中“等待”。当进程被操作系统唤醒后,又会被加入到工作队列中。
  • 示例

在这里插入图片描述

1.3.2.1.2 bgsave手动触发
  1. bgsave ,相比save来说最大的区别就是bgsave会通过操作系统的多进程COW机制的fork函数生成一个子进程来执行持久化,只有父进程在fork子进程的这段时间内才会发生阻塞,这比save阻塞时间短得多,可以忽略不计。
  2. 子进程产生后,不会立马对数据进行复制,此时父进程与子进程是共享内存数据的。同时kernel(内核函数)会把父进程中的所有内存页的权限设为只读状态。
  3. 当发生写操作时,父进程只能读,所以会触发内存页异常中断,此时就会复制分离一份数据到共享空间,然后子进程写入磁盘,写完之后会销毁子进程,从而生成rdb持久化文件。
  • 示例

在这里插入图片描述

1.3.2.1.2 flushall手动触发

客户端输入flushall命令时也会手动触发rdb持久化机制,清空所有数据库的数据,生产环境禁止使用。

在这里插入图片描述

1.3.2.1.3 shutdown手动触发

停止redis服务,会自动执行一次bgsave,也会触发rdb持久化机制。

在这里插入图片描述

1.3.2.2 自动触发

自动触发,就是程序自己读取对应的规则从而触发rdb持久化机制,这个规则可以由我们在redis.conf文件中来定义。

1.3.2.2.1 “save m n”实现原理

配置文件里的 “save m n” 参数是通过serverCron函数、dirty计数器、和lastsave时间戳共同来实现的。

  • serverCron函数:是redis服务的周期性操作函数,默认每隔100ms执行一次,负责管理服务器的资源,其中一项工作就是检查redis.conf配置文件的 “ save m n ” 配置的条件是否满足,如果满足就执行bgsave。
  • dirty计数器:记录距离上一次成功执行save命令或者bgsave命令后,服务器对redis数据库(服务器中的所有数据库)进行了多少次修改(包括写入、删除、更新等操作)。而当save/bgsave执行完成后,会将dirty重置为0。
    • 举个例子,在redis客户端执行一条命令”set key1 v1“,则dirty值会+1;如果执行了一条命令"sadd key2 v1 v2 v3",则dirty值会+3。所以我们可以看出,dirty记录的是对数据库的数据变化的次数,而不是客户端执行了多少条修改数据的命令。
  • astsave时间戳:是一个UNIX时间戳,记录上一次成功执行save命令或者bgsave命令的时间。

“save m n”的原理:

  1. 每隔100ms,执行serverCron函数,redis遍历“save m n”对应的rdb规则,只要满足其中一个,就进行执行bgsave。那么要怎么才能满足我们的配置条件呢?这时候就是dirty计数器和lastsave时间戳来起作用了。

    • lastsave可以查看上次成功执行save/bgsave命令的时间,这里的时间对应条件中的m值。
    • dirty可以查看距离上次成功执行save/bgsave命令后数据发生变化的次数,这里的次数就对应条件中的n值。
  2. 当同时满足条件中的m和n值时,就会触发rdb持久化执行一次bgsave。每次执行完后,会将dirty重置为0。所以每次创建 RDB 文件之后,Redis 服务器设置的时间计数和次数计数就会被清零,并重新开始计数,因此多个策略的效果不会叠加。

1.3.2.2.2 配置策略自动触发
  1. 自动触发策略在redis.conf配置文件中配置,“save m n”。
  2. "save m n "的含义是在时间 m 秒内,如果 Redis 数据至少发生了 n 次变化,那么就自动执行bgsave命令。
  • “save 900 1” 表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发bgsave 命令,将数据保存到硬盘。
  • "save 300 10 "表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 bgsave 命令,将数据保存到硬盘。
  • “save 60 10000 ”表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发bgsave 命令,将数据保存到硬盘。
  • 不设置save指令,或者给save传入空字符串,则禁用该功能,默认是启动读取触发规则的。

在这里插入图片描述

1.3.2.2.3 主从同步自动触发
  1. slave连接master时,发送sync。
  2. master执行bgsave触发持久化机制,同时缓存记录该段时间内的写操作。
  3. master向所有slave发送rdb持久化文件。
  4. slave接收到rdb持久化文件后,会删除就得rdb文件,装在新的rdb文件。
  5. master向所有slave发送刚刚缓存记录中得写操作。

1.3.3 rdb文件细节介绍

1.3.3.1 文件位置

dir参数,该参数指定持久化文件存放位置,也包括aof文件。

在这里插入图片描述

1.3.3.2 文件名称

dbfilename参数,指定rdb文件名,默认就是dump.rdb。

在这里插入图片描述

1.3.3.3 参数设定方式

1、第一种就是在redis.conf配置文件里配置,这种方式需要重启服务才能生效。
2、第二种是动态设定,就是服务启动后在客户端里用命令来修改,当磁盘损坏或空间不足时可以急救。但是这种方式重启服务后会失效。

  • 执行命令
# config set [参数]  [自定义新内容]
127.0.0.1:6379> config set dbfilename wuhan.dump
  • 执行效果

在这里插入图片描述

1.3.4 快照恢复

  • 当 redis 服务器启动时,如果 Redis 根目录存在 RDB 文件 dump.rdb,Redis 就会自动加载 RDB 文件恢复持久化数据。
  • 如果根目录没有 dump.rdb 文件,需要先将 dump.rdb 文件移动到 Redis 的根目录。
  • redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。
  • 验证 RDB 文件是否被加载 Redis 在启动时有日志信息,会显示是否加载了 RDB 文件,我们执行 Redis 启动命令,如图所示。

在这里插入图片描述

在这里插入图片描述

1.3.5 优缺点

  • 优点
  • rdb文件里记载的是二进制数据,占用内存更小,更紧凑,更适合做为备份文件。
  • 就因为它是一个紧凑文件,所以非常适合定时备份,常用于大规模的数据恢复、灾难恢复。
  • 同时rdb可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作。
  • redis加载rdb文件的速度比aof快很多,正因为rdb文件中是存储的是内存里的数据,而aof文件中存储的是一条条命令,需要重演命令。怎么理解呢?比如插入一条数据“set key1 v1”,rdb文件里存的是value,也就是这里的"v1",aof存的是整条命令"set key1 v1"。
  • 缺点
  • 因为 rdb是根据持久化机制来操作的,只能保存某个时间间隔的数据,倘若中途 redis 服务被意外终止了,则会丢失这段时间内还在内存里的数据。
  • rdb每次持久化时,主进程都需要 fork() 一个子进程才能将内存里的数据持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟,也就是主进程fork子进程这段阻塞时间会被拉长。

1.4 AOF持久化(Append Only File)

  • AOF持久化是以日志的形式来记录每个写操作,换句话讲就是记录对内存进行修改的命令(查询命令不会记录),所以AOF日志是存储的redis服务器的顺序指令序列,以文本的方式记录命令本身,不记录命令执行后产生的结果。
  • 如果AOF 日志记录了从 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对另外一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。
  • Redis 会在收到客户端修改指令后,先进行参数校验,如果没问题,就立即将该指令文本存储到 AOF 日志中,也就是先存到磁盘,然后再执行指令。这样即使遇到突发宕机,已经存储到 AOF 日志的指令进行重放一下就可以恢复到宕机前的状态。
  • AOF 的日志会在持续运行中持续增大,由于redis重启过程会有限加载AOF日志进行指令重放操作来恢复数据,重放时间非常耗时,会导致redis长时间无法对外提供服务,所以需要对 AOF 日志瘦身。

1.4.1 AOF机制实现原理

每当有一个修改数据库的命令被执行时,服务器就将命令写入到 appendonly.aof 文件(默认名,可修改)中,该文件存储了服务器执行过的所有修改命令。所以,只要服务器重新执行一次 aof 文件,就可以实现还原数据的目的,这个过程被形象地称之为“命令重演”。

1.4.2 AOF持久化流程

AOF持久化流程细分三个步骤:命令追加、文件写入(调用函数)、文件同步(调用策略)。

1.4.2.1 命令追加

当AOF持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾。

  • 为什么会先追加到aof_buf缓冲区?
    • 好处一,可以优化性能,提高写入效率。 因为AOF是文件操作,对于变更操作比较密集的server机器来说,会加重磁盘IO的负荷,倘若是直接追加到硬盘,那么写入的效率完全取决与当前硬盘的负载。这里提一点,Linux操作系统对文件操作采取了“延迟写入”手段,并非每次写操作都会直接触发磁盘操作,而是先写入到内存中的buffer区,当buffer数据达到阀值时再触发实际写入(当然也有其他触发机制,这里不做过多讨论)。
    • 好处二,可以提供多种缓冲区数据同步硬盘的策略(也就是后文的函数使用命令同步),在性能和安全方面做出平衡。
  • 为什么AOF文件内容是以redis命令请求协议格式保存的?
    • 因为redis的命令请求协议是纯文本格式,我们直接打开AOF文件,可以直观里面的内容。这跟rdb文件区别很大的,rdb文件内容需要借助rdbtools工具辅助来查看。
1.4.2.1.1 AOF文件内容解析

比如在客户端执行这个命令,127.0.0.1:6379> set key1 v1,则会在AOF缓冲区追加如下文本:

$3   #set指令字符串的长度。
set  #代表set指令。
$4   #代表插入的key的名称字符串长度,这里就是指key1字符串长度。
key1   #key值。
$2    #代表插入value值的字符串长度,这里就是指v1字符串长度。
v1    #value值。
1.4.2.1.2 AOF文件内容修复

官方提供了AOF文件内容修复工具redis-check-aof,在redis安装同级目录下。aof文件里出现非redis命令会进行修复。

在这里插入图片描述

  • 示例
  1. 此时aof文件里记录的是正常的redis数据。

在这里插入图片描述
2. 现在在aof里插入非redis数据,模拟aof文件被故意破坏。

在这里插入图片描述
3. 此时重启redis才能重新读写aof文件里的命令数据。

 redis-cli shutdown
redis-server redis.conf 

在这里插入图片描述
4. 命令修复

redis-check-aof --fix appendonly.aof

在这里插入图片描述
5. 命令修复后需要重新启动服务,就可以正常连接了。

1. redis-server  redis.conf
2. redis-cli 

在这里插入图片描述

1.4.2.2 文件写入

当数据进入到aof_buf缓冲区后,就要开始将数据写入到硬盘中了,但是这一个步骤不简单,过程中会调用flushAppendOnlyFile函数,这个函数决定了是否需要将 AOF 缓存区中的内容写入同步到 AOF 文件中。而以哪种方式同步?在redis.conf配置文件里有个参数“appendfsync”会提供三种方式,也是下面要讲的“命令同步”。

  • 写入过程:
    • redis的服务器进程是一个事件循环(loop),这个循环中的文件事件是负责接收客户端的命令请求的,所以接受请求后会有可能执行写操作,一旦有写操作就需要把数据会追加到aof_buf缓冲区,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,函数会根据redis.conf里的配置策略将aof_buf缓冲区中的内容写入和保存到AOF文件里。
    • 至于以哪种策略写入到AOF文件里,我们后文详谈,这里我们只先了解整个流程细节。提一点,在整个过程中,还有时间事件来负责执行像serverCron函数这样需要定时运行的函数。

1.4.2.3 文件同步

flushAppendOnlyFile函数的行为由配置文件里的“appendfsync”参数来决定。官方提供了三种方式,其中everysec是appendfsync选项的默认值。

  1. appendfsync always:每次写入都执行fsync函数,立马同步地将日志写回磁盘。
  2. appendfsync everysec:每次写命令执行完,先把日志写到aof_buf缓冲区,再每秒执行一次fsync函数将缓冲区地内从写入到磁盘,这样可能会导致丢失这1s数据。
  3. appendfsync no:每次写命令执行完,先把日志写到aof_buf缓冲区,不执行fsync函数,由操作系统保证决定何时将缓冲区的日志写回磁盘。
  • 为什么要做AOF持久化策略?
    • 因为这样可以保证数据一定的安全性。如果遇到宕机,缓存内的数据还没有落盘,会存在数据丢失的风险,丢失数据的多少取决于落盘时间。而官方就是使用到Linux系统的fsync()函数,将指定文件内容从内核缓存刷到硬盘,定义这个写入频率来控制写入磁盘的数据量。
1.4.2.3.1 三种策略比较
配置项写回机制 优点缺点
always同步写回安全性最高,速度最慢
everysec每秒写回性能适中
no操作系统控制写回频率速度最快,安全性最低
  1. always模式下效率最低,但安全性最高。出现宕机时,AOF持久化也只会丢失一个时间循环中所产生的命令数据。
  2. everysec模式下性能适中,也是官方建议的默认模式。
  3. no模式下效率最高,但安全性最低。但这种模式单词同步时长通常是三种模式中时间最长的,因为这种模式是根据操作系统来控制回写的,期间缓冲区会一直积累这段时间的写入数据。当出现宕机时,服务器将会丢失上次同步AOF文件之后的所有写命令数据。

1.4.3 重写机制

重写机制产生的原因?
可以解决AOF日志文件过大带来的性能问题。

  • 文件系统本身对文件大小有限制,无法保存过大的文件。
  • 文件过大,再追加写的时候,效率也会低。
  • 恢复过程,文件过大的话,重放命令,耗时也会很长。更小的AOF文件可以更快地被redis加载。

1.4.3.1 重写机制原理

官方是通过新增重写机制来实现的,触发重写机制有两种,咱们后文再详谈,这里只需要知道当触发了重写机制,redis就会对AOF文件进行内容压缩。压缩流程咱们也是后文再详谈,这里先了解一下压缩的是怎么东西?是怎么实现重写机制的?重写机制原理是什么?咱们一起来了解下。

  • 如何实现把AOF文件压缩的?
    • 把进程内已经超时的数据不再写入文件。
    • 去除旧的AOF文件含有无效命令,如del key1、set a 111、set a 222等这些修改数据的命令都会保存下来。重写使用进程内数据命令再直接生成,这样新的AOF文件只保留最终数据的写入命令。
    • 把多条写命令合并为一个,如lpush list a、lpush list b、 lpush list c 可以转化为:lpush list a b c。

注意:为了防止合并的数据过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型,以64个元素为界拆分为多条。

  • 示例文件对比
    在这里插入图片描述

可以看出,新生成的 aof 文件中,它的命令格式做了很大程度的简化。

1.4.3.2重写机制流程(瘦身运动)

  1. 当执行bgrewriteaof命令后,aof_rewrite函数会开辟一个bgrewriteaof 子进程,这时fork会把内存数据拷贝一份给bgrewriteaof 子进程(这里只包含了创建子进程时之前的所有内存数据),然后bgrewriteaof 子进程就可以在不影响主进程的情况下将所有的数据生成多条命令写入临时AOF文件(缺少主线程创建完子进程之后接受客户端处理的的内存数据)。
  2. 主线程创建子进程不耽误正常的AOF持久化的流程,所以主线程同样会把所有的内存(给子进程的数据+实时处理的新数据)数据写到aof_buf缓冲区。
  3. 子进程创建完之后,主线程继续处理客户端请求,它会将这部分的数据写入到重写缓冲区,当临时AOF文件生成后子进程会给主线程发信号通知,主线程接收到信号后会调用信号处理函数,该函数就会把重写缓冲区的数据追加到临时AOF文件里,所以这时候的临时AOF文件里的数据才是最新的(临时AOF文件——>新AOF文件),然后对新AOF文件改名,原子覆盖旧文件。
  • 一次拷贝什么时候进行的?
    • 主线程生成bgrewriteaof 子进程时会把自己当前的内存数据拷贝一份给子进程,此时子进程的读取的内存数据=此时的aof_buf缓冲区的数据。
  • 两处日志是指哪两个日志?
    • 第一处,AOF持久化流程正常走,数据会暂时写到aof_buf缓冲区,缓冲区的数据正常写入当前的AOF日志文件中。
    • 第二处,主线程创建完子进程之后,继续处理客户端请求接受新数据,并写入到重写缓冲区,之后追加到临时的AOF日志文件生成新的AOF日志。
  • AOF后台重写会有阻塞吗?什么时候?
    • 当主线程fork子进程时,拷贝虚拟页表的数据,这个操作过程会对主线程阻塞。
    • 当临时AOF日志生成后,主进程追加重写缓冲区数据到临时AOF日志并对新的AOF文件改名覆盖旧AOF文件时,会对主进程阻塞。

1.4.3.3 重写机制触发

1.4.3.3.1 手动触发

直接在客户端执行命令bgrewriteaof就可以触发。

1.4.3.3.2 自动触发(策略)

通过读取redis.conf配置文件中的两个参数,同时满足时服务自己执行bgrewriteaof命令。

  • auto-aof-rewrite-percentage: 当前的AOF文件大小超过上一次重写的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF大小为依据。比如,第一次重写时文件大小为 10M,那么第二次触发重写的体积为 20M,第三次重写为 40M,以此类推。
  • auto-aof-rewrite-min-size: 触发AOF重写的最小文件体积,当大于或等于多少兆时自动触发。

在这里插入图片描述

1.4.4 AOF持久化配置参数详解

1.4.4.1 AOF持久化开启与关闭

appendonly参数,默认是不开启的。

在这里插入图片描述

  • 开启后,重启服务就会生效。

在这里插入图片描述

1.4.4.2 修改日志文件名

appendfilename参数,可以修改AOF日志文件名称,默认不用修改,做到见名知意。

在这里插入图片描述

1.4.4.3 持久化策略

  • always模式下效率最低,但安全性最高。出现宕机时,AOF持久化也只会丢失一个时间循环中所产生的命令数据。
  • everysec模式下性能适中,也是官方建议的默认模式。
  • no模式下效率最高,但安全性最低。但这种模式单词同步时长通常是三种模式中时间最长的,因为这种模式是根据操作系统来控制回写的,期间缓冲区会一直积累这段时间的写入数据。当出现宕机时,服务器将会丢失上次同步AOF文件之后的所有写命令数据。

在这里插入图片描述

1.4.4.4 自动重写触发策略

  • auto-aof-rewrite-percentage 100
  • auto-aof-rewrite-min-size 64mb

表示当前AOF文件大小超过64mb,且相比原来的AOF文件来说,新文件内容比旧文件多一倍,则会触发AOF重写。

在这里插入图片描述

1.4.4.5 日志重写时是否开启命令追加

aof-load-truncated参数,默认为no,

  • 设置no,表示在日志重写时,进行命令追加操作,把命令数据从重写缓冲区里追加到新AOF日志文件里。这样做数据最安全,不会丢失数据,但是会有阻塞问题。
  • 如果设置为yes,这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。
    • 丢失多少数据呢?
      在linux的操作系统的默认设置下,最多会丢失30s的数据,因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no

在这里插入图片描述

1.4.4.6 是否忽略最后有问题的命令

aof-load-truncated参数。

  • 默认yes,表示redis启动加载AOF文件时候,发现文件最后一行有错误,会忽略该错误继续执行完成然后通知用户。若在文件中间有错误则会直接返回错误,所以这个参数的使用常常使用在服务器异常断电,持久化只写了一半,比如内存的命令数据“set k1 v1”正在写入AOF日志文件中,此时突然断电AOF日志只记录了“set”,那么这个参数会起作用。
    设置no,加载AOF文件遇到错误时会直接终止,直接拒绝启动。这种情况下我们可以通过前文介绍的redis-check-aof工具来修复AOF文件。

在这里插入图片描述

1.4.4.7 是否开启混合持久化

aof-use-rdb-preamble参数,默认yes, 开启混合持久化,更快的AOF重写和启动时数据恢复。

  • **实现原理:**全程通过bgrewriteaof来操作的,先fork一个子进程,并将共享的内存全部数据以rdb方式写入AOF文件里(rdb持久化的前部分),然后将重写缓冲区的增量命令数据以AOF方式追加到AOF文件。写入完成后通知主进程,并将刚刚产生的新AOF文件(rdb格式+aof格式)替换旧的的AOF文件。所以新的AOF文件前半段是rdb格式的全量数据,后半段是AOF格式的增量数据。

1.4.5 优缺点

1.4.5.1 优点

AOF只是追加写日志文件,对服务器性能影响较小,写入速度比rdb持久快,消耗的内存较少。

1.4.5.2 缺点

  • AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
  • 即使经过AOF重写瘦身,由于文件是文本文件,文件体积较大(相比于RDB的二进制文件)。
  • AOF重演命令去恢复数据,速度显然比RDB要慢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/58635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最常用的python开发工具

有哪些值得推荐的 Python 开发工具 推荐5个非常适合Python小白的开发工具:1、Python TutorPython Tutor是由Philip Guo开发的一个免费教育工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。 通过…

CentOS8克隆虚拟机修改IP,错误:未知的连接 “ens160“

关于CentOS8该如何克隆与修改IP,并设置成静态IP的方法,可以参考我的另一篇文章,我也是一直这么做的。 CentOS8拷贝虚拟机、修改ip、主机 但是最近我再使用我的这篇文章克隆虚拟机的时候,竟然报错了,本来想删除掉克隆…

2023年天津农学院专升本专业课报名、确认缴费及准考证打印流程

天津农学院2023年高职升本科专业课考试 报名、确认缴费及准考证打印操作流程 一、报名操作流程 1. 阅读报名注意事项 请考生于2022年12月5日9点—12月10日12点登录报名系统 http://gzsb.tjau.edu.cn,请认真阅读报名注意事项。2.报名登录 点击“报名”菜单后进入报名…

LeetCode 374. 猜数字大小

🌈🌈😄😄 欢迎来到茶色岛独家岛屿,本期将为大家揭晓LeetCode 374. 猜数字大小,做好准备了么,那么开始吧。 🌲🌲🐴🐴 一、题目名称 LeetCode 374.…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校辅导员工作管理系统82aub

对于即将毕业或者即将做课设的同学而言,由于经验的欠缺,面临的第一个难题就是选题,确定好题目之后便是开题报告,如果选题首先看自己学习那些技术,不同技术适合做不同的产品,比如自己会些简单的Java语言&…

【圣诞文】用python带你体验多重花样圣诞树

前言 大家早好、午好、晚好吖 ❤ ~ 在圣诞要来临的前夕,我们来出一起圣诞特辑吧 (虽说可能有一丢丢早,但是等要来了在准备就来不及了呀~) 圣诞节要素 1、圣诞袜,最早以前是一对红色的大袜子,大小不拘。 …

Spring异步任务async介绍与案例实战

关于spring异步任务 简单地说,用Async注释bean的方法将使其在单独的线程中执行。换句话说,调用者不会等待被调用方法的完成。利用spring提供的注解即可简单轻松的实现异步任务处理。 默认线程池问题 Spring 异步任务默认使用 Spring 内部线程池 Simpl…

网页自动点赞

进入网页版QQ空间 ,在开发者模式下创建脚本 var x5,y10;function autoClick(){yy5;var zandocument.getElementsByClassName(item qz_like_btn_v3);for(var i0;i<zan.length;i){if(zan[i].attributes[6].valuelike){zan[i].firstChild.click();}};window.scrollBy(x,y);}win…

LC118原厂直流驱动芯片 SOP-8

直流驱动芯片 LC118 SOP-8 电机驱动电路 马达驱动IC 马达驱动IC LC118的描述&#xff1a; LC118 是为专门为低电压下工作的系统而设计的单通道玩具直流电机驱动集成电路。它具有 H桥驱动器, 采用导通电阻非常小的P-MOS和N-MOS功率晶体管作为开关管&#xff0c;可在瞬间提供大电…

CMake中target_link_libraries的使用

CMake中的target_link_libraries命令用于指定链接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的使用要求将被传播(propagated)。目标依赖项的使用要求会影响其自身源代码的编译。其格式如下&#xff1a; target_link_libraries(<target> ... <item>…

用Rust写一个链表,非常详细,一遍看懂

前言 在Rust里写一个链表可不是一件容易的事&#xff0c;涉及到很多的知识点&#xff0c;需要熟练掌握之后才能写出一个不错的链表。这篇文章主要介绍了如何写一个Rust链表&#xff0c;并且补充了涉及到的很多的额外知识点&#xff0c;尤其是所有权问题。 首先&#xff0c;你需…

人工智能内容生成元年—AI绘画原理解析

AIGC体验生成一、背景 2022年AIGC&#xff08;AI生成内容&#xff09;焕发出了勃勃生机&#xff0c;大有元年之势&#xff0c;技术与应用迭代都扎堆呈现。在各种新闻媒体处可以看到诸多关于学术前沿研究&#xff0c;以及相应落地的商用案例。可谓出现了现象级的学术-商业共振。…

phpbugs代码审计第三题多重加密答案错误

phpbugs多重加密 这题官方给的答案是错的&#xff0c;网上给的也是错的&#xff0c;麻烦别直接拿给的答案来抄好吗&#xff1f;就想纠正一下别误导别人了 源码如下: <?phpinclude common.php;$requset array_merge($_GET, $_POST, $_SESSION, $_COOKIE);//把一个或多个…

安卓期末大作业——售票APP源码和设计报告

大作业文档 项目名称&#xff1a;售票APP专业&#xff1a;班级&#xff1a;学号&#xff1a;姓名&#xff1a; 目 录 目录 一、项目功能介绍3二、项目运行环境31、开发环境32、运行环境33、是否需要联网3三、项目配置文件及工程结构31、工程配置文件32、工程结构目录4四、项…

【C语言 数据结构】串 - 顺序

文章目录串 - 顺序一、串的表示及实现1.1 串的概念1.2 串的初始化1.3 复制串1.4 串的判空1.5 串的比较1.6 串的长度1.7 清空串1.8 串的拼接1.9 串的截取1.10 插入子串1.11 串的打印二、串的应用2.1 串的模式匹配 - 基本操作2.2 串的模式匹配 - BF2.3 串的模式匹配 - KMPnext数组…

【学习笔记77】ajax的函数封装

一、封装分析 &#xff08;一 &#xff09;封装方案 1、回调函数方式 将来使用的时候, 可能会遇到回调地狱 2、promise方式 效果不会有变化, 而且还能和 async/await 一起使用 &#xff08;二&#xff09;函数的参数 请求方式: method > 默认值 get请求地址: url > 必填…

Android开发——Jetpack Compose的使用

Android开发——Jetpack Compose的使用什么是Jetpack ComposeJetpack Compose带来的变化Jetpack Compose的两种运用方法将Jetpack Compose 添加到现有项目1.gradle 配置2.使用Kotlin-Gradle 插件3. 添加依赖项创建一个新的支持Jetpack Compose的项目1.创建一些简单应用定义可组…

12.3做题

一.车队问题 1.思路: 先把所在位置进行排序,升序排序, 计算出每辆车在不受其余车的影响时&#xff0c;行驶到终点需要的时间 从后往前看 对于相邻的两辆车 S 和 F&#xff0c;F 的起始位置大于 S&#xff0c;如果 S 行驶到终点需要的时间小于等于 F&#xff0c;那么 S 一定…

MySQL集群搭建-MMM高可用架构

MySQL集群搭建-MMM高可用架构 原文地址 https://segmentfault.com/a/1190000017286307&#xfeff; 1 MMM 介绍 1.1 简介 MMM 是一套支持双主故障切换以及双主日常管理的第三方软件。MMM 由 Perl 开发&#xff0c;用来管理和监控双主复制&#xff0c;虽然是双主架构&#xff…

volatile

是java虚拟机提供的轻量级的同步机制&#xff08;乞丐版的synchronized) 具备三个性质&#xff1a;保证可见性&#xff0c;不保证原子性&#xff0c;禁止指令重排 前置知识&#xff1a; …