Redis_持久化

1、持久化的介绍

为什么需要持久化?

我们知道Redis是基于内存存储的,有一个问题就是断电即失,所以Redis提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能,从内存当中同步到硬盘上,这个过程叫做持久化过程。

Redis支持两种形式的持久化,一种是RDB另一种是AOF;

2、RDB持久化

RDB持久化就是把当前Redis数据库中的内存数据保存到硬盘的过程,RDB方式是Redis默认支持的;在指定时间间隔内写入硬盘,压缩成一个二进制文件(dump.rdb).

RDB持久化的触发方式有两种:自动触发和手动触发;

RDB持久化的触发条件有:

  • 符合自定义配置的快照规则;
  • 执行save或者bgsave命令;
  • 执行flushall命令;
  • 执行主从复制操作;

2.1自动触发

通过在redis.conf配置文件中进行配置

save 900 1     #表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10    #表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000  #表示60  秒内如果至少有 10000 个 key 的值变化,则保存
  • save: 这是默认触发Redis的RDB持久化的条件,如果我们用Redis只做缓存功能,而不需要持久化,就可以不用配置所有的sava以此来停止保存功能。
  • **stop-writes-on-bgsave-error :**默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了。
  • **rdbcompression ;**默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
  • **rdbchecksum :**默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
  • **dbfilename :**设置快照的文件名,默认是 dump.rdb
  • **dir:**设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。

2.2手动触发

通过save或者bgsave命令;一般是不会用命令生成RDB文件;

  • save:此命令会使用Redis的主线程进程同步存储,阻塞当前的Redis服务器,造成服务不可用,直到RDB过程完成。无论当前服务器数据量大小,线上不要用。
  • bgsave:此命令会通过fork()创建子进程,在后台进程存储。只有fork阶段会阻塞当前Redis服务器,不必到整个RDB过程结束,一般时间很短。因此Redis内部涉及到RDB都采用bgsave命令。
  • 这里注意一点,无论RDB还是AOF,由于使用了写时复制,fork出来的子进程不需要拷贝父进程的物理内存空间,但是会复制父进程的空间内存页表。

2.3RDB运行原理

bgsave的原理是fork() + copyonwrite

1.fork()

fork()是unix和linux这种操作系统的一个api,而不是Redis的api。

fork()用于创建一个子进程,注意是子进程,不是子线程。fork()出来的进程共享其父类的内存数据。仅仅是共享fork()出子进程的那一刻的内存数据,后期主进程修改数据对子进程不可见,同理,子进程修改的数据对主进程也不可见。

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

  1. Redis执行bgsave命令,判断当前是否存在正在执行的子进程,如RDB/AOF子进程,存在,则bgsave命令直接返回
  2. 不存在,则使用fork函数复制一份当前进程的副本(子进程),子进程与Redis主进程共享同一份内存空间,所以子进程可以搞他的RDB文件持久化工作,主进程又能继续他的对外提供服务,二者互不影响。
  3. 父进程继续接受并处理客户端发来的命令;
  4. 子进程开始将内存中的数据写入到硬盘中的临时文件。当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
  5. 子进程告诉父进程处理完成,至此,一次快照操作完成
2.copyonwrite

主进程和子进程共享了一块内存空间,怎么做到的彼此更改互不影响吗?

主进程fork()子进程之后,内核把主进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向主进程。这也就是共享了主进程的内存,当其中某个进程写内存时(这里肯定是主进程写,因为子进程只负责rdb文件持久化工作,不参与客户端的请求),CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入内核的一个中断例程。中断例程中,内核就会把触发的异常的页复制一份(这里仅仅复制异常页,也就是所修改的那个数据页,而不是内存中的全部数据),于是主子进程各自持有独立的一份。

其实就是更改数据的之前进行copy一份更改数据的数据页出来,比如主进程收到了set k 1请求(之前k的值是2),然后这同时又有子进程在rdb持久化,那么主进程就会把k这个key的数据页拷贝一份,并且主进程中k这个指针指向新拷贝出来的数据页地址上,然后进行更改值为1的操作,这个主进程k元素地址引用的新拷贝出来的地址,而子进程引用的内存数据k还是修改之前的。

