Redis 如何避免数据丢失


前言

Redis一个普遍使用的场景就是当作缓存使用,因为它把后端数据库中的数据存储在内存中,然后直接从内存中读取数据,响应速度会非常快。但是这里也有一个不容忽视的问题那就是:一旦服务器宕机,内存中的数据将全部丢失
目前Redis的持久化主要有两大机制,即:AOP(Apend Only File)日志和RDB(Redis Database)快照


一、AOF

||日志是如何实现的

说到日志,我们比较熟悉的是数据库的写前日志,在实际写数据之前,先把修改的数据记录到日志文件当中,以便故障时进行恢复。不过,AOF 日志正好相反,它是写后日志,"写后"的意思是 Redis 是先执行命令,把数据写入内存,然后才记录日志。
在这里插入图片描述
AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。

||写后日志的优势与风险

为了避免额外的检查开销,Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查。

如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。而写后日志这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错。

所以,Redis 使用写后日志这一方式的一大好处是,可以避免出现记录错误命令的情况。除此之外,写后日志的另一个好处就是它是在命令执行之后才记录日志,不会阻塞当前的写操作。

AOF也有两个潜在的风险:

  • 风险一:如果刚执行完一个命令,还没来得及写入日志文件就宕机了,那么这个命令和数据就有丢失的风险。如果这个此时Redis只是用作缓存,还可以从后端数据库重新读取数据进行恢复;如果Redis是直接用作数据库的话,此时命令没有写入日志,所以无法用日志进行恢复。
  • 风险二:AOF虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。比如日志文件在写入磁盘的时候,如果磁盘的写入压力较大,就会导致写盘很慢,进而导致后续操作无法执行。

这两个风险都是和磁盘写入时机相关的,这也就以为着如果我们能够控制一个写命令执行完成后AOF写入磁盘的,那么这两个问题迎刃而解。

||日志的写回策略

AOF一共有三种写回策略,也就是AOF的配置项 appendfasyc 的三个可选值。

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

针对避免主线程堵塞和减少数据丢失的问题,这三种写回策略都无法做到两全其美。

配置项写回时机优点缺点
Always同步写回可靠性高,数据基本不丢失每个写命令都要落盘,性能影响较大
Everysec每秒写回性能适中宕机时丢失1秒内的数据
No由操作系统决定性能好宕机时丢失数据最多

我们可以根据性能和可靠性的要求,来选择使用哪种写回策略。

  • 想要高性能,选择No
  • 想要高可靠,选择Always
  • 允许一点数据丢失,有希望性能不受到太大的影响用Everysec

||日志的重写

  1. 重写的作用:AOF是以文件的形式记录所有写命令。随着写入的命令越来越多,AOF文件也就越来越大,从而导致性能问题。AOF重写主要在于一下三个方面:
    一:文件系统本身对文件大小有限制
    二:如果文件太大,之后再追加命令记录的话,效率会变低
    三:如果发生宕机,AOF记录的命令要一个个被重新执行用于故障恢复,如果日志文件太大,整个恢复过程会非常的缓慢,这会影响到Redis的正常使用。

AOF重写机制就是在重写时,Redis根据数据库的现状创建一个新的AOF文件,也就是说,在读取数据库中所有键值对的时候,用一条命令记录写入。重写机制具有“多变一”的功能,也就是说旧的日志文件中的多条命令,在重写后的新AOF日志中变成一条命令。
在这里插入图片描述
总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用子进程进行日志重写,所以,这个过程并不会阻塞主线程

正因为记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。这当然不是理想的结果。那么,还有没有既可以保证可靠性,还能在宕机时实现快速恢复的其他方法呢?

二、RDB

对于Redis来说,它实现了类似照片效果的方式,把某个时刻的状态以文件的形式写到磁盘,也就是快照(RDB文件)。这样一来即使宕机,快照文件也不会丢失,我们可以直接将RDB文件读入内存,很快的完成数据恢复。
Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。

  • save:在主线程中执行,会导致阻塞
  • bgsave创建一个子线程,专门用于写RDB文件,避免住线程的阻塞,这个也是Redis RDB的默认配置。

我们可以bgsave命令来执行全量 快照,这既提供了数据的可靠性保证,也避免了对Redis性能的影响。

这样既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。

三、混合AOF/RDB

虽然bgsave不阻塞主线程,但是如果频繁的进行全量快照会带来两部分的开销:

  • 频繁的将全量数据写入磁盘会给磁盘带来很大的压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。(所以在Redis中如果有一个bgsave线程运行,就不会再启动第二个子进程)。
  • bgsave需要fork主线程,虽然在子线程在创建之后不会再阻塞主线程,但是fork这个操作本身就会阻塞主线程,而且主线程内存越大,阻塞时间越长
    Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作 。这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

总结

最后,关于 AOF 和 RDB 的选择问题:

  • 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择
  • 如果允许分钟级别的数据丢失,可以只使用 RDB;
  • 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉霍拉卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值