我们都知道在对于Redis的开发或者面试的过程中,很容易就会遇到这个关于 Redis 持久化的问题,而我们在面试的时候,经常会有小伙伴只能说出这个 Redis 持久化的两种方式,后续可能还会对比一些区别,但是对于怎么实现这个持久化的操作,都不是很熟,而且也并没有实际应用过,以及什么时候应该使用什么类型的持久化,今天了不起就来给大家说说这个持久化。
Redis持久化
什么是 Redis 的持久化,我们都知道,Redis 是基于内存存储的 key-value 的数据库,那么如果出现断电了,这就会导致数据丢失,那么持久化就非常重要了,也就是说,可以把数据写入到硬盘上,而这个写入到硬盘上面的操作,就是持久化。
Redis 持久化的两种方式
- RDB(Redis DataBase)
- AOF(Append Of File)
什么是 RDB 呢?
简而言之,就是在指定的时间间隔内,定时的将 redis 存储的数据生成Snapshot快照并存储到磁盘等介质上。
那么什么是 AOF 呢?
AOF 则是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
而 Redis 也是有自己默认的持久化的方式的,那就是 RDB 。
RDB持久化方式的原理
我们先说实现原理:
Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化,这个机制很有意思,也很少人知道。多进程 COW 也是鉴定程序员知识广度的一个重要指标。
Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以将父子进程想像成一个连体婴儿,共享身体。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。
子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。
这个时候就会使用操作系统的 COW 机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
而这,就是 fork,也就是多进程。
那么我们应该怎么去配置,然后怎么知道这个 默认的持久化方式呢?
RDB 修改持久化
在redis.conf中,可以修改rdb备份文件的名称,默认为dump.rdb,如下:
图片
图片
而存放目录也是默认为Redis启动命令所在的目录
从这里我们能去配置 Redis 的持久化的方式。
接下来我们就得看看怎么能触发这个持久化的规则了。
触发 RDB 持久化操作
图片
配置文件我们能看看到。
900秒(15分钟)后,如果至少有一个按键发生变化。
300秒(5分钟)后,如果至少有10个按键发生变化
60秒后,如果至少有10000个密钥发生更改
而这个 save 就是用来配置备份的规则的。
其实这个就是相当于是自动备份了,这个配置直接都是使用的默认,或者咱们自己去修改这个 save 的操作。
如果我们想要恢复备份其实很简单,其实当你重启的时候,他默认会从咱们刚才看到的 dir 下去恢复,所以,如果你修改了备份的目录,那么你想恢复备份,那么你就得之前的 dump.rdb 放到 dir 的下面,然后重启 redis 就可以恢复了。
既然我们了解了这个 RDB 持久化了,那么接下来就得来说说这个 AOF 持久化了。
AOF 持久化
AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。
假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。
所以按照使用来说,更多的人会选择 RDB 的持久化。
写入操作
Redis 在收到客户端修改命令后,先进行相应的校验,如果没问题,就立即将该命令存追加到 .aof 文件中,也就是先存到磁盘中,然后服务器再执行命令。这样就算遇到了突发的宕机情况情况,也只需将存储到 .aof 文件中的命令,进行一次“命令重演”就可以恢复到宕机前的状态。
也就是说,他是先存磁盘,然后再去执行命令。
而 Redis 为了提升写入效率,它不会将内容直接写入到磁盘中,而是将其放到一个内存缓存区(buffer)中等到缓存区被填满时采用异步真正将缓存区中的内容写入到磁盘里。
所以就有了问题,如果机器突然宕机,AOF 日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。
我们都能知道这么浅显的问题,那么 Redis 一定是可以解决的,解决方案都很粗暴,直接就是配置文件上写明了。
图片
- Everysec默认
服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据,通常都使用它作为 AOF 配置策略
- Always
服务器每写入一个命令,就调用一次 fsync函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据,但是其执行速度较慢
- No
服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的,所以这种策略,不确定性较大,不安全。
而我们如果选用了 AOF ,那么在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作( Everysec),这样既保持了高性能,也让数据尽可能的少丢失。
AOF 配置开启
AOF默认不开启,可以在 redis.conf 文件中对AOF进行配置开启:
appendonly no # 是否开启AOF,yes:开启,no:不开启,默认为no
appendfilename "appendonly.aof" # aof文件名称,默认为appendonly.aof
dir ./ # aof文件所在目录,默认./,表示执行启动命令时所在的目录
AOF 的备份恢复
AOF的备份机制和性能虽然和RDB不同,但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。
所以关于 Redis 的持久化操作,你学会了么?