copyonwritefork()出来的子进程共享主进程的物理空间,当主子进程有内存写入操作时,read-only内存页发生中断,将触发的异常的内存页复制一份(其余的页还是共享主进程的)。

2.4RDB优缺点

1.优点
  • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份
  • 只有一个文件,保存时间间隔的数据,方便压缩转移(就一个文件)
  • 因为RDB是利用fork下面的子进程来进行持久化,所有Redis加载RBD恢复数据会比使用AOF恢复数据快
2.缺点
  • 没办法做到实时准实时的持久化,如果出现断电或者宕机,可能导致最后面部分数据丢失。
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒。

3、AOF持久化

AOF是以日志的形式记录每一个写操作(读操作除外),服务器启动后就构建数据库,重再新执行AOF文件中的命令来恢复数据。

AOF会先把命令追加到AOF缓冲区,然后根据对应的策略写入硬盘,它只允许追加文件但不可以改写文件。

注意:如果RDB和AOF两种方式都打开,Redis会优先使用AOF的方式,因为AOF的持久化文件更加完整。

3.1自动触发

在 redis.conf 配置文件的 APPEND ONLY MODE 部分下:

  • appendonly:默认是关闭的,也就是说redis 默认使用的是rdb方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。

  • appendfilename :aof文件名,默认是"appendonly.aof"

  • **appendfsync:**aof持久化策略的配置(同步频率),有3种:

    • always:表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低,不建议配置;
    • everysec:表示每秒执行一次fsync,如果一秒内出现宕机,可能会导致丢失这1s数据。通常选择 everysec ,兼顾安全性和效率。
    • no:表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全;
  • no-appendfsync-on-rewrite:在AOF重写或者写入RDB文件的时候,会执行大量IO。此时,对于everysec和always的AOF模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。

    • 设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。
  • auto-aof-rewrite-percentage:默认值为100。AOF自动重写配置,当目前AOF文件大小超过上一次重写的AOF文件大小的百分之多少进行重写,即当AOF文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。

  • auto-aof-rewrite-min-size:64mb。设置允许重写的最小AOF文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写。

  • aof-load-truncated:AOF文件可能在尾部是不完整的,当redis启动的时候,AOF文件的数据被载入内存。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象 redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的AOF文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes。

3.2手动触发

使用bgrewriteaof命令:Redis主进程fork子进程来执行AOF重写,这个子进程创建新的AOF文件来存储重写结果,防止影响旧文件。

因为fork采用了写时复制机制,子进程不能访问在其被创建出来之后产生的新数据**。**

Redis使用“AOF重写缓冲区”保存这部分新数据,最后父进程将AOF重写缓冲区的数据写入新的AOF文件中然后使用新AOF文件替换老文件。

3.3AOF重写原理

为什么要重写?

由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,AOF 的文件会越来越大,占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以向 Redis 发送 BGREWRITEAOF 命令,这个命令会移除 AOF 文件中冗余的命令来重写 AOF 文件,使 AOF 文件的体积变得尽可能地小。实际上 AOF 文件重写并不需要对现有的 AOF 文件进行任何读取、分析或者写入操作,这个功能是根据通过读取服务器当前数据库状态实现的。

3.4AOF工作原理

当 Redis 需要以 AOF的形式持久化文件时, 服务器执行以下操作:

  1. 所有的写入命令追加到aof缓冲区
  2. AOF缓冲区根据对应appendfsync配置向硬盘做同步操作
  3. 定期对AOF文件进行重写
  4. Redis重启时,可以加载AOF文件进行数据恢复

3.5AOF优缺点

1.优点
  • 安全性相对RDB方式高很多。
  • AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。
  • AOF 文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。例如,如果我们不小心错用了 FLUSHALL 命令,在重写还没进行时,我们可以手工将最后的 FLUSHALL 命令去掉,然后再使用 AOF 来恢复数据。
2.缺点
  • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 效率相对RDB方式低很多。
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

4、总结

一般来说, 如果对数据的安全性要求非常高的话,应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值