持久化
概念:
什么是持久化:
因为Redis是内存数据库,它将自己的数据库状态存储在内存中,如果进程一旦退出,服务器的数据就会消失。为了解决这个问题,就需要将数据持久化。Redis的持久化有两种,RDB持久化和AOF持久化。
RDB持久化
RDB持久化就是将内存中的数据库状态保存到磁盘中,从而避免数据意外丢失。RDB持久化既可以手动实现,也可以自动实现,将某一个时间点上的数据库状态保存到一个RDB文件中,该文件可用于还原数据库状态。
RDB文件的生成与载入
两个生成命令:
SAVE
SAVE命令创建RDB文件,在这个过程中,服务器会被阻塞,直到SAVE命令执行完。
BGSAVE
BGSAVE命令执行时,服务器会fork()一个子进程,由子进程进行RDB文件的创建。
这时服务器不会被阻塞,而是可以继续执行客户端命令。子进程完成创建时会向服务器发送信号。
载入: 服务器会在启动时自动载入RDB文件,在载入过程中,服务器处于阻塞状态,知道载入完毕。
RDB文件自动间隔性保存
因为BGSAVE命令是不会阻塞服务器的,所以通过设置服务器配置的save选项,可以使得服务器每隔一段时间执行一次BGSAVE命令。
save 900 1
save 300 10
save 60 10000
以上表示:只要三个条件满足其中一个,就能自动执行BGSAVE命令
条件一:服务器在900秒内,对数据库进行了至少1次修改;
条件二:服务器在300秒内,对数据库进行了至少10次修改;
条件三:服务器在60秒内,对数据库进行了至少10000次修改;
数据结构:
redisServer{
…
struct saveparams *saveparams;
…
//修改计数器
long long dirty;
//上一次执行保存的时间
time_t lastsave;
…
}
struct saveparams{
//秒数
time_t seconds;
//修改次数
int changes
}
dirty:脏数计数器。
当当前时间与上一次保存时间的时间差超过了saveparams中设置的时间,则如果dirty的次数大于saveparams设置的changes次数,则执行BGSAVE命令,并修改dirty为0,更新lastsave时间。
自动执行:因为redis服务器有一个周期性函数serverCron。默认每隔100ms就会执行一次,其中一个任务就是检查save选项所设置的保存条件是否满足。
RDB文件结构
AOF
RDB是通过保存数据库中的键值对来来记录数据库状态,而AOF则是保存服务器执行的写命令来保存数据库状态。
AOF持久化的实现
三个步骤: 追加(append)、文件写入、文件同步
- 当服务器在执行完一个写命令后,会一回忆协议格式将被执行的命令追加到服务器状态的aof_buf缓冲区末尾
- 服务器每次结束一个事件循环前,考虑是否将aof_buf缓冲区的内容写入AOF文件(执行函数 flushAppendOnlyFile(),该函数执行什么行为是由服务器配置的appendfsync选项值来决定)
appendfsync选项值 | flushAppendOnlyFile函数行为 |
---|---|
always | 将aof_buf缓冲区中的所有内容写入并同步到AOF文件 |
everysec | 将aof_buf缓冲区中的所有内容写入到AOF文件,如果与上次同步时间相隔超过1秒,那么对AOF文件进行同步,且同步操作又一个线程专门负责执行的 |
no | 将aof_buf缓冲区中的所有内容写入到AOF文件,但不对AOF文件进行同步,由操作系统决定何时同步 |
AOF文件的载入与数据还原
AOF重写(BGREWIRTEAOF)
因为AOF保存的是写命令,经过保存删除等操作之后,AOF文件会越来越大,所以需要对AOF文件进行重写,新的AOF文件不会包含任何浪费空间的冗余命令。
重写条件:
在redis服务器上每秒执行一次的ServerCron()中,如果当前没有rdb进程或者aof进程在工作,那么就会进行aof重写操作。
或者:
如果当前aof文件大于最小重写触发大小,并且距离上一次重写增长率超过了默认的百分之一百,那么也会通过调用rewiriteAppendOnlyFileBackground()函数开始进行aof重写。
- 子进程创建一个新的AOF文件,开始重写;
- 重写过程中客户端发送的新的写命令会被追加到AOF缓冲区和AOF重写缓冲区;
- 子进程完成重写后,会向父进程发送一个信号,父进程接收并进行相应处理(此时不接受客户端命令);
- 将AOF重写缓冲区的数据所有内容写入新的AOF文件,此时新旧AOF文件状态一致;
- 对新的AOF文件进行改名,原子的覆盖现有的AOF文件,完成新旧文件的替换。
- 执行完毕,父进程可以正常进行命令处理。