概述
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简单粗暴,直接把内存快照下来,这样会使文件很紧凑,节约空间,从而利于文件的传输,有利于保存各个时间点的数据库。
触发
- 通常 RDB是间隔进行的,用户使用参数来指定快照的频率(
N秒内数据集至少有M个改动)。 - 用户
SAVE或者BGSAVE, 手动让 Redis 进行数据集保存操作。SAVE同步执行RDB快照,阻塞所有来到Redis的请求。BGSAVE后台保存RDB快照。
保存机制
要保证Redis继续接受来自客户端的请求并且正确地保证此刻的数据库数据,Redis利用子进程以及Copy On Write机制来实现。
写时复制能让某一时刻的数据被凝固:
当RDB开始时,Redis通过fork函数产生一个子进程,子进程将会负责RDB快照,而父进程继续接受客户端请求。
在父进程收到一个修改数据库的命令时,并非直接写到原本的数据库中,而是拷贝一份,然后在拷贝中进行修改。操作系统对内存进行分页处理,故拷贝的就是数据所在的页面。这样一来,原先的数据不会变化,修改数据库的指令还能继续工作。
通过牺牲空间的方式来保存现场,就是Copy On Write机制。
当新的RDB快照完成后,就会替换原来的RDB文件。
AOF的持久化原理
AOF保存的是易于开发人员看懂的指令序列。
故AOF文件的体积会比RDB的更大,恢复起来也不如RDB那么干脆快捷。但是最大的好处就是,在每一次对数据库进行变更时,Redis都会记录AOF日志,这直接保证了安全有效的持久化。
触发
- 自动,每一次指令来临时,先运行指令,后保存日志。
- 用户手动触发
BGREWRITEAOF,通过内存数据库导出一份精简的AOF文件,替换原有的AOF文件。
保存机制
每一次修改指令执行完就将指令写到AOF中,这显然会大大提高磁盘IO的频率。
阻止IO频发的方式,操作系统本身已经为我们想好了:内存缓存。
对一个文件进行写操作,并非真的写到了磁盘,而是写在了内存,过段时间再真正的写到文件中。
fsync函数用于将内存缓存写到磁盘中。但是,在fsync函数还没调用的时候,服务器就宕机的话,这就会导致数据丢失。
Redis为了避免这样的事情发生,提供了控制fsync函数调用的频率,一般情况下,1秒进行一次,这样即使宕机,丢失的数据也是一秒钟的。
AOF重写
Redis 在长期运行中,AOF 的日志会很长,用户可以自己手动触发重写AOF,Redis也会根据用户设定的条件来触发AOF重写。
n条 incr命令其实可以用1条set命令来代替,这就是重写的思想。
重写的机制:
- 产生子进程
- 子进程遍历内存后写到一个新的AOF文件中
- 主进程所接受到的数据修改,均写入内存的缓冲区以备写入新的AOF,而这些变动也同时会写入旧的AOF中,这保证了新的AOF出错了仍然可以用旧的。
- 子进程AOF重写完后,主进程将缓冲区的内容写到新的AOF中
- 新旧替换