Redis持久化解读

一、简介

  • redis是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失。幸好Redis还为我们提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Append Only File)。 -

  • 持久化是将程序数据在持久状态和瞬时状态间转换的机制。对于程序来说,程序运行中数据是在内存的,如果没有及时同步写入到磁盘,那么一旦断电或者程序突然奔溃,数据就会丢失了,只有把数据及时同步到磁盘,数据才能永久保存,不会因为宕机影响数据的有效性。而持久化就是将数据从程序同步到磁盘的一个动作过程。

  • 数据存放于:

    • 内存:高效、断电(关机)内存数据会丢失
    • 硬盘:读写速度慢于内存,断电数据不会丢失

持久化

二、redis中持久化的两种方式(RDB和AOF)

在我们安装了redis之后,所有的配置都是在redis.conf文件中,里面保存了RDB和AOF两种持久化机制的各种配置。

1.RDB机制

  • RDB是redis的默认持久化机制

  • RDB其实就是把数据以快照的形式保存在磁盘上。什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。 几KB快照相当于几十G的数据

  • RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

  • 既然RDB机制是通过把某个时刻的所有数据生成一个快照来保存,那么就应该有一种触发机制,是实现这个过程。对于RDB来说,提供了三种机制:save、bgsave、自动化。我们分别来看一下

1、save触发方式

  • 该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程如下:

在这里插入图片描述

  • 执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。

2、bgsave触发方式

  • 执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体流程如下:

在这里插入图片描述

  • 具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。

3、自动触发

自动触发是由我们的配置文件来完成的。在redis.conf配置文件中,里面有如下配置,我们可以去设置:

save:这里是用来配置触发 Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave。

默认如下配置:

#表示900 秒内如果至少有 1 个 key 的值变化,则保存save 900 1#表示300 秒内如果至少有 10 个 key 的值变化,则保存save 300 10#表示60 秒内如果至少有 10000 个 key 的值变化,则保存save 60 10000

不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。

stop-writes-on-bgsave-error :默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了

rdbcompression :默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。

rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

dbfilename :设置快照的文件名,默认是 dump.rdb

dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。

  • 我们可以修改这些配置来实现我们想要的效果。因为第三种方式是配置的,所以我们对前两种进行一个对比:
    在这里插入图片描述

4、RDB的优势与劣势

  • 优势:
    • RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
    • 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
    • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
  • 劣势:
    • RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。

5、总结

  • bgsave命令执行过程中,只有fork子进程时会阻塞服务器;而对于save命令,整个过程都会阻塞服务器;因此save已基本被废弃,线上环境要杜绝save的使用;

2.AOF机制

  • 由于快照方式是在一定间隔时间做一次的,所以如果redis 意外down 掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof 持久化方式。
  • RDB文件保存的是数据库的键值对数据,AOF保存的s是数据库执行的写命令。
  • Append-only file:aof 比快照方式有更好的持久化性,是由于在使用aof 持久化方式时,redis 会将每一个收到的写命令都通过write 函数追加到文件中(默认是appendonly.aof)。当redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
  • AOF的实现流程有三步:
    • append->write->fsync
    • append追加命令到AOF缓冲区,write将缓冲区的内容写入到程序缓冲区,fsync将程序缓冲区的内容写入到文件

1、持久化原理

  • 他的原理看下面这张图:

在这里插入图片描述

  • 每当有一个写命令过来时,就直接保存在我们的AOF文件中。

2.文件重写原理

  • AOF的方式也同时带来了另一个问题。 AOF持久化模式每个写命令都会追加到AOF文件,随着服务器不断运行,AOF文件会越来越大,为了避免AOF产生的文件太大,服务器会对AOF文件进行重写,将操作相同key的相同命令合并,从而减少文件的大小。

  • 举个例子,要保存一个员工的名字、性别等信息:

    > hset employee_12345 name "hoohack"
    > hset employee_12345 good_at "php"
    > hset employee_12345 gender "male"
    
  • 只是录入这个哈希键的状态,AOF文件就需要保存三条命令,如果还有其他,比如删除,或者更新值的操作,那命令将会更多,文件会更大,有了重写后,就可以适当地减少文件的大小。

  • AOF重写的实现原理是先服务器中的数据库,然后遍历数据库,找出每个数据库中的所有键对象,获取键值对的键和值,根据键的类型对键值对进行重写。比如上面的例子,可以合并为下面的一条命令:

    > hset employee_12345 name "hoohack" good_at "php" gender "male"。
    
  • AOF的重写会执行大量的写入操作,Redis是单线程的,所以如果有服务器直接调用重写,服务器就不能处理其他命令了,因此Redis服务器新起了单独一个进程来执行AOF重写。

  • Redis执行重写的流程:
    在这里插入图片描述

  • 在子进程执行AOF重写时,服务端接收到客户端的命令之后,先执行客户端发来的命令,然后将执行后的写命令追加到AOF缓冲区中,同时将执行后的写命令追加到AOF重写缓冲区中。
    等到子进程完成了重写工作后,会发一个完成的信号给服务器,服务器就将AOF重写缓冲区中的所有内容追加到AOF文件中,然后原子性地覆盖现有的AOF文件。

3. AOF也有三种触发机制

  • appendonly yes //启用 aof 持久化方式
    • appendfsync always // 同步持久化,收到写命令就立即写入磁盘,性能较差但数据完整性比较好
    • appendfsync everysec // 异步操作,每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中。但是如果一秒内宕机,有数据丢失
    • appendfsync no //完全依赖 os,性能最好,持久化没保证,从不同步

4.AOF机制的优势与劣势

  • 优势:
    • AOF的持久化方式也是通过配置的不同,默认配置的是每秒同步,最快的模式是同步每一个命令,最坏的方式是等待系统执行fsync将缓冲同步到磁盘文件中,大部分操作系统是30s。通常情况下会配置为每秒同步一次,所以最多会有1s的数据丢失
    • AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损
    • AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
    • AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
  • 劣势:
    • 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
    • AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的

3.RDB和AOF该如何选择

  • 不要仅仅使用RDB,因为那样会导致你丢失更多的数据
  • 也不要仅仅使用AOF,第一:通过AOF做冷备,没有RDB做冷备恢复的速度快。第二:RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF复杂的备份和恢复机制bug。(AOF的数据恢复速度没有RDB来的快,RDB备份机制方便快捷)
  • 综合使用AOF和RDB两种持久化机制,使用AOF来保证数据不丢失,作为数据恢复的第一选择;用RDB做不同程度的冷备,当AOF备份文件丢失或损坏不可用时,可以使用RDB快照文件快速的恢复数据。

参考资料

redis持久化
详解Redis中两种持久化机制RDB和AOF(面试常问,工作常用)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章