Redis的持久化

145 阅读4分钟

概述

Redis作为一种非关系型的数据库,其数据的变更是由指令导致的。

数据集1 ---> 数据集2 的变化,必然是一个指令造成的,故Redis的持久化策略有二,一是对数据集进行全量备份,二是对指令进行记录。

Redis对第一种方式的实现称为RDB(Redis Database),持久化时,保证将当前时刻的数据库快照到一个文件中;恢复时,将内存中的数据库替换为快照。

Redis对第二种方式的实现称为AOF(Append Only File),持久化发生在每一次用户执行指令(每执行一个指令,Redis会将该指令存至文件中,一形成一个指令序列),恢复时Redis从文件中读出指令序列,并在Redis中重现,一构建出一个数据库(可以联想关系型数据库的SQL文件)。

RDB和AOF可以同时存在或者单独打开,也可以都不打开。

Redis 4.0实现了混合持久化,兼得RDB和AOF的特性,即恢复时既使用RDB来恢复快照,由用AOF来重现指令。

RDB的持久化原理

RDB简单粗暴,直接把内存快照下来,这样会使文件很紧凑,节约空间,从而利于文件的传输,有利于保存各个时间点的数据库。

触发

  1. 通常 RDB是间隔进行的,用户使用参数来指定快照的频率(N 秒内数据集至少有 M 个改动)。
  2. 用户 SAVE 或者 BGSAVE , 手动让 Redis 进行数据集保存操作。
    1. SAVE 同步执行RDB快照,阻塞所有来到Redis的请求。
    2. BGSAVE 后台保存RDB快照。

保存机制

要保证Redis继续接受来自客户端的请求并且正确地保证此刻的数据库数据,Redis利用子进程以及Copy On Write机制来实现。

写时复制能让某一时刻的数据被凝固:

当RDB开始时,Redis通过fork函数产生一个子进程,子进程将会负责RDB快照,而父进程继续接受客户端请求。

在父进程收到一个修改数据库的命令时,并非直接写到原本的数据库中,而是拷贝一份,然后在拷贝中进行修改。操作系统对内存进行分页处理,故拷贝的就是数据所在的页面。这样一来,原先的数据不会变化,修改数据库的指令还能继续工作。

通过牺牲空间的方式来保存现场,就是Copy On Write机制。

当新的RDB快照完成后,就会替换原来的RDB文件。

AOF的持久化原理

AOF保存的是易于开发人员看懂的指令序列。

故AOF文件的体积会比RDB的更大,恢复起来也不如RDB那么干脆快捷。但是最大的好处就是,在每一次对数据库进行变更时,Redis都会记录AOF日志,这直接保证了安全有效的持久化。

触发

  1. 自动,每一次指令来临时,先运行指令,后保存日志。
  2. 用户手动触发BGREWRITEAOF,通过内存数据库导出一份精简的AOF文件,替换原有的AOF文件。

保存机制

每一次修改指令执行完就将指令写到AOF中,这显然会大大提高磁盘IO的频率。

阻止IO频发的方式,操作系统本身已经为我们想好了:内存缓存。

对一个文件进行写操作,并非真的写到了磁盘,而是写在了内存,过段时间再真正的写到文件中。

fsync函数用于将内存缓存写到磁盘中。但是,在fsync函数还没调用的时候,服务器就宕机的话,这就会导致数据丢失。

Redis为了避免这样的事情发生,提供了控制fsync函数调用的频率,一般情况下,1秒进行一次,这样即使宕机,丢失的数据也是一秒钟的。

AOF重写

Redis 在长期运行中,AOF 的日志会很长,用户可以自己手动触发重写AOF,Redis也会根据用户设定的条件来触发AOF重写。

n条 incr命令其实可以用1条set命令来代替,这就是重写的思想。

重写的机制:

  1. 产生子进程
  2. 子进程遍历内存后写到一个新的AOF文件中
  3. 主进程所接受到的数据修改,均写入内存的缓冲区以备写入新的AOF,而这些变动也同时会写入旧的AOF中,这保证了新的AOF出错了仍然可以用旧的。
  4. 子进程AOF重写完后,主进程将缓冲区的内容写到新的AOF中
  5. 新旧替换