Redis持久化之AOF

一、AOF(Append Only File)基础

个人复习笔记

1、AOF文件作用

  • 以日志的形式来记录每个写操作(读操作不记录),将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
  • AOF文件的更新频率要高于RDB文件,所以如果服务器开启了AOF文件持久化功能,那么服务器会优先使用AOF文件进行还原数据库的状态,只有在AOF文件持久化功能被关闭的时候服务器才使用RDB文件来还原数据库
  • 默认AOF没有开启
   appendonly no #如果要开启,改为yes表示打开AOF持久化

2、AOF持久化的实现

MySQL中redo log,记录的是修改后的数据,AOF中记录的是以文本的形式来记录收到的每一条命令。
例如执行以下命令

set testkey testvalue

看一下AOF日志的内容,*3代表当前的命令有三个部分,分别是set,testkey,testvalue,每个部分的开头都是由$+数字开头,后面跟着对应的命令、键或者值,数字代表的就是对应的命令、键或者值有多少个字节。
$3 set表示的set命令有3个字节,如下图所示:
在这里插入图片描述

3、AOF的工作流程

AOF持久化的实现可以分为:命令追加( append )、文件写入( write )、文件同步( sync )、文件重写(rewrite)和重启加载(load)。

  • 所有的写命令会追加至aof_buf缓存中;
  • AOF缓存区根据对应的策略向硬盘进行同步操作;
  • AOF日志会越来越大,需要定期对AOF文件进行重写来实现压缩;
  • Redis重启时,可以加载AOF文件进行数据恢复;
    在这里插入图片描述

二、AOF写回策略

1、基本操作

  • AOF 日志是以文件的形式存在的,当程序对AOF日志文件进行写操作时,实际上是写到了内核为文件描述符分配的一个内存缓冲中,内核会异步将脏数据刷回到磁盘。
  • 如果机器突然宕机,那就有可能会丢失日志数据。
  • AOF日志写操作是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。
  • Linux的glibc提供了 fsync(int fd)函数将指定文件内容强制从内核缓存刷到磁盘,如果实时调用这个方法,就可以保证AOF日志不丢失,但是 fsync是一个磁盘IO操作,很慢。

2、三种策略

Redis对AOF刷到磁盘,提供了三个可选值

  • Always(同步写回): 每个写命令执行完,立马同步地将日志写回磁盘。
  • Everysec(每秒写回): 每个写命令执行完,先把日志写到AOF文件的内存缓冲区,每个一秒把缓冲区中的内容写入磁盘。
  • NO(操作系统控制的写回):每个写命令执行完,只是先把日志写到AOF文件的内容缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
vim /etc/redis/6379.conf
● appendfsync always:
命令写入aof_ buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。
这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支
持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约
也只能处理几万个命令,而且会大大降低SSD的寿命。
● appendfsync everysec:
命令写入aof_ buf后调用系统write操作,write完成后线程返回; fsync同步文件操作
由专门的线程每1秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的
平衡,因此是Redis的默认配置,也是我们推荐的配置。
● appendfsync no:
命令写入aof_ buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统
负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的
数据会很多,数据安全性无法保证。

总结:always只调用fsync,no只调用write,eversec既调用wirte,又每秒调用一
次fsync。

write命令和fsync命令的区别:

write:只能确定数据成功写入io缓冲区。数据是否成功写入aof文件,是由操作系统定期或当io缓冲区填满时,自动将io缓冲区的数据写入到aof文件。所以在io缓冲区的数据存在断电数据丢失的风险。
fsync:具有强制将io缓冲区数据写入到aof文件的机制,可以确定数据是否成功写入aof文件。

3、策略优缺点

在这里插入图片描述

  • 想要获得高性能,就选择 No 策略;
  • 如果想要得到高可靠性保证,就选择 Always 策略;
  • 如果允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择 Everysec 策略。

三、AOF重写

1、重写原因

重写作用

  • redis 随着命令不断的写入数据,aof 文件会越来越大。为了解决AOF文件体积膨胀的问题,Redis提供了AOF重写功能:Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。

