快照,aof持久化

快照持久化

就是获得存储在内存里面的数据在某个时间点上的副本。

在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他服务器,从而创建具有相同数据的服务器副本,还可以将快照留在原地,以便重启服务器时使用。

快照机制的运行原理

  • 执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。
  • 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒。
  • 父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
  • 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
  • 进程发送信号给父进程表示完成,父进程更新统计信息,具体见info Persistence下的rdb_*相关选项。

Snapshotting(RDB)机制的触发时机

  • 客户端可以通过向Redis发送bgsave命令来创建一个快照。对于支持bgsave命令的平台来说,Redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程继续处理命令请求。
  • 客户端还可以通过向Redis发送save命令来创建一个快照。接到save命令的Redis服务器在快照创建完毕之前将不再响应任何其他命令。save命令并不常用,我们通常只会在没有足够内存去执行bgsave命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下才会使用这个命令
  • 如果用户设置了save配置选项,比如save 60  10000 那么从Redis最近一次创建快照之后开始算起,当“60秒之内有一万次写入”这个条件被满足时,Redis就会自动触发bgsave命令。如果用户设置了多个save配置选项,那么当任意一个save配置选项所设置的条件被满足时,Redis就会触发一次bgsave命令。 
  • 当Redis是通过shutdown命令接收到关闭服务器的请求时,或者接收到标准term信号时,会执行一个save命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在save命令执行完毕之后关闭服务器。
  • 当一个Redis服务器连接另一个Redis服务器,并向对方发送sync命令来开始一次复制操作的时候,如果主服务器目前没有在执行bgsave操作,或者主服务器并非刚刚执行完bgsave操作,那么主服务器就会执行bgsave命令。

AOF持久化

会将被执行的写命令写到aof文件的末尾以此来记录数据发生的变化,因此Redis是只要要从头到尾重新执行一次aof文件包含的所有写命令,就可以恢复aof文件所记录的数据集。

Aof持久化功能的实现分为命令追加,文件写入,文件同步三个步骤

1)命令追加

Aof功能打开时,服务器在执行完一个写命令之后,会以协议的形式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾:

Struct redisServer{

//..

Sds   aof_buf;

//..

};

比如,客户端向服务器发送以下命令:

那么服务器在执行这个set命令之后,会将以下协议追加到aof_buf缓冲区的末尾

2) 文件的写入与同步

服务器执行完写命令,使得一些内容被追加到aof_buf缓冲区里面,接下来会调用flushAppendOnlyFile函数,判断是否将缓冲区的内容写入和保存到aof文件里面。

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定

AOF机制的运行原理

  • Redis 通过fork一个子进程
  • 父进程继续处理client请求,子进程把AOF内容写入缓冲区
  • 子进程写完退出,父进程接收退出消息,将缓冲区AOF写入临时文件
  • 临时文件重命名成appendonly.aof,原来文件被覆盖,整个过程完成

AOF为什么把命令追加到aof_buf缓冲区中?

      Redis使用单线程相应命令,如果每次写入AOF文件命令直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入缓存aof_buf中,可以提供多种缓冲区同步硬盘的策略

 

AOF文件重写机制的原理

虽然Redis将生成新aof文件替换旧aof文件的功能命名为“aof文件重写”,

但aof文件重写并不需要对现有的aof文件进行任何的读取,分析或者写入操作,

它是通过读取服务器当前的数据库状态来实现的。

 

那么,为了保存animals键的状态,aof文件必须保存上面列的四条命令

如果想减少保存animals键的命令的数量,服务器可以通过读取animals键的值,然后用一条sadd animals “Dog” “Panda” “Tiger” “Lion” “Cat”命令来代替。

这样就将保存animals键所需的命令从四条减为一条了。

AOF重写时的服务器进程和子进程

Redis将aof重写放到子进程里执行,这样做可以同时达到两个目的

1)子进程进行aof重写期间,服务器进程(父进程)可以继续处理命令请求

2)子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全

使用子进程也有问题要解决,因为使用子进程在进行aof重写期间,服务器进程还需要处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前的数据库状态和重写后的aof文件所保存的数据库状态不一致

 

为了解决这种数据库不一致问题,Redis服务器设置了一个aof重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,他会同时将这个写命令发送给aof缓冲区和aof重写缓冲区

 

也即,服务器进程需要执行以下三个工作:

1)执行客户端发来的命令

2)将执行后的写命令追加到aof缓冲区

3)将执行后的写命令追加到aof重写缓冲区

aof文件后台重写过程:

所以,

重写后AOF文件为什么变小?

1)无效命令的重写。

set name baby

set age 18

del name

由于AOF机制会将所有的写命令记录在日志文件,所以上面的三个命令会被全部记录。但是此时内存中的数据只存在一个age,其余两个命令相对于内存的数据为无效命令。经AOF重写后的日志文件禁会保留set age 18,消除了无效命令。

2)内存过期数据的处理。

setex name 10 Tom  // 设置一个key 存活时间为10秒

上面的命令向redis中设置了一个key,并设置了过期时间,当超过过期时间后,此key会被自动销毁,而AOF日志文件记录的写命令也变的无效了。AOF重写后会消除过期数据的命令。

3)命令的合并。

lpush users admin1

lpush users admin2

lpush users admin3

上面的三个命令,可以通过AOF重写合并成 : rpush users admin3 admin2 admin1

 

posted @ 2020-05-05 09:49  云和美和  阅读(248)  评论(0编辑  收藏  举报