1、为什么要持久化
redis数据是保存在内存中,如果不做持久化。一旦出现redis进程挂掉或者redis所在服务器宕机等异常情况,重启redis后缓存数据为空。大量请求过来,缓存命中率为0(即缓存已雪崩),导致数据访问直接穿透到DB这一层。DB也可能一下子无法承受过多并发的负载,直接挂掉。
简单点说,持久化是为了:数据恢复,灾难恢复。灾难恢复主要考虑到需要将持久化数据文件异地备份或云端备份,考虑到机房发生火灾、地震等不可抗因素。持久化也可以认为是一种伪高可用的表现。
2、持久化的两种机制
RDB(Redis DB):按照一定的规则,周期性的持久化。(默认开启)
AOF(Append Only File):每条写入命令以命令日志的方式追加到文件中。(默认关闭,如果和RDB同时开启,每次启动时优先以AOF文件来构建缓存数据,因为比较数据比较新)
3、RDB
不管是周期性持久化还是调用(save|bgsave|shutdown)等命令触发的持久化,原理都是类似。redis父进程会fork出一个子进程进行数据的持久化,父进程继续处理用户的请求,待子进程处理完后会用临时文件替换RDB文件。
优点:
1、数据紧凑,同样时间段的数据日志文件,RDB要比AOF的小
2、如果数据量大时,RDB的恢复速度比AOF快
缺点:
1、周期性的持久化势必会导致发生故障时,持久化的数据可能不是最新的,存在上次持久化与故障时间之间的缓存数据丢失问题。
2、如果数据量大,fork出的子进程写数据也比较耗时,会占用CPU等系统资源,也可能会是父进程存在短暂的停止响应。如果数据没写完,发生故障,也存在数据丢失。所以,如果在数据一致性要求比较高的场景,rdb不推荐不适合做第一优先的 恢复方案,适合冷备。
默认的触发策略:
save 900 1 (15分钟变更一次)
save 300 10 (5分钟变更10次)
save 60 10000 (1分钟变更1万次)
默认文件配置
dbfilename dump.rdb
持久化文件存储目录(RDB和AOF都适用),默认为根目录
dir ./
4、AOF
通过记录发送到服务器的写操作命令来形成日志文件(读操作不记录),当日志文件大小超过设置的阈值时,根据当前内存数据重新生成(rewrite)新的AOF文件。
开启AOF持久化
appendonly yes(默认no,关闭)
持久化文件名
appendfilename "appendonly.aof"
策略
appendfsync always #每次都同步,保证数据不会丢失,但会慢
appendfsync everysec #每秒同步,系统默认同步策略
appendfsync no #不主动同步,由操作系统决定,快,但数据容易丢失
修复日志文件
redis-check-aof --fix AOF配置文件名称
重写AOF文件
定义:AOF采用文件追加的方式持久化数据,所以文件会越来越大,为了避免这种情况发生,增加了重写机制
当AOF文件的大小超过了配置所设置的阙值时(默认为100%,即一倍大小),Redis就会启动AOF文件压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof手动触发。
原理:当AOF增长过大时,会fork出一条新的进程将文件重写(也是先写临时文件最后rename),遍历新进程的内存数据,每条记录有一条set语句。
重写AOF文件并没有操作旧的AOF文件,而是将整个内存中的数据内容用命令的方式重写了一个新的aof文件(有点类似快照)
触发机制:Redis会记录上次重写时的AOF文件大小,默认配置时当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
auto-aof-rewrite-percentage 100 (一倍)
auto-aof-rewrite-min-size 64mb
同步过程:
1、Redis 执行 fork() ,现在同时拥有父进程和子进程。
2、子进程开始将新 AOF 文件的内容写入到临时文件。
3、对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾: 这样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
4、当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
5、搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。