1. 持久化的作用
1. 持久化:Redis运行时所有的数据都保存在内存中,对数据的更新将会异步的存储到磁盘中,当Redis需要恢复数据时就加载磁盘中的数据
2. 持久化的实现方式:
- 快照:简单来说,就类似于用一个照相机将某个时间点的Redis中的数据“拍摄”下来保存在“照片”中,“照片”就是快照文件,将快照保存在磁盘中,即实现持久化,具体实现比如MySQL数据库中的MySQL Dump功能和Redis RDB功能
- 日志文件记录:将对数据的更新操作全部记录在一个日志文件中,当需要恢复数据时,只需要重新执行一遍日志中的操作即可,具体实现比如MySQL数据库中的MySQL Binlog功能和Redis AOF功能
2. Redis中的数据持久化方式——RDB
1. RDB:以快照方式来实现Redis数据的持久化操作,Redis执行一条RDB指令,生成一个RDB文件(二进制)并保存到硬盘中,该文件中保存了生成该文件时Redis中存储的所有数据,当Redis需要恢复这些数据时(比如重启)就可以重新加载这个RDB文件来恢复数据。RDB文件还有另一个用处,就是可以使用该文件来实现数据复制。
2. 生成RDB文件的触发条件:
- save(同步):save,直接在客户端中执行该命令,Redis就会生成一个RDB文件,同步执行指的是该命令会与普通命令一样,在唯一的命令队列(单线程)里排队,直到该命令执行完成之后(RDB文件生成完毕之后),才会执行save命令之后的命令,也就是会发生同步阻塞,尽量不用该命令来生成RDB文件,因为如果数据量过多,会引起长时间的阻塞;如果RDB文件存储的目标路径下有旧的RDB文件,那么就会将新的RDB替换旧的;save操作的时间复杂度为O(n)
- bgsave(异步):bgsave,直接在客户端中执行该命令,Redis就会生成一个RDB文件,异步执行指的是该命令不会与普通命令一样占用Redis的单线程执行,而是利用linux中的fork()函数(该函数依然会阻塞Redis主进程,不过该过程基本都非常快速)开辟一个Redis子进程来执行生成RDB文件,生成完成之后再返回给主进程RDB文件生成成功,在子进程生成RDB文件时,Redis会继续处理命令队列后续的命令;如果RDB文件存储的目标路径下有旧的RDB文件,那么就会将新的RDB替换旧的;save操作的时间复杂度为O(n)
- 自动:自动即指不需要执行命令即可自动生成RDB文件,不过需要配置一定条件来触发,需要配置seconds和changes两个参数,表示在seconds秒内对Redis中的数据修改的changes条时就会生成RDB文件;该方式有一定的问题,就是有可能造成生成RDB文件频率过高,进而导致对硬盘有一定的压力,而且阻塞时间也会变多。
3. 在redis.conf文件中对生成RDB文件的一些参数配置:
- 自动生成RDB文件的seconds和changes两个参数设置
- 配置生成的RDB文件的文件名,默认为dump.rdb
- 配置RDB文件的存储路径,默认为 ./ ,表示与redis.conf同级目录下
- 配置如果bgsave操作过程中出现异常错误,则立即停止写入数据到RDB文件中,默认为yes,不建议改动
- 生成RDB文件是否采用压缩的格式,默认为yes,不建议改动
- 在加载RDB文件时是否对RDB文件进行校验,默认为yes,不建议改动
4. 配置参数建议:
- 删除RDB自动生成配置参数,也就是把seconds和changes两个参数设置全部删除
- 把dbfilename的参数设置为dump-port.rdb,因为Redis是单线程,所以一台机器上往往会部署多个Redis以充分利用多核处理器,而每个Redis运行时会占用不同的端口,所以需要依据不同端口来生成对应的RDB文件名,防止重复,比如dump-6379.rdb
5. 一定会生成RDB文件的触发条件:
- 全量复制:在进行主从复制时,主节点会自动生成RDB文件
- debug reload:Redis中提供了一个debug级别的重启方式,该方式不会清空内存中的数据,但是会生成一个RDB文件
- shutdown:通过客户端shutdown命令关Redis时,会自动生成一个RDB文件
6. RDB存在的问题:
- 耗时而且耗费性能:耗时是因为RDB文件生成时会将Redis中的所有数据全部存储的RDB文件中,而且如果是采用save命令执行的话,耗时会更久;如果使用bgsave生成RDB文件,又会因为fork()函数消耗更多的性能;其次,本身生成RDB文件就是一个IO操作,如果数据量过多,那么会造成很严重的性能消耗
- 不可控,会发生数据丢失
3. Redis中的数据持久化方式——AOF
1. AOF原理:以日志文件记录分数来实现数据持久化,即每当一条数据修改命令被执行后,都会将该命令写入AOF文件中,当Redis需要回复数据时,只需要从AOF文件中一条条的将命令取出并执行。
2. AOF三种配置参数:
- always:每执行一条数据修改命令,都会将该命令写入AOF文件中,不会丢失数据,但是性能很差,对于IO的开销很大
- everysec:每隔一秒将数据修改命令写入AOF文件中,每次写入AOF文件意味着会丢失至少一秒的数据,性能稍好,默认该AOF配置参数
- no:由操作系统决定什么时候将数据修改命令写入AOF文件,不可控
3. AOF重写:如果对一个文件持续不停地写入数据,随着文件越来越大,那么IO速度也会越来越低,Redis提供了一个AOF重写的功能来降低AOF文件大小的增长速度;在记录的命令中,有很多是重复的、无用的、过期的命令,可以将这些命令进行一些优化和删减,比如对同一个key-value数据进行多次set命令,那么只需要记录最后一次set命令即可,比如某个数据已经过期(expire),那么该数据的相关语句就可以删除;通过对AOF文件进行AOF重写就可以减少磁盘占用量,增加数据恢复速度
4. AOF重写的实现方式:
- bgrewriteaof:是一条客户端执行命令,执行成功会返回给客户端ok,和bgsave类似,会通过fork开辟一个子进程来进行AOF重写,
- 使用配置文件:在Redis的配置文件redis.conf中可以通过auto-aof-rewrite-percentage(AOF文件增长率)和auto-aof-rewrite-min-size(AOF文件最大字节长度)两个配置参数来实现自动AOF重写;如果AOF文件的大小已经达到了auto-aof-rewrite-min-size,并且AOF文件大小的增长速度到达了auto-aof-rewrite-percentage,则会进行一次重写。比如下图中的配置参数auto-aof-rewrite-min-size 64mb表示AOF文件的大小要超过64mb,auto-aof-rewrite-percentage 100表示增长率要达到100%(如果上一次进行AOF重写时AOF文件的大小为100mb,那么下一次AOF文件的大小为200mb时就表示增长率为100%),这两个条件同时满足就会执行一次AOF重写
5. AOF功能的相关配置参数:在Redis的配置文件redis.conf中,除了上面的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size
- 修改appendonly为yes;修改appendfilename为"appendonly-port.aof"
- port处写Redis运行所占用的端口号,该参数表示生成的AOF文件的名称
- 可以修改appendfsync,但建议使用默认everysec
- 修改dir,配置AOF文件的存储目录路径,该目录下也存储RDB文件
- 修改no-appendfsync-on-rewrite为yes,表示是否在进行AOF重写的同时,可以进行AOF普通的命令append操作,yes表示不能进行(这样会有更好的性能),具体取决于是否允许在AOF重写期间丢失Redis执行的一些数据修改命令
4. Redis中的数据持久化方式AOF与RDB的选择
1. 比较RDB与AOF:
- 加载优先级:Redis会优先加载AOF文件来恢复数据,其次是RDB文件
- 文件体积:RDB文件较小,AOF文件较大,因为RDB文件采用二进制存储,而且采用压缩格式,所以体积较小
- 数据恢复速度:RDB较快,AOF较慢
- 安全性:AOF的存储策略不同,不一定会丢失数据,比如always就不会丢失,但everysec就会丢失至少1秒的数据;RDB一定会丢失数据
- RDB的读写操作性能消耗较大,而AOF的读写性能消耗相对小一点
2. 依据以上对比,根据实际应用环境来进行选择。