Redis学习篇之持久化机制

参考:Redis设计与实现
事先声明:本文为对该书的总结。并参考
https://github.com/Snailclimb/JavaGuide/blob/master/docs/database/Redis/Redis持久化.md 作者: JavaGuide
https://segmentfault.com/a/1190000016951866 作者:java3y

Redis是一款基于key-value的内存数据库,它所有的数据都存在内存中,我们必须采用合适的持久化机制将数据保存在磁盘中,否则一旦服务器重启,宕机,数据就会丢失

Redis提供两种持久化机制:RDB、AOF

RDB持久化机制

RDB会在某个时间点上将数据库中的数据全部导入到一个.rdb的二进制文件中相当于形成了一份当前数据的快照,这个文件保存在硬盘中,所以服务器启动时就可以加载这个文件还原数据库中的数据到内存中,注意!这个加载过程是会阻塞请求的

RDB文件生成可以手动执行也可以通过,服务器配置选项定期执行

这几种情况下会生成RDB文件

  • SAVE命令:该命令会阻塞Redis服务器进程,该命令执行时所有请求不会被响应
  • BGSAVE命令:该命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续接收请求
  • SAVE配置项间隔性生成: 该配置项会调用BGSAVE命令
  • SHUTDOWN命令:该命令会停止当前redis服务器,此时调用SAVE命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在SAVE命令执行完毕之后关闭服务器。
  • 主从复制时:当从服务器给主服务器发送SYNC命令时

redis默认采用RDB持久化机制会自动间隔性保存数据,在redis.onf配置文件中可以看到save配置项
在这里插入图片描述
该配置项使用的是BGSAVE命令,只要满足3个条件中的一个,就会执行BGSAVE命令
Redis服务器会调用周期性操作函数sererCron默认每隔100ms检查sava的条件是否满足
该函数会遍历3个配置,

  1. 如果当前时间距离上次保存的时间已经超过900s 并且900s内对数据库有一次修改 执行命令
  2. 否则继续判断如果当前时间距离上次保存的时间已经超过300s 并且300s内对数据库有10次修改 执行命令
  3. 否则 如果当前时间距离上次保存的时间已经超过60s 并且60s内对数据库有10000次修改 执行命令

这时我们可以发现因为RDB是隔一段时间进行生成.rdb文件的,如果我们系统发生崩溃:那么最后一次生成文件之后所有的命令请求对数据进行的修改都不会被保存下来

AOF持久化机制

与RDB持久化通过保存数据库中的键值对来记录数据不同,AOF持久化机制是通过保存Redis服务器所执行的写命令来记录数据库状态的。如果Redis服务器同时开启了RDB和AOF持久化,服务器会优先使用AOF文件来还原数据(因为AOF更新频率比RDB更新频率要高,还原的数据更完善)

我们可以通过redis.conf配置文件中的appendonly配置选项来开启AOF持久化功能
在这里插入图片描述
当我们调用写命令时,AOF持久化会将我们的命令写到一个.aof文件中

在这里插入图片描述
appendonly.aof文件中的内容如下
在这里插入图片描述

AOF持久化的实现分为3步

  • 命令追加
    当执行完一个写命令,会以协议格式将被执行的命令追加到aof_buf缓冲区的末尾,这个缓冲区被定义在服务器结构redisServler中

  • 文件写入
    调用flushAppendOnlyFile函数将缓冲区的内容写入和保存到AOF文件中,这里注意写入之后并没有立即保存到AOF文件中,因为现代操作系统存在缓冲区,它会将写入磁盘文件中的数据先缓存起来,我们还需要将缓冲区中的数据同步到文件中。

  • 文件同步
    由flushAppendOnlyFile函数决定啥时候将数据同步到磁盘文件中

就是这个同步行为我们可以通过redis.conf配置文件中的appendfsync配置项来修改
在这里插入图片描述
可以看到有3个值供我们配置 默认的值为everysec

  • always
    每次将aof_buf缓冲区的数据写入内存时都进行同步
  • everysec
    如果距离上次同步超过一秒,那么再次同步
  • no
    不进行同步操作,由操作系统决定何时同步

三个选项值总结:

always 可以实现将数据丢失减到最少,不过这种方式需要对硬盘进行大量的写入而且每次只写入一个命令,十分影响Redis的速度性能很低。另外使用固态硬盘的用户谨慎使用always选项,因为这会明显降低固态硬盘的使用寿命。

