持久化策略
Redis 提供了两种持久化策略
RDB (Redis Database Snapshot)
持久化机制,会在一段时间内生成指定时间点的数据集快照(snapshot)AOF(Append Only File)
持久化机制,记录 server 端收到的每一条写命令,当 server 重启时会进行重放以此来重建之前的数据集。AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加(append) 到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite) ,使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。- 如果你仅使用 Redis 作为缓存加速访问,你可以关闭这两个持久化设置
- 你也可以同时开启这两个持久化设置,但是在这种情况下,Redis 重启时会使用 AOF 文件来重建数据集,因为 AOF 文件保存的数据往往更加完整。
RDB:Redis的时间胶囊
RDB的基本特性
RDB(Redis Database Backup) 是Redis的一种持久性数据快照机制,它允许将Redis内存中的数据定期保存到磁盘上的二进制文件中。RDB文件包含了数据库在某个时间点的完整快照,包括所有的键值对、数据结构和元数据。这个机制的主要用途是在Redis服务器宕机后,能够通过加载RDB文件来恢复数据,以确保数据的持久性和可恢复性。
以下是RDB的一些关键特点:
-
全量快照:RDB执行的是全量快照,即将内存中的所有数据都记录到磁盘上的RDB文件中,包括所有数据库、键值对、数据结构等。
-
非实时:RDB快照不是实时的,而是周期性地执行。你可以配置Redis以在特定时间间隔或在特定条件下生成RDB文件。这有助于降低磁盘I/O负载和提高性能。
-
生成RDB文件:Redis提供了两个主要的命令来生成RDB文件:
SAVE
:在主线程中执行,会导致Redis暂停对外提供服务,因为它会阻塞Redis的主线程,不推荐在生产环境中使用。BGSAVE
(后台保存):这是默认的RDB生成方式。它创建一个子进程,专门用于生成RDB文件,这样就不会影响Redis的主线程,允许Redis继续处理请求。
-
写时复制(Copy-On-Write,COW) :
bgsave
子进程是由主线程fork
生成的,可以共享主线程的所有内存数据。当主线程要修改某个数据时,该数据会被复制一份,生成一个数据副本。主线程在数据副本上进行修改,而bgsave
子进程可以继续将原始数据写入RDB文件。这保证了快照的完整性,同时允许主线程和子进程并发地对数据进行操作,而不会相互影响。
写时复制技术
bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C')。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
AOF:记录每个操作的日志
AOF的基本特性
Redis的AOF(Append-Only File)机制是一种持久化方式,用于记录数据库状态的变化,以确保数据持久性。AOF机制的主要原理是将每个写操作追加到AOF日志文件的末尾,从而记录了导致数据库状态变化的每个命令。
以下是Redis的AOF机制的主要特点和工作原理:
- 持久化方式:AOF是一种持久化方式,与Redis的另一种持久化方式RDB(Redis Database Snapshot)不同,它记录了每个写操作,而不是周期性地保存数据库的快照。
- 追加写入:AOF日志文件采用追加写入的方式,每个写操作都会以命令的形式被追加到AOF文件的末尾,这确保了AOF文件包含了导致数据库状态变化的每个命令。
- 可读性:AOF日志是以纯文本的形式记录的,易于阅读和理解。这也意味着AOF文件可以通过文本编辑器进行查看和编辑,使其成为一种可维护的数据恢复工具。
- 恢复机制:Redis可以使用AOF日志来完全恢复数据库的状态。当Redis启动时,它会重新执行AOF文件中的所有命令,以重建数据库的状态。这种方式可确保数据的持久性。
- 同步策略 :AOF文件的写入可以采用不同的同步策略。可以选择在每个写操作完成后立即将命令追加到AOF文件(
always
选项),或者在后台定期将多个写操作一起追加(everysec
选项)。everysec
选项在保持较好性能的同时提供了一定程度的数据安全性。 - AOF重写:AOF文件会随着时间的推移变得越来越大,因为它包含了历史上的所有写操作。为了解决这个问题,Redis引入了AOF重写机制。AOF重写是一个后台任务,它会创建一个新的AOF文件,其中只包含当前数据库状态的最小命令集。这个机制可以在不中断Redis服务的情况下减小AOF文件的体积,提高性能。
三种写回策略
AOF 机制给我们提供了三个选择,也就是 AOF 配置项 appendfsync
的三个可选值。
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
避免主线程阻塞和减少数据丢失问题,这三种写回策略都无法做到两全其美。
- "同步写回"可以做到基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,不可避免地会影响主线程性能;
- 虽然"操作系统控制的写回"在写完缓冲区后,就可以继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了;
- "每秒写回"采用一秒写回一次的频率,避免了"同步写回"的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。所以,这只能算是,在避免影响主线程性能和避免数据丢失两者间取了个折中。
三种写回策略对比如下:
总结一下就是:想要获得高性能,就选择 No 策略;如果想要得到高可靠性保证,就选择 Always 策略;如果允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择 Everysec 策略。
AOF重写机制
由于AOF日志随时间增长,可能包含大量冗余操作。为了解决这个问题,Redis引入了AOF重写机制,该机制通过后台子进程bgrewriteaof
执行,以避免阻塞主线程,保持数据库性能。
AOF重写过程可以概括为"一个拷贝,两处日志":
-
一个拷贝 :在AOF重写过程中,主线程会fork出后台子进程
bgrewriteaof
,将数据库的最新数据拷贝给这个子进程。子进程在拷贝的数据上执行写操作,生成一个新的AOF重写日志。 -
两处日志:
- 第一处日志是指正在使用的AOF日志,新的写操作会被写入这个AOF日志的缓冲区,即使宕机,这个AOF日志的操作仍然完整,可用于恢复。
- 第二处日志是指新的AOF重写日志,新的写操作也会被写入这个重写日志的缓冲区,以确保重写日志不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志中的最新操作也会被写入新的AOF文件,以保持数据库最新状态的记录。
最终,新的AOF文件可以用来替代旧文件,从而实现AOF文件的压缩和性能提升。这个机制确保了数据库的完整性和一致性,同时不会影响主线程的正常操作,使得Redis在高负载情况下也能够高效运行。
总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。
AOF的优点
- 比RDB可靠。你可以制定不同的 fsync 策略:no 、everysec 和 always 。默认是 everysec。这意味着你最多丢失一秒钟的数据。
- AOF日志文件是一个纯追加的文件。就算是遇到突然停电的情况,也不会出现日志的定位或者损坏问题。甚至如果因为某些原因(例如磁盘满了)命令只写了一半到日志文件里,我们也可以用 redis-check-aof 这个工具很简单的进行修复。
- 当AOF文件太大时,Redis 会自动在后台进行重写。重写很安全,因为重写是在一个新的文件上进行,同时 Redis 会继续往旧的文件追加数据。新文件上会写入能重建当前数据集的最小操作命令的集合。当新文件重写完,Redis 会把新旧文件进行切换,然后开始把数据写到新文件上。
- AOF 把操作命令以简单易懂的格式一条接一条的保存在文件里,很容易导出来用于恢复数据。例如我们不小心用 FLUSHALL 命令把所有数据刷掉了,只要文件没有被重写,我们可以把服务停掉,把最后那条命令删掉,然后重启服务,这样就能把被刷掉的数据恢复回来。
AOF 的缺点
- 在相同的数据集下,AOF 文件的大小一般会比 RDB 文件大。
- 在某些 fsync 策略下,AOF 的速度会比 RDB 慢。通常 fsync 设置为每秒一次就能获得比较高的性能,而在禁止 fsync 的情况下速度可以达到 RDB 的水平。
- 在过去曾经发现一些很罕见的BUG导致使用AOF重建的数据跟原数据不一致的问题。
aof与rdb对比
下面是Redis中AOF(Append-Only File)
和RDB(Redis Database Backup)
两种持久化机制的详细对比:
特性 | AOF | RDB |
---|---|---|
数据记录方式 | 以日志追加的方式记录每个写操作 | 全量数据快照 |
文件体积 | 通常比RDB文件更大,因为记录了每个写操作 | 通常比AOF文件更小,因为是快照 |
恢复速度 | 较慢,因为需要重新执行每个写操作 | 较快,因为只需加载RDB文件即可 |
可读性 | 相对较好,AOF文件包含了可读的日志记录 | 不容易人工读取,是二进制格式的数据快照 |
写入延迟 | 稍微高于RDB,因为需要追加写入到文件中 | 低,因为是后台生成,不会影响正常读写 |
恢复数据完整性 | 高,每个写操作都有日志记录 | 低,数据恢复到RDB生成时的状态 |
适用场景 | 需要更高的数据持久性和恢复能力 | 需要更快的数据恢复速度 |
恢复到指定时间点 | 较容易,可以通过AOF文件中的时间戳实现 | 不直接支持,需要基于时间来选择RDB文件 |
磁盘I/O负载 | 高,每次写操作都需要追加到AOF文件中 | 低,仅定期生成RDB文件 |
适用于大数据集 | 可能占用大量磁盘空间 | 更适用,可以定期生成轻量级的RDB文件 |
内存效率 | 相对较低,AOF文件通常较大 | 较高,RDB文件通常较小 |
备份频率 | 高,每个写操作都会写入AOF文件 | 低,根据配置的生成策略 |
混合模式
RDB的全量快照频率不易把握,导致可能会有较多的数据丢失,而AOF的频繁写入可能带来额外的开销。
Redis 4.0提出了混合持久化模式(可以通过配置项 aof-use-rdb-preamble 开启),结合了AOF和内存快照的优势。在此模式下,内存快照按照一定的频率执行,而在两次内存快照之间,所有命令操作都使用AOF日志记录。
工作原理
内存快照定期执行,而AOF日志只记录两次内存快照之间的操作。一旦新的内存快照生成,AOF日志就可以被清空,因为这些操作已经包含在新的快照中。这样可以降低RDB的频率,减轻对主线程的影响,同时避免AOF文件过大和重写的问题。
如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。
优势:
- 充分利用了RDB的快速恢复能力。
- 充分利用了AOF只记录操作命令的优势,避免AOF文件过大和重写的问题。
- 达到了"鱼和熊掌可以兼得"的效果,结合了两种持久化方式的优点。
Redis的混合持久化模式允许你在不牺牲数据完整性的情况下,以较小的开销实现快速恢复,这使得Redis在处理大量写入操作的同时能够高效地维护数据的一致性。