为什么要持久化
Redis是内存数据库,宕机后数据会消失,Redis重启后快速恢复数据,要提供持久化机制。
Redis的两种持久化方式:RDB和AOF
Redis持久化不保证数据的完整性,有可能会丢数据。当Redis用作DB时,DB数据要完整,所以一定要有一个完整的数据源(文件、mysql),在系统启动时,从这个完整的数据源中将数据load到Redis中。
RDB持久化
RDB(Redis DataBase Backup file),是redis默认的存储方式,RDB方式是通过快照( snapshotting )完成的。它保存的是某一时刻的数据并不关注过程。RDB保存redis某一时刻的数据的快照,快照文件称为RDB,默认保存在当前运行目录
触发快照的方式
1. 符合自定义配置的快照规则;
2. 执行save或者bgsave命令;
3. 执行flushall命令;
4. 执行主从复制操作 (第一次)。
保存方式:
1.
由Redis主进程来执行RDB会阻塞所有的命令
2.
开启子进程执行RDB,避免主进程受到影响
注:Redis停机时会执行一次RDB
Redis内部有触发RDB的机制
默认是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次。
注意: 30s内12个key改变,触发快照,会将前10个key进行持久化,而后两个key重新从0s开始计算,如果达到30s,没有满足10个key改变的条件,那么不进行持久化操作
stop-writes-on-bgsave-error
当Redis无法写入磁盘的话,直接关掉Redis的写操作。默认yes
注:在开启RDB且最近一次bgsave执行失败的情况下,如果该参数为yes,则Redis会阻止客户端的写入,直到bgsave执行成功。
rdbcompression 压缩文件
建议不开启压缩,会消耗cpu
rdbchecksum 检查完整性
存储快照后,还可以让redis使用CRC64算法来进行数据校验
(但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能)
如何停止RDB
动态停止RDB:redis-cli config set save “”#save后给空值,表示禁用保存策略rdb文件
- Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
- 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”
- 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程
读时共享,写时复制
RDB保存策略原理
bgdsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据,完成fork后读取内存数据并写入
RDB的优缺点:
优点:
1. RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照,适合备份,全量复制等场景。
2. 加载RDB恢复数据远远快于AOF的方式。
缺点:
1.没办法做到实时持久化/秒级持久化,因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。
2.最后一次持久化后的数据可能丢失
3.fork子进程,压缩,写出rdb文件都比较耗时
AOF持久化
AOF全称为Append Only File (追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
注:只允许追加不允许改写的文件
AOF默认不开启,需要修改redis.conf配置文件来开启AOF
appendfilename “appendonly.aof”:默认生成的文件名字:appendonly.aof
开启aof:appendonly yes
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓存区,然后表示每隔1秒将缓存取数据写入AOF文件,是默认的方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓存区内容写入磁盘
appendfsync no
配置项 | 刷盘时机 | 优点 | 缺点 |
Always | 同步刷盘 | 可靠性高,几乎不丢数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最大丢失1秒数据 |
no | 操作系统控制 | 性能最好 | 可靠性较差,可能丢失大量数据 |
因为是记录命令,AOF文件会比RDB文件大的多,而且AOF会记录对同一个key的多次写操作,但是自有最后一次操作才有意义,通过执行
bgrewriteaof
命令,可以将AOF文件执行重写功能,用最少的命令达到相同的效果。
重写原理,如何实现重写
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作
no-appendfsync-on-rewrite:
如果 no-appendfsync-on-rewrite=yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
如果 no-appendfsync-on-rewrite=no, 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)
触发机制,什么时候重写
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写
auto-aof-rewrite-percentage:设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)
auto-aof-rewrite-min-size:设置重写的基准值,最小文件64MB。达到这个值开始重写。
重写流程
(1)bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
(2)主进程fork出子进程执行重写操作,保证主进程不会阻塞。
(3)子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
(4)
a.子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。
b.主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
(5)使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
AOF的优缺点:
优点
- 备份机制更稳健,丢失数据概率更低。
- 可读的日志文本,通过操作AOF稳健,可以处理误操作。
缺点
- 比起RDB占用更多的磁盘空间。
- 恢复备份速度要慢。
- 每次读写都同步的话,有一定的性能压力。
RDB与AOF对比
RDB | AOF | |
持久化方式 | 定时对整个内存做快照 | 记录每一次执行命令 |
数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
文件大小 | 会压缩,文件体积小 | 记录命令,文件体积很大 |
宕机恢复时间 | 很快 | 慢 |
数据恢复优先级 | 低,因为数据完整性不如AOF | 高,因为数据完整性更高 |
系统资源占用 | 高,大量cpu和内存消耗 | 低,主要是磁盘IO资源但AOF重写时会占用大量的cpu和内存资源 |
使用场景 | 可以容忍数分钟的数据丢失,对求更快的启动速度 | 对数据安全性要求较高常见 |