Redis官方提供了两种数据持久化的方式,分别是:RDB和AOF。今天我们来讨论一下这两种持久化方式的区别。
RDB
基本原理:RDB持久化主要是通过SAVE和BGSAVE两个命令对Redis数据库中当前的数据做snapshot并生成rdb文件来实现的。其中SAVE是阻塞的,BGSAVE是非阻塞的,通过fork了一个子进程来完成的。在Redis启动的时候会检测rdb文件,然后载入rdb文件中未过期的数据到服务器中
配置信息:RDB可以通过向服务器提供配置信息来自动间隔性保存。如默认情况下服务器满足以下3个条件中任意一个条件就会触发BGSAVE命令
save 900 1 // 服务器在900秒之内,对数据库进行了至少1次修改
save 300 10 // 服务器在300秒之内,对数据库进行了至少10次修改
save 60 10000 // 服务器在60秒之内,对数据库进行了至少10000次修改
实现方式:服务器通过维护dirty
计数器和lastsave
属性分别记录距离上次成功执行SAVE或者BGSAVE命令之后,服务器对数据库状态进行修改的次数和最后一次成功SAVE或者BGSAVE的UNIX时间戳。由Redis周期性操作函数serverCron
默认每隔100ms
来检测是否满足配置信息中的要求,然后再决定是否执行SAVE或者BGSAVE命令来对数据库进行备份。
AOF
基本原理:AOF(Append Only File)持久化是通过将存储每次执行的客户端命令,然后由一个伪客户端来执行这些命令将数据写入到服务器中的方式实现的。一共分为命令追加(append)、文件写入、文件同步(sync)三个步骤完成的
命令追加
当有修改、删除操作时,服务器会在执行完之后以协议格式将被执行的写命令追加到服务器状态的aof_buf
缓冲区的末尾
文件写入
Redis的服务进程就是一个事件循环,这个循环中的文件事件负责接收客户端的命令请求。服务器在处理文件事件时可能会执行写命令,同时会追加到aof_buf
缓冲区,所以在每结束一次循环之前,都会调用flushAppendOnlyFile
函数,将aof_buf
缓冲区的数据写入到AOF文件里面。
文件同步
flushAppendOnlyFile
函数通过服务器配置appendfsync
选项的值来决定的将每次循环结束之前aof_buf
缓冲区的数据写入到AOF文件后,将以何种方式同步到AOF文件里面:
appendfsync | flushAppendOnlyFile函数的行为 |
---|---|
always |
每次都同步 |
everysec |
单独一个线程一分钟同步一次 |
no |
操作系统决定何时同步 |
AOF重写
AOF方式持久化时记录的时一条一条的写命令,随着服务器运行的时间越来越长,AOF文件会越来越大,AOF重写就是为了解决这个问题。
函数aof_rewrite
启动一个子进程创建AOF重写缓冲区,将Redis中所有的数据生成多条写命令写入AOF文件。在子进程进行AOF重写期间,服务器还会处理写请求的命令,这会导致服务器当前的数据库状态和重写后的AOF文件所保存的数据不一致。为了解决这个问题,子进程在执行AOF重写期间,服务器进程需要执行以下三件事情:
- 执行客户端发送来的命令
- 将执行后的写命令追加到AOF缓冲区
- 将执行后的写命令追加到AOF重写缓冲区
当子进程完成AOF重写工作后,会发送一个信号到父进程,父进程收到信号后会调用信号处理函数(这个过程会block主父进程),执行以下工作:
- 将AOF重写缓冲区中的数据全部写入到新AOF文件中,这时新AOF文件所保存的数据库状态和服务器当前的数据库状态一致
- 对新的AOF文件进行改名,原子的覆盖现有的AOF文件,完成新旧两个AOF文件的替换
RDB与AOF区别
- RDB可以理解为是一种全量数据更新机制,AOF可以理解为是一种增量的更新机制,AOF重写可以理解为是一种全量+增量的更新机制(第一次是全量,后面都是增量)
- RDB适合服务器数据库数据量小,写命令频繁的场景
- AOF适合数据量大,写命令少的场景
- AOF重写适合在AOF运行了很久的写命令之后执行