RDB持久化
RDB是保持在硬盘中的经过压缩的二进制文件;
触发机制
SAVE命令
save命令是同步命令,其他客户端会阻塞等待save命令执行完成;
bgsave命令
bgsave是异步命令,会fork一个子进程去执行save操作(fork时会阻塞,不过时间很短),redis服务器进程则继续响应请求;
自动触发
- 配置”save m n “表示在m秒内有n次修改时自动触发bgsave;
- 从节点执行全量复制,主节点自动执行bgsave生成最新的RDB文件并发送给从节点;
- 执行shutdown时,如果没有开启aof,会自动执行bgsave;
AOF持久化
aof文件:以独立日志记录每次写命令,内容是文本协议格式,具有很好的兼容性,可读性;
执行一条写命令的流程
aof缓冲区同步数据到硬盘
redis设有aof缓冲区,每次写命令都先写入缓冲区,提高性能,而何时写入硬盘,取决于同步文件策略;有以下三种:
- fsync:会直接同步到硬盘文件中;
- write:操作会触发延迟些,所谓延迟写就是调用write不会立即访问磁盘,而是会将数据从用户空间缓冲区(这里的aof缓冲区)写入内核缓冲区高速缓存中,后面操作系统在复制将他写入到硬盘中;
- everysec策略:redis会使用另外一条线程每秒执行sfync同步数据到硬盘;
AOF文件重写
随着命令不断写入,aof文件会越来越大,所以需要进行重写;AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程
,aof文件越小加载起来速度会更快;
新的aof文件,不会写入以超时的数据,不会包含无效的命令,会合并多条写命令;
触发机制
手动触发:直接调用bgrewriteaof命令。
自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时
- auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB
- auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。大于该值则重写;
重写流程
aof重写仍然是fork一个子进程去执行aof重写逻辑,然后此时会有两个缓冲区,分别是 aof_buf和aof_rewrite_buf,为什么需要这两个缓冲区呢?
首先需要知道aof重写的实现原理,他是fork一个子进程,然后根据读取当前数据库的状态
来实现重写的,并不是根据aof文件;所以在重写阶段,主进程还在处理请求,会导致重写后aof文件数据不一致,就需要有aof_rewrite_buf来将新的命令写入到缓冲中;那么为什么需要两个缓冲呢,假如现在只有一个aof_buf缓冲,如果为了保证数据的一致性,那么在重写阶段缓冲的数据就不能写入到aof文件中,否则重写完之后替代旧的aof文件
,后来新添加的数据就没了,但是如果不写入到文件,此时出错,进程被关闭
了,那么新添加的数据就会丢失,同样造成不一致;所以aof_buf需要保证原先的aof机制正常,然后再将新的命令写入到aof_rewrite_buf中,这样在重写完成后,就可以将这些新的命令追加到新的aof文件中,保证数据的一致性;
AOF追加阻塞(只有在使用是everysec同步策略时)
同步线程会每秒钟执行一次磁盘同步操作,并记录最近一次同步时间;每次主线程写入AOF缓存区后会对比上去fsync的时间,如果上次同步时间在2秒内,则返回;否则至线程将会阻塞,直到同步操作完成;
RDB和AOF的区别
- 加载速度:RDB远远快于AOF
- 文件大小:RDB是紧凑压缩的二进制文件,aof是文本协议格式文件,所以相同数据的情况下RDB会比aof小;
- 实时持久化/秒级持久化:RDB无法做到,因为每次bgsave都需要fork,属于重量级操作,所以没办法每次都执行;而AOF的主要作用就是解决实时性,他每次写入新数据时都是直接当时的命令,只有在aof文件达到一定大小时才会fork子进程来重写aof文件;
- 默认方式:RDB;
- 运行效率:根据同步策略的不同(一般是everysec),AOF在运行效率上往往会慢于RDB,而关闭 fsync 可以让 AOF 的速度和 RDB 一样快;
二者选择的标准,是看愿意牺牲一些性能来换取缓存的实时性(aof),还是愿意在写的时候不起用备份来换取更高的性能(一般有主从结构的话,主节点是不开启备份来提高性能,让从节点去备份);
fork操作
对大多数操作系统来说,fork操作都是一个重量级操作;因为fork一次会复制父进程的空间内存页表,父进程总内存量越大,fork操作就越耗时;不过Linux有写时复制机制,父子进程会共享相同的物理内存页,当父进程写请求时会为修改的页创建副本,所以还是会消耗一些内存;