AOF重写规则

  • 进程内已超时的数据不再写入文件
  • 忽略无效指令,重写时使用进程内数据直接生成,这样的新的AOF文件只保留最终数据的写入命令
  • 重写机制就是具有多变一的功能,旧日志中的多条命令,在重写后的新日志中变成一条命令,示例如下图所示:
    在这里插入图片描述
    在对一个列表之后6次修改操作之后,最终的列表的状态是[“D”, “C”, “N”],只用LPUSH u:list “N”, “C”, "D"这一条命令就能实现该数据的恢复,这就节省了五条命令的空间。
    虽然AOF重写后,日志文件会缩小,但是,要把整个数据库的最新数据的操作日志都写回磁盘,仍然是一个非常耗时的过程。这时,我们就要继续关注另一个问题了:重写会不会阻塞主线程?

2、重写原理

(1)、触发条件

手动触发

  • AOF重写可以由用户通过调用bgrewriteaof命令手动触发。
  • 执行的原理也是fork一个子线程去执行重写。

自动触发

  • 服务器在AOF功能开启的情况下,进程会维持以下三个变量:

    >  记录当前AOF文件大小的变量aof_current_size。
    >  记录最后一次AOF重写之后,AOF文件大小的变量aof_rewrite_base_size。
    >  增长百分比变量aof_rewrite_perc。
    
  • 每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:

    >  没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
    >  没有BGREWRITEAOF在进行;
    >  当前AOF文件大小要大于server.aof_rewrite_min_size(默认为1MB),
       或者在redis.conf配置了auto-aof-rewrite-min-size大小;
    >  当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于
       指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,
       不设置默认为100%
  • 在redis.config配置文件中有两个配置项示例

    #当AOF文件小于64MB的时候不进行AOF重写
    auto-aof-rewrite-min-size 64MB 
    当当前AOF文件比上次AOF重写后的文件大100%的时候进行AOF重写
    auto-aof-rewrite-min-percenrage 100
    

(2)、重写流程

  • 1)、 触发bgrewriteaof重写命令流程,手动直接触发,自动检查相关条件。
  • 2)、系统会调用fork产生一个子进程去执行重写操作,在fork是主进程是阻塞状态的,但是时间非常短,这时主进程和子进程是共享内存空间的,主进程继续执行命令请求的读写操作,子进程执行重写操作,但子进程只有读操作。
  • 3)、触发重写操作后系统为了解决数据不一致问题,会开辟出一个新的缓存空间出来aof_rewrite_buf在fork子进程后使用,aof_buf没重写前就有,所以也会一直存在。
    • 3.1)、aof_buf( AOF缓冲区):当 Redis 服务器执行完一个写命令之后,还是继续会往旧aof文件插入数据,防止系统挂机重写操作不成功。
    • 3.2)、 aof_rewrite_buf( AOF重写缓冲区):同时也插入重写缓存区,给后面新的aof写入重写过程中新改变的数据,保持数据一致性、
  • 4)、子进程执行重写操作,内存中的数据写入新的aof文件,这份文件不会有冗余的命令,会比旧aof小,但此时数据还不完整,还需要写入重写缓存区中的数据。
  • 5)、当子进程完成 AOF 重写工作之后,它会向父进程发送一个信号,父进程在接到该信号后,会调用一个信号处理函数,并执行一下工作:
    • 5.1)、 进程完成 AOF 重写工作,子进程向父进程发送一个完成信号,然后销毁子进程。
    • 5.2)得到信号后,主进程将 AOF 重写缓冲区中的所有内容写入到新 AOF 文件中,这是新的 AOF 文件所保存的数据库状态将和服务器当前的数据库状态一致。
    • 5.3)、主进程对新的 AOF 文件进行改名,原子地(atomic)覆盖现有的 AOF 文件,完成新旧两个 AOF 文件的替换。

当这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接收命令请求了。 在整个AOF后台重写过程中,只有最后的“主进程写入命令到AOF缓存”和“对新的AOF文件进行改名,覆盖原有的AOF文件。”这两个步骤(信号处理函数执行期间)会造成主进程阻塞。 在其他时候,AOF后台重写都不会对主进程造成阻塞,这将AOF重写对性能造成的影响降到最低。

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值