# Redis持久化
Redis官方提供了两种持久化方法。
- 快照(Snapshot)
- AOF(Append Only File)只追加日志文件
## 快照(Snapshot)
### 1.特点
这种方式是将`某一时刻`的所有数据写入磁盘,保存的文件以`.rdb`格式存储。因此这种方式也可称为`RDB方式`。这也是`Redis默认开启的持久化方式`。
### 2.快照生成方式
- 客户端方式:BGSAVE和SAVE指令。
- 服务器配置自动触发。
#### a) BGSAVE
当收到客户端的BGSAVE指令时,Redis会调用fork函数来创建一个子进程,然后子进程负责将快照写入磁盘,父进程则继续处理客户端的指令请求。
> fork:是一个用于创建子进程的函数。当一个进程调用fork创建一个子进程时,底层操作系统将会创建一个该进程的副本,在刚开始时父子进程共享内存,直到父进程或子进程第一次对内存进行写操作之后,被写入的内存的共享结束。
#### b) SAVE
当收到客户端的SAVE指令时,Redis主进程负责将快照写入磁盘,期间将不响应任何客户端指令(`阻塞`)。
#### c) 服务器配置
通过在`redis.conf`配置文件中配置`save`选项,Redis会在save选项条件满足时自动触发一次BGSAVE指令。如果设置了多个save选项,那么当任意一个选项满足时,都会触发一次BGSAVE指令。
#### d) SHUTDOWN指令
当收到客户端的SHUTDOWN指令时,Redis会执行一个SAVE指令。执行完成后关闭服务器。
## AOF(Append Only File)只追加日志文件
### 1.特点
这种方式是将客户端发送的`所有写命令`记录到日志文件中,AOF持久化会将被执行的写命令追加到AOF日志文件的末尾,以此来记录数据的变化。因此,只要从头到尾执行一次AOF中的所有指令,就可以恢复AOF文件记录的数据。
### 2.开启AOF持久化
#### a) 修改配置文件
将配置文件中的`appendonly`选项改为`yes`。
> 可以修改`appendfilename`选项指定生成的文件名称。以`.aof`结尾。
### 3.日志追加频率
- **always**【谨慎使用】
> 每个写命令都会同步写入到磁盘,严重降低Redis速度。
- **everysec**【推荐】【默认】
> 每秒执行一次将多个写命令同步写入到磁盘。可以保证最多丢失一秒内产生的数据。
- **no**【不推荐】
> 完全由操作系统决定何时同步,不会对任何Redis性能带来任何影响。会丢失不定量的数据。
#### 4.修改日志同步频率
修改配置文件中的`appendfsync`选项,选项值为前面三个值中的一个。
## AOF文件的重写
### 1.AOF带来的问题
持久化文件会随着写指令的增加而变得越来越大。例如调用`incr num`100次,文件中保存了100条指令,其实99条是多余的,因为要恢复数据库的状态只需执行一条`set num 100`就够了。为了压缩AOF持久化文件,Redis提供了AOF的`重写`机制。
### 2.AOF重写
用来一定程度上减小AOF文件的体积。
### 3.触发重写方式
- 客户端指令
> 执行`BGREWRITEAOF`命令,不会阻塞Redis。
- 服务器配置自动触发
> 修改配置文件中的`auto-aof-rewrite-percentage`和`auto-aof-rewrite-min-size`选项。
>
> 如果配置`auto-aof-rewrite-percentage`为100,`auto-aof-rewrite-min-size`为64mb,那么当AOF文件大于64mb,并且AOF文件的体积比上一次重写后体积大了100%时,会自动触发重写。
### 4.重写原理
重写AOF时,并没有读取旧的AOF文件,而是将内存中的数据用命令的方式重写了一个新的AOF文件替换旧的AOF文件。
> 重写流程:
>
> 1. Redis调用fork,子进程根据内存中的数据快照,往临时文件中写入重建数据库状态的命令。
> 2. 父进程继续处理客户端请求,除了将写命令追加到原来的文件中,同时将其缓存起来。这样可以保证子进程如果重写失败不会出现问题。
> 3. 当子进程写入完成后通知父进程,父进程就将缓存中的命令写入到临时文件中。
> 4. 父进程将临时文件替换旧的AOF文件并重命名,后续的命令追加到新的AOF文件中。

## 总结
两种持久化方式既可以单独使用,也可以同时使用,也可以都不使用。
无论使用AOF还是快照持久化机制,将数据写到硬盘都是必要的,除了持久化之外,用户还应该对持久化生成的文件进行备份,增加安全性。

Redis持久化机制和AOF重写原理