持久化策略
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机制的主要特点和工作原理:
1. 持久化方式:AOF是一种持久化方式,与Redis的另一种持久化方式RDB(Redis Database Snapshot)不同,它记录了每个写操作,而不是周期性地保存数据库的快照。
2. 追加写入:AOF日志文件采用追加写入的方式,每个写操作都会以命令的形式被追加到AOF文件的末尾,这确保了AOF文件包含了导致数据库状态变化的每个命令。
3. 可读性:AOF日志是以纯文本的形式记录的,易于阅读和理解。这也意味着AOF文件可以通过文本编辑器进行查看和编辑,使其成为一种可维护的数据恢复工具。
4. 恢复机制:Redis可以使用AOF日志来完全恢复数据库的状态。当Redis启动时,它会重新执行AOF文件中的所有命令,以重建数据库的状态。这种方式可确保数据的持久性。
5. 同步策略:AOF文件的写入可以采用不同的同步策略。可以选择在每个写操作完成后立即将命令追加到AOF文件(always
选项),或者在后台定期将多个写操作一起追加(everysec
选项)。everysec
选项在保持较好性能的同时提供了一定程度的数据安全性。
6. 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文件过大和重写的问题。
优势:
充分利用了RDB的快速恢复能力。
充分利用了AOF只记录操作命令的优势,避免AOF文件过大和重写的问题。
达到了“鱼和熊掌可以兼得”的效果,结合了两种持久化方式的优点。
Redis的混合持久化模式允许你在不牺牲数据完整性的情况下,以较小的开销实现快速恢复,这使得Redis在处理大量写入操作的同时能够高效地维护数据的一致性。