everysec让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。

当Redis出现故障宕机时 no 选项会使上次同步AOF文件之后所有的写命令数据全部丢失,并且如果用户的硬盘处理写入操作的速度不够的话,那么当缓冲区被等待写入的数据填满时,Redis的写入操作将被阻塞,这会导致Redis的请求速度变慢。

持久化生成AOF文件后,那么服务器在启动时,就可以通过载入和执行AOF文件中保存的命令来还原数据库之前的数据
实现细节
Redis服务器会创建一个不带网络连接的伪客户端,因为redis命令 只能在客户端中执行,并且这些命令直接来源于AOF文件,所以不需要网络连接。
这个伪客户端会从AOF文件中分析并读取命令并执行。
在这里插入图片描述

AOF重写

因为AOF持久化需要保存每一次的写命令,当服务器运行时间很长,AOF文件就会变得越来越大,如果不进行把控,体积过大的AOF文件会对服务器产生影响。

为了解决这种AOF文件体积膨胀的问题,Redis采用了AOF文件重写功能
什么是AOF重写?
看个例子
set
执行完这3条命令后,AOF文件也需要保存3条命令
然而根本不需要这样做,只需要保存一条rpush name wmh wyy jay 就解决了

AOF重写会把原来的AOF文件中一些不必要多余的命令去掉,但它并不需要对原来的AOF文件进行任何操作
它会创建一个新的AOF文件,并读取当前的数据库中的数据用新的命令代替原来多余的多条命令写入新的AOF文件,然后代替老的文件。

Redis通过执行BGREWRITEAOF命令会执行AOF重写

在这里插入图片描述
设置这两个选项代表自动执行BGREWRITEAOF命令。
举例:假设用户对Redis设置了如下配置选项并且启用了AOF持久化。那么当AOF文件体积大于64mb,并且AOF的体积比上一次重写之后的体积大了至少一倍(100%)的时候,Redis将执行BGREWRITEAOF命令。

BGREWRITEAOF命令:
因为新的AOF文件需要执行大量的命令会耗费大量CPU时间。
所以Redis将AOF重写程序放到子进程里执行,BGREWRITEAOF命令会像BGSAVE命令一样fork出一个子进程来完成重写AOF的操作,从而不会影响到主进程。主进程还是可以接收请求执行写命令

AOF后台重写是不会阻塞主进程接收请求的,但是新的写命令请求可能会导致当前数据库和重写后的AOF文件的数据不一致!

当子进程执行AOF重写时,服务器进程还需要继续接收命令请求,这些请求会对数据进行修改,会导致数据库的数据和重写后的AOF文件数据不一致。

解决数据不一致:
Redis服务器设置了一个AOF重写缓冲区,这个缓存区会在服务器创建出子进程之后使用

在子进程执行AOF重写期间,服务器进程接收请求时会做出3步

  1. 执行命令
  2. 将命令追加入aof缓冲区
  3. 将命令追加入aof重写缓冲区

这3步保证了子进程重写期间,

  • 对原AOF文件正常进行
  • 这期间的命令被重写缓冲区保存了下来

当子进程执行完之后,会向服务器进程发出一个信号,服务器进程接收到信号调用信号处理函数执行2个操作

  • 将重写缓冲区的内容写入到新的AOF文件
  • 原子的覆盖了原有的AOF文件

重写流程图示:
在这里插入图片描述

RDB持久化机制的优点和缺点

优点
(1)相对于AOF持久化机制基于回放命令来说,直接基于RDB数据文件来重启和恢复数据,更加快速
(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可

缺点
(1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据
(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒

一般不要让RDB的间隔太长,否则每次生成的RDB文件太大了,对redis本身的性能可能会有影响的

AOF持久化机制的优点和缺点

优点
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
(3)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
缺点:
(1)数据恢复的时候,速度会比较慢,因为需要执行命令
(2)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
(3)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次AOF文件,当然,每秒一次fsync,性能也还是很高的

RDB和AOF到底该如何选择

(1)不要仅仅使用RDB,因为那样会导致你丢失很多数据

(2)也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备恢复速度快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug

(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

Redis 4.0 对于持久化机制的优化

Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分就是压缩格式不再是 AOF 格式,可读性较差。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值