Redis学习之数据持久化,防止数据丢失

Redis的高性能是因为它是一个基于内存存储计算的非关系型数据库,这就导致它存在一个严重的问题:一旦服务器宕机,内存中的数据将全部消失。
目前,Redis有两种持久化方式:

  • AOF(Append Only File)日志
  • RDB(Redis DataBase)快照

AOF实现及原理

Redis写日志的逻辑是先执行命令,把数据写入内存中,再执行写日志操作。而我们知道的MySQL的WAL(全称:Write-Ahead Logging)预写日志系统却是先写日志(undo log,redo log,binlog),再执行数据的实际写入,防止发生故障时进行恢复。

首先我们要知道,MySQL的写操作是随机IO,且是要写入磁盘的,比较耗性能,先写入日志,就变成了顺序写入,再有后台线程以异步的方式去更新数据,同时大大降低了IO的次数,从而提供性能。

而Redis本身就是往内存中写数据,那么AOF先执行命令后记日志的原因是什么呢?Redis是为了避免命令语句的正确性检查开销。要是当Redis先向AOF里面记录日志,且没有对这些操作命令做语法检查,那么记录的日志将是错误的操作命令。一是这根本是一条错误的无效命令,没有发生对应数据的增量或更改;二是当使用该日志恢复数据时,执行该条命令时就会发生错误。而这种先写后记录日志的方式,可以避免以上错误,只有当命令执行成功时,Redis才会去执行日志的操作,否者,会直接抛出异常。除此之外,我们知道Redis是“单线程”的,所以AOF还有一个好处:它是在执行完命令之后再记录日志,因此不会阻塞当前的写操作。

顺序执行的操作都会存在一个风险,如果刚执行完一个命令,还没写入,服务器就宕机了,那么这条数据就会无法恢复。同时写入操作也会带来一定的风险,当AOF日志在主线程中执行写入磁盘时,当磁盘写压力大时,写入变得很慢,从而影响后续的操作被阻塞。

对于上述问题,Redis给我们提供了三种写回策略,通过配置项appendfsync决定。

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘。
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘。
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

三种写回策略,各有优缺点,总结如下表。

appendfsync配置项写会时机优点缺点
Always同步写回可靠性高,数据基本不会丢失每个性能都要落盘,性能较差
Everysec每秒写回性能适中宕机时丢失1s的数据
No操作系统控制写回性能好宕机时丢失离上次写回后的数据

同时AOF如其名,是以文件追加的方式写入,随着写入的命令越来越多,文件也会越来越大,这个时候,AOF重写机制就上场了。简单来说,就是对旧的AOF日志文件进行压缩精简,把一些重复的操作以及最终目标数据一致的多条操作,多变一,精简成单条命令。

RDB实现及原理

AOF日志记录的是操作命令,日志一多,恢复数据时需要再次执行这些命令,会比较耗时,影响上层应用的正常使用。RDB相比AOF,记录的是内存中某一时刻的数据状态,而且RDB文件是一个二进制文件,
结构非常紧凑,可以加速数据恢复。

Redis提供了两个命令来生成RDB文件。

  • save:在主线程中执行,会导致阻塞。
  • bgsave:创建一个子进程,专门用来写入RDB文件,避免了主线程的阻塞,这也是Redis RDB文件默认的生成方式。

bgsave子线程是Redis主线程fork生成的,可以共享主线程的所有内存数据,若在快照执行期间内,数据被改动了,那该怎么办。为了快照而阻塞主线程的写操作,肯定是不可取的,这个时候,Redis会借助操作系统的COW(Copy-On-Write)写时复制。简单来说,就是主线程要修改一块数据是,这块数据会被copy一份,生成副本;然后,主线程在这个副本上对数据做修改操作;同时,bgsave子进程就可以继续读取原来的文件,写入到RDB文件中,从而避免了对主线程写操作的影响。

但是RDB频繁的执行快照,也会给系统带来压力。一发面是频繁的写操作,会给磁盘带来压力,频繁的快照可能导致上一个快照还没有落盘,下一个快照就又开始了,导致各种异常情况。另一方面是bgsave子线程虽然执行期间不影响主线程,但是它需要通过主线程fork操作创建出来,这个过程是在主线程中执行的,是会阻塞主线程的,频繁的快照,也会导致主线程执行频繁的fork操作,从而阻塞主线程的其他操作。

有什么好的办法来解决上述问题吗?结合AOF和RDB各自的优缺点,Redis4.0之后,可以混合使用二者。内存快照按一定的频率执行,两次快照之前,使用AOF来记录期间的操作命令。这样一来,快照不用很频繁地执行,也就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值