- 前言
- 什么是AOF?
- 三种写回策略
- 日志文件太大怎么办?
- AOF重写会阻塞主线程吗?
- AOF的缺点
- 总结
- 什么是RDB?
- 给哪些数据做快照?
- 快照时能够修改数据吗?
- 多久做一次快照?
- 增量快照
- AOF和RDB混合使用
- 总结
- 总结
Redis
作为内存型的数据库,虽然很快,依然有着很大的隐患,一旦 「 服务器宕机」重启,内存中数据还会存在吗?
很容易想到的一个方案是从后台数据恢复这些数据,如果数据量很小,这倒是一个可行的方案。但是如果数据量过大,频繁的从后台数据库访问数据,压力很大;另外一方面恢复数据的时间极慢。
对于 Redis
来说,实现数据的持久化和快速恢复是至关重要。
今天这篇文章就来介绍一下 Redis
持久化的两种机制 AOF
日志、 RDB
快照。
什么是 AOF 日志?
AOF
(Append Only File
)日志称之为 「 写后日志」,即是命令先执行完成,把数据写入内存,然后才会记录日志。
AOF
日志(文本形式)会将收到每一条的命令且执行成功的命令以一定的格式写入到文本中(追加的方式)。
「 写后日志有什么好处呢?」 如下:
但是 AOF
日志也有 「 潜在的风险」,分析如下:
为了解决上面的风险, AOF
日志提供了三种回写策略。
AOF
机制提供了三种回写策略,这些都在 appendfsync
配置,如下:
其实这三中写回策略都无法解决主线程的阻塞和数据丢失的问题,分析如下:
以上三种策略优缺点总结如下表:
随着数据量的增大,AOF日志文件难免会很大,这样将会导致写入和恢复数据都将变得非常慢。此时AOF提供了一种 「 重写机制」解决这一问题。
❝重写机制理解起来很简单,即是
Redis
会创建一个新的AOF
日志文件,将每个键值对最终的值用一条命令写入日志文件中。
❞
比如读取了键值对 key1:value1
,重写机制会在新的AOF日志文件中记录如下一条命令:
set key1 value1
其实即是记录多次修改的最终的值记录在新的AOF日志文件中,这样当恢复数据时可直接执行该命令。
「 为什么重写机制能够缩小文件呢?」 当一个键值被多次修改后, AOF
日志文件中将会记录多次修改键值的命令,重写机制是根据这个键值最新状态为它生成 「 写入」命令,这样旧文件中的 「 多条」命令在重写后的新日志中变成了 「 一条」命令。
作者画了一张重写流程图,仅供参考,如下:
AOF重写虽然能够缩减日志文件的大小,达到减少日志记录和数据恢复的时间,但是在数据量非常的大情况下把整个数据库重写后的日志写入磁盘是一个非常耗时的过程,难道不会阻塞主线程吗?
「 答案是:不会阻塞主线程」; 因为AOF重写过程是由后台子进程 bgrewriteaof
来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
其实重写的过程分为两个阶段: 「 一个拷贝,两处日志」。
「 一个拷贝」:指每次执行重写时,主线程都 fork
一个子线程 bgrewriteaof
,主线程会把内存数据拷贝一份到子线程,此时子线程中包含了数据库的最新数据。然后子线程就能在不影响主线程的情况下进行AOF重写了。
「 两处日志」是什么?如下:
虽说进行了日志重写后,AOF日志文件会缩减很多,但是在数据恢复过程中仍然是一条命令一条命令(由于单线程,只能顺序执行)的执行恢复数据,这个恢复的过程非常缓慢。
AOF这种通过逐一记录操作命令的日志方式,提供了三种写回策略保证数据的可靠性,分别是 Always
、 Everysec
和 No
,这三种策略在可靠性上是从高到低,而在性能上则是从低到高。
为了避免日志文件过大,Redis提供了重写的机制,每次重写都fork一个子线程,拷贝内存数据进行重写,将多条命令缩减成一条生成键值对的命令,最终重写的日志作为新的日志。
什么是RDB?
RDB
(Redis DataBase)是另外一种持久化方式:内存快照。
❝
RDB
记录的是 「 某一个时刻」的内存数据,并不是操作命令。
❞
这种方式类似于拍照,只保留某一时刻的形象。内存快照是将某一时刻的状态以文件的形式写入磁盘。这样即使宕机了,数据也不会丢失,这个快照文件就称为 RDB
文件。
❝由于记录的是某个时刻的内存数据,数据恢复非常快的,不需要像AOF日志逐一执行记录的命令。
❞
为了保证数据的可靠性,Redis执行的 「 全量快照」,也就是把内存中的所有数据都写到磁盘中。
随着数据量的增大,一次性把全部数据都写到磁盘中势必会造成线程阻塞,这就关系到Redis的性能了。
针对线程阻塞的问题Redis提供了两个命令,如下:
这样就可以使用 bgsave
命令执行全量快照,既可以保证数据的可靠性也避免了主线程的阻塞。
子线程执行全量快照的同时,主线程仍然在接受着请求,读数据肯定没有问题,但是如果个修改了数据,如何能够保证快照的完整性呢?
「 举个栗子」:我在 T
时刻进行全量快照,假设数据量有 8G
,写入磁盘的过程至少需要 20S
,在这 20S
的时间内,一旦内存中的数据发生了修改,则快照的完整性就破坏了。
但是如果在快照时不能修改数据,则对Redis的性能有巨大的影响,对于这个问题,Redis是如何解决的呢?
❝
Redis
借助操作系统提供的写时复制技术
(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
❞
其实很简单, bgsave
命令会 fork
一个子线程,这个子线程共享所有内存的数据,子线程会读取主线程内存中的数据,将他们写入 RDB
文件。
如上图,对于 键值对A
的读取并不会影响子线程,但是如果主线程一旦修改内存中一块数据(例如 键值对D
),这块数据将会被复制一个副本,然后 bgsave
子线程会将其写入 RDB
文件。
快照只是记录某一时刻的数据,一旦时间隔离很久,则服务器一旦宕机,则会丢失那段时间的数据。
比如在 T1
时间做了一次快照,在 T1+t
时又做了一次快照,如果在 t
这个时间段内服务器突然宕机了,则快照中只保存了 T1
时刻的快照,在 t
时间段内的数据修改未被记录(丢失)。如下图:
从上图明显可以看出, 「 RDB
并不是一个完美的日志记录方案」,只有让 t
时间逐渐缩小,才能保证丢失的数据缩小。
「 那么问题来了,时间能够缩短 1秒
吗?」 即是每秒执行一次快照。
❝全量快照是记录某一个时刻的 「 全部」内存数据,每秒执行一次的对Redis性能影响巨大,于是 「 增量快照」就出来了。
❞
「 增量快照是指做了一次全量快照之后,后续的快照只对修改的数据进行快照记录」,这样可以避免每次都全量快照的开销。
增量快照的前提是Redis能够记住修改的数据,这个功能其实开销也是巨大的,需要保存完整的键值对,这对内存的消耗是巨大的。
❝为了解决这个问题,Redis使用了
AOF
和RDB
混合使用的方式。
❞
这个概念是在 Redis4.0
提出的,简单的说就是 「 内存快照以一定的频率执行,比如1小时一次,在两次快照之间,使用AOF日志记录这期间的所有命令操作。」
❝混合使用的方式使得内存快照不必频繁的执行,并且AOF记录的也不是全部的操作命令,而是两次快照之间的操作命令,不会出现AOF日志文件过大的情况了,避免了AOF重写的开销了。
❞
这个方案既能够用到的RDB的快速恢复的好处,又能享受都只记录操作命令的简单优势,强烈建议使用。
RDB
内存快照记录的是某一个时刻的内存数据,因此能够快速恢复; AOF
和 RDB
混合使用能够使得宕机后数据快速恢复,又能够避免 AOF
日志文件过大。
本文介绍了两种数据恢复和持久化的方案,分别是 AOF
和 RDB
。
AOF
介绍了什么?如下:
RDB
介绍了什么?如下:
Original: https://www.cnblogs.com/Chenjiabing/p/14029943.html
Author: 爱撒谎的男孩
Title: 宕机了,Redis数据丢了怎么办?
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/711445/
转载文章受原作者版权保护。转载请注明原作者出处!