共计 11937 个字符,预计需要花费 30 分钟才能阅读完成。
如何进行 Redis 持久化 RDB 和 AOF 的分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
Redis 持久化方案
Redis 是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将 Redis 中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次 Redis 重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。
Redis 提供了多种不同级别的持久化方式:一种是 RDB,另一种是 AOF。
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot),将数据库的快照(snapshot)以二进制的方式保存到磁盘中。
AOF 持久化记录服务器执行的所有更改操作命令,AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。
Redis 可以同时使用 AOF 持久化和 RDB 持久化。在这种情况下,当 Redis 重启时,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存在。
了解 RDB 持久化和 AOF 持久化之间的异同是非常重要的,以下几个小节将详细地介绍这这两种持久化功能,并对它们的相同和不同之处进行说明。
RDB 快照
下面我们说一下 Redis 的第一个持久化策略,RDB 快照。Redis 支持将当前内存数据的快照存成一个数据文件的持久化机制,而一个持续写入的数据库如何生成快照呢?Redis 巧妙地借助了 fork 命令的写时复制(copy on write)机制,将当前进程 fork 出一个子进程,子进程根据内存快照,循环将数据持久化为 RDB 文件。
在默认情况下,Redis 将数据库快照保存在根目录下,名字为 dump.rdb 的二进制文件中。可通过参数 dir 配置指定保存目录,dbfilename 指定文件名。你可以对 Redis 进行设置,如“save N M”,表示 N 秒内数据项中有 M 个改动时这一条件被满足时,自动保存一次数据集。比如你可以配置当 10 分钟以内有 100 次写入就生成快照,也可以配置当 1 分钟内有 1000 次写入就生成快照,支持可以多个规则一起生效,当匹配到哪个就哪个规则生效。这些规则的定义就在 Redis 的配置文件中,你也可以通过 Redis 的 CONFIG SET 命令在 Redis 运行时设置规则,不需要重启 Redis。
比如说,以下设置会让 Redis 在满足“60 秒内有至少有 1000 个键被改动”这一条件时,自动保存一次数据集:
save 60 1000
你也可以通过调用 SAVE 或者 BGSAVE,手动让 Redis 进行数据集保存操作。SAVE 命令执行一个同步操作,以 RDB 文件的方式保存所有数据的快照,很少在生产环境直接使用 SAVE 命令,因为它会阻塞所有的客户端的请求,不要在生产环境使用,可以使用 BGSAVE 命令代替。BGSAVE 命令执行过程中是通过 fork 一个子进程来完成的,所以不会阻塞客户端请求,只有 fork 子进程时会阻塞服务器。另外,在自动触发 RDB 持久化时,Redis 也会选择 BGSAVE 而不是 SAVE 来进行持久化。
Redis 自动 RDB 持久化在其内部是通过 serverCron 周期性操作函数、dirty 计数器、和 lastsave 时间戳来实现的。其中 serverCron 每 100ms 执行一次,检查服务器状态,其中就包括检查“save N M”是否满足条件,如果满足就执行 BGSAVE;当然也包括 AOF 重写检查。dirty 计数器是 Redis 服务器维持的一个状态,记录了上一次执行 BGSAVE/SAVE 命令后,服务器状态进行了多少次修改(包括增删改),而当 BGSAVE/SAVE 执行完成后,会将 dirty 重新置为 0。lastsave 时间戳也是 Redis 服务器维持的一个状态,记录的是上一次成功执行 BGSAVE/SAVE 的时间,当前时间减去 lastsave 需满足 M。
除了手动和自动以外,还有一些其他情况会触发 BGSAVE:
在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行 BGSAVE 命令,并将 rdb 文件发送给从节点。
执行 shutdown 命令时,自动执行 rdb 持久化。
另外需要了解的,因为其写操作是在一个新进程中进行的,当生成一个新的 RDB 文件时,Redis 生成的子进程会先将数据写到一个临时文件中,然后通过原子性 rename 系统调用将临时文件重命名为 RDB 文件,这样在任何时候出现故障,Redis 的 RDB 文件都总是可用的。
这种持久化方式被称为快照(snapshot)。但是,我们可以很明显的看到,RDB 有他的不足,就是一旦数据库出现问题,那么我们的 RDB 文件中保存的数据并不是全新的,从上次 RDB 文件生成到 Redis 停机这段时间的数据全部丢掉了。在某些业务下,如果可以忍受间隔内数据丢失,我们也推荐这些业务使用 RDB 的方式进行持久化,因为开启 RDB 的代价并不高。但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB 就无能为力了,所以 Redis 引入了另一个重要的持久化机制,AOF 日志方式持久化。
为了尽可能使 RDB 文件体积减小,Redis 默认采用 LZF 算法对 RDB 文件进行压缩。虽然压缩耗时,但是可以大大减小 RDB 文件的体积,因此压缩默认开启,参数为 rdbcompression。需要注意的是,RDB 文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度 (20 字节) 时才会进行。
除了压缩,你也可以检验 RDB 文件,通过参数 rdbchecksum 设置,默认为 yes。在写入文件和读取文件时都起作用,关闭 checksum 在写入文件和启动文件时大约能带来 10% 的性能提升,但是数据损坏时无法发现。
另外,当 bgsave 出现错误时,Redis 是否停止执行写命令。Redis 提供了一个参数 stop-writes-on-bgsave-error,设置为 yes,则当硬盘出现问题时,可以及时发现,避免数据的大量丢失;设置为 no,则 Redis 无视 bgsave 的错误继续执行写命令,当对 Redis 服务器的系统 (尤其是硬盘) 使用了监控时,该选项考虑设置为 no。
说说 FORK 的开销?
父进程通过 fork 操作可以创建子进程,第一代 Unix 系统实现了一种傻瓜式的进程创建:当执行 fork 系统调用时,内核复制父进程的整个用户空间并把复制得到的那一份分配给子进程。这种行为时非常耗时的,因为它需要完成以下几项任务:为子进程的页表分配页面、为子进程的页分配页面、初始化子进程的页表、把父进程的页复制到子进程对应的页中。
现在
Linux
的 fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候。所以就算 fork 很大内存的进程,对内存的消耗和耗时都很小。
现在虽然 fork 时,子进程不会复制父进程的数据空间,但是会复制内存页表(页表相当于内存的索引、目录);父进程的数据空间越大,内存页表越大,fork 时复制耗时也会越多。这个问题也是导致 Redis 内存不宜过大的原因之一,当然还有导致故障恢复时间延长也是 Redis 内存不宜过大的原因。
AOF 日志
通过上面的分析,我们知道 RDB 快照有大概率丢失最近写入、且仍未保存到快照中的那些数据。尽管对于某些程序来说,数据安全并不是最重要的考虑因素,但是对于那些追求数据安全的程序来说,快照功能就不太适用了。从 1.1 版本开始,Redis 增加了一种实时性更好的持久化方式,即 AOF 持久化。AOF 日志的全称是 append only file,从名字上我们就能看出来,它是一个追加写入的日志文件。与 RDB 相比,AOF 的实时性更好,因此已成为主流的持久化方案。
AOF 文件与 MySQL 数据库的 binlog 不同的是,AOF 是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点,它记录的内容就是一个个的 Redis 标准命令。开启 AOF 持久化命令如下:
appendonly yes
appendfilename appendonly.aof
从现在开始,每当 Redis 执行一个改变数据集的命令时(比如 SET),这个命令就会被追加到 AOF 文件的末尾。这样的话,当 Redis 重新启时,程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。
由于需要记录 Redis 的每条写命令,因此 AOF 不需要触发,下面介绍 AOF 的执行流程:
命令追加(append)
Redis 先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘 IO 成为 Redis 负载的瓶颈。
文件写入(write)和文件同步(sync)
Redis 提供了多种 AOF 缓存区的同步文件策略,策略涉及到操作系统的 write 函数和 fsync 函数,说明如下:
为了提高文件写入效率,在现代操作系统中,当用户调用 write 函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了 fsync、fdatasync 等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。
AOF 缓存区的同步文件策略由参数 appendfsync 控制,各个值的含义如下:
always:命令写入 aof_buf 后立即调用系统 fsync 操作同步到 AOF 文件,fsync 完成后线程返回。这种情况下,每次有写命令都要同步到 AOF 文件,硬盘 IO 成为性能瓶颈,Redis 只能支持大约几百 TPS 写入,严重降低了 Redis 的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低 SSD 的寿命。
no:命令写入 aof_buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步;同步由操作系统负责,通常同步周期为 30 秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
everysec:命令写入 aof_buf 后调用系统 write 操作,write 完成后线程返回;fsync 同步文件操作由专门的线程每秒调用一次。everysec 是前述两种策略的折中,是性能和数据安全性的平衡,因此是 Redis 的默认配置,也是我们推荐的配置。
文件重写(rewrite)
因为 AOF 的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加,AOF 文件的体积也会变得越来越大。举个例子,如果你对一个计数器调用了 100 次 INCR,那么仅仅是为了保存这个计数器的当前值,AOF 文件就需要使用 100 条记录(entry)。然而在实际上,只使用一条 SET 命令已经足以保存计数器的当前值了,其余 99 条记录实际上都是多余的。另外还有一些过期的数据,无效的数据也都是可以去除。
过大的 AOF 文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。为了处理这种情况,Redis 支持一种有趣的特性,可以在不打断服务客户端的情况下,对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令,Redis 将生成一个新的 AOF 文件,这个文件包含重建当前数据集所需的最少命令。
AOF REWRITE(重写)生成过程和 RDB 快照类似,都巧妙地利用了写时复制机制。同样也是 fork 一个子进程(此时主线程是阻塞的),子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件。当主进程 fork 完子线程后继续接受请求,所有写命令依然写入 AOF 缓冲区(aof_buf),并根据 appendfsync 策略同步到硬盘,保证原有 AOF 机制的正确。但由于 fork 操作使用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然在响应命令,因此 Redis 使用 AOF 重写缓冲区(aof_rewrite_buf)保存这部分新日志,防止新 AOF 文件生成期间丢失这部分数据。也就是说,bgrewriteaof 执行期间,Redis 的写命令同时追加到 aof_buf 和 aof_rewirte_buf 两个缓冲区。
当子进程写完新的 AOF 文件后,向父进程发信号,父进程更新统计信息,具体可以通过 info persistence 查看。然后父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件,这样就保证了新 AOF 文件所保存的数据库状态和服务器当前状态一致。然后调用原子性的 rename 命令用新的 AOF 文件取代老的 AOF 文件,完成 AOF 重写。
这里需要注意,因为由主进程把 aof_rewrite_buf 缓存追加到新日志文件。主进程追加日志时,不会处理其他请求,如果 aof_rewrite_buf 特别大,例如几百 M,也可能造成 Redis 几秒甚至几十秒不响应。
从上面的流程我们能够看到,RDB 和 AOF 操作都是顺序 IO 操作,性能都很高。而在通过 RDB 文件或者 AOF 日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读。
文件重写的触发,分为手动触发和自动触发:
手动触发:直接调用 bgrewriteaof 命令,该命令的执行与 bgsave 有些类似:都是 fork 子进程进行具体的工作,且都只有在 fork 时阻塞。
自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数,以及 aof_current_size 和 aof_base_size 状态确定触发时机。
auto-aof-rewrite-min-size 表示执行 AOF 重写时,文件的最小体积,默认值为 64MB。
auto-aof-rewrite-percentage 表示执行 AOF 重写时,当前 AOF 大小(即 aof_current_size)和上一次重写时 AOF 大小(aof_base_size)的比值,即增长比例达到设定值。
只有当 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 两个参数同时满足时,才会自动触发 AOF 重写,即 bgrewriteaof 操作。
其中,参数可以通过 config get 命令查看:
127.0.0.1:6391 CONFIG GET auto-aof-rewrite-min-size
1) auto-aof-rewrite-min-size
2) 64000000
127.0.0.1:6391 CONFIG GET auto-aof-rewrite-percentage
1) auto-aof-rewrite-percentage
2) 100
状态可以通过 info persistence 查看:
127.0.0.1:6379 info persistence
# Persistence
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_current_size:40876638
aof_base_size:2217565
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
另外在 aof rewrite 过程中,是否采取增量”文件同步”策略,由参数 aof-rewrite-incremental-fsync 控制,默认为”yes”,而且必须为 yes。rewrite 过程中,每 32M 数据进行一次文件同步,这样可以减少”aof 大文件”写入对磁盘的操作次数。
bgrewriteaof 机制,在一个子进程中进行 aof 的重写,从而不阻塞主进程对其余命令的处理,同时解决了 aof 文件过大问题。现在问题出现了,同时在执行 bgrewriteaof 操作和主进程写 aof 文件的操作,两者都会操作磁盘,而 bgrewriteaof 往往会涉及大量磁盘操作,这样就会造成主进程在写 aof 文件的时候出现阻塞的情形,现在 no-appendfsync-on-rewrite 参数出场了。
如果该参数设置为 no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为 yes 呢?这就相当于将 appendfsync 设置为 no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候 Redis 挂掉,就会丢失数据。丢失多少数据呢?在 Linux 的操作系统的默认设置下,最多会丢失 30s 的数据。因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为 yes。如果应用系统无法忍受数据丢失,则设置为 no。
AOF 刷新策略?
前面提到过,在 AOF 中,如果 AOF 缓冲区的文件同步策略为 everysec,则:在主线程中,命令写入 aof_buf 后调用系统 write 操作,write 完成后主线程返回;fsync 同步文件操作由专门的文件同步线程每秒调用一次。这种做法的问题在于,如果硬盘负载过高,那么 fsync 操作可能会超过 1s;如果 Redis 主线程持续高速向 aof_buf 写入命令,硬盘的负载可能会越来越大,IO 资源消耗更快;如果此时 Redis 进程异常退出,丢失的数据也会越来越多,可能远超过 1s。
为此,Redis 的处理策略是这样的:主线程每次进行 AOF 会对比上次 fsync 成功的时间;如果距上次不到 2s(也就是延迟了 1s),主线程直接返回;如果超过 2s,则主线程阻塞直到上一次 fsync 同步完成。因此,如果系统硬盘负载过大导致 fsync 速度太慢,会导致 Redis 主线程的阻塞;此外,使用 everysec 配置,AOF 最多可能丢失 2s 的数据,而不是 1s。具体看 Redis AOF 刷新策略分析
AOF 追加阻塞问题定位的方法,监控 info Persistence 中的 aof_delayed_fsync,当 AOF 追加阻塞发生时(即主线程等待 fsync 而阻塞),该指标累加。另外,AOF 阻塞时的 Redis 日志:Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.
如果 AOF 追加阻塞频繁发生,说明系统的硬盘负载太大;可以考虑更换 IO 速度更快的硬盘,或者通过 IO 监控分析工具对系统的 IO 负载进行分析。
对于 pipelining 有什么不同?
对于 pipelining 的操作,其具体过程是客户端一次性发送 N 个命令,然后等待这 N 个命令的返回结果被一起返回。通过采用 pipilining 就意味着放弃了对每一个命令的返回值确认。由于在这种情况下,N 个命令是在同一个执行过程中执行的。所以当设置 appendfsync 为 everysec 时,可能会有一些偏差,因为这 N 个命令可能执行时间超过 1 秒甚至 2 秒。但是可以保证的是,最长时间不会超过这 N 个命令的执行时间和。
如果 AOF 文件出错了,怎么办?
服务器可能在程序正在对 AOF 文件进行写入时停机,如果停机造成了 AOF 文件出错(corrupt),那么 Redis 在重启时会拒绝载入这个 AOF 文件,从而确保数据的一致性不会被破坏。当发生这种情况时,可以用以下方法来修复出错的 AOF 文件:为现有的 AOF 文件创建一个备份。然后使用 Redis 附带的 redis-check-aof –fix 程序对原来的 AOF 文件进行修复。
然后可选使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。再次重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。
但如果是 AOF 文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且 aof-load-truncated 参数开启,则日志中会输出警告,Redis 忽略掉 AOF 文件的尾部,启动成功。aof-load-truncated 参数默认是开启的。
RDB 和 AOF 优缺点
RDB 的优点?
RDB 是一个非常紧凑(compact)的文件,体积小,网络传输快,它保存了 Redis 在某个时间点上的数据集。这种文件非常适合用于进行备份,恢复速度比 AOF 快很多。当然,与 AOF 相比,RDB 最重要的优点之一是对性能的影响相对较小。父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
RDB 的缺点?
RDB 文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此 AOF 持久化成为主流。此外,RDB 文件需要满足特定格式,兼容性差(如老版本的 Redis 不兼容新版本的 RDB 文件)。
AOF 的优点?
与 RDB 持久化相对应,AOF 的优点在于支持秒级持久化、兼容性好。你可以设置不同的 fsync 策略,比如无 fsync,每秒钟一次 fsync,或者每次执行写入命令时 fsync。AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据。AOF 文件是一个只进行追加操作的日志文件(append only log),因此对 AOF 文件的写入不需要进行 seek(查找),即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等),redis-check-aof 工具也可以轻易地修复这种问题。
Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写:重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。AOF 文件有序地保存了对数据库执行的所有写入操作,这些写入操作以 Redis 协议的格式保存,因此 AOF 文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF 文件也非常简单:举个例子,如果你不小心执行了 FLUSHALL 命令,但只要 AOF 文件未被重写,那么只要停止服务器,移除 AOF 文件末尾的 FLUSHALL 命令,并重启 Redis,就可以将数据集恢复到 FLUSHALL 执行之前的状态。
AOF 的缺点?
AOF 文件的体积通常要大于 RDB 文件的体积、且恢复速度慢。对于相同的数据集来说,根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。在一般情况下,每秒 fsync 的性能依然非常高,而关闭 fsync 可以让 AOF 的速度和 RDB 一样快。另外,AOF 在过去曾经发生过这样的 bug,因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。虽然这种 bug 在 AOF 文件中并不常见,但是对比来说,RDB 几乎是不可能出现这种 bug 的。
RDB 和 AOF,我应该用哪一个?
首先要明白无论是 RDB 还是 AOF,持久化的开启都是要付出性能方面代价的:对于 RDB 持久化,一方面是 bgsave 在进行 fork 操作时 Redis 主进程会阻塞,另一方面,子进程向硬盘写数据也会带来 IO 压力。但如果业务能容忍几分钟到 10 几分钟的数据丢失(且不使用备库),RDB 是一个不错的选择;不然,就选择 AOF。
对于 AOF 持久化,向硬盘写数据的频率大大提高(everysec 策略下为秒级),IO 压力更大,甚至可能造成 AOF 追加阻塞问题(后面会详细介绍这种阻塞),此外,AOF 文件的重写与 RDB 的 bgsave 类似,会有 fork 时的阻塞和子进程的 IO 压力问题。相对来说,由于 AOF 向硬盘中写数据的频率更高,因此对 Redis 主进程性能的影响会更大。
在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用 RDB 或 AOF 的一种,或同时开启 RDB 和 AOF 持久化等。此外,持久化的选择必须与 Redis 的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机 master 和从机 slave 可以独立的选择持久化方案。比如完全关闭 master 持久化(包括 RDB 和 AOF),这样可以让 master 的性能达到最好;而 slave 可以只开启 AOF。但这种情况下,如果 master 服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将 master 自动重启,由于没有持久化文件,那么 master 重启后数据是空的,slave 同步数据也变成了空的,意味着数据丢失。所以尽量避免这种情况出现。
RDB 和 AOF 之间的相互作用?
在版本号大于等于 2.4 的 Redis 中,BGSAVE 执行的过程中,不可以执行 BGREWRITEAOF。反过来说,在 BGREWRITEAOF 执行的过程中,也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I / O 操作。
如果 BGSAVE 正在执行,并且用户显示地调用 BGREWRITEAOF 命令,那么服务器将向用户回复一个 OK 状态,并告知用户,BGREWRITEAOF 已经被预定执行:一旦 BGSAVE 执行完毕,BGREWRITEAOF 就会正式开始。当 Redis 启动时,如果 RDB 持久化和 AOF 持久化都被打开了,那么程序会优先使用 AOF 文件来恢复数据集,因为 AOF 文件所保存的数据通常是最完整的。
RDB 和 AOF 数据导入
这些持久化的数据有什么用,当然是用于重启后的数据恢复。Redis 是一个内存数据库,无论是 RDB 还是 AOF,都只是其保证数据恢复的措施。所以 Redis 在利用 RDB 或 AOF 进行恢复的时候,会读取 RDB 或 AOF 文件,重新加载到内存中。相对于 MySQL 等数据库的启动时间来说,会长很多,因为 MySQL 本来是不需要将数据加载到内存中的。
但是相对来说,MySQL 启动后提供服务时,其被访问的热数据也会慢慢加载到内存中,通常我们称之为预热,而在预热完成前,其性能都不会太高。而 Redis 的好处是一次性将数据加载到内存中,一次性预热。这样只要 Redis 启动完成,那么其提供服务的速度都是非常快的。
而在利用 RDB 和利用 AOF 启动上,其启动时间有一些差别。RDB 的启动时间会更短,原因有两个,一是 RDB 文件中每一条数据只有一条记录,不会像 AOF 日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是 RDB 文件的存储格式和 Redis 数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在 CPU 消耗上要远小于 AOF 日志的加载。
注意:当 redis 启动时,如果 rdb 持久化和 aof 持久化都打开了,那么程序会优先使用 aof 方式来恢复数据集,因为 aof 方式所保存的数据通常是最完整的。如果 aof 文件丢失了,则启动之后数据库内容为空。
注意:如果想把正在运行的 redis 数据库,从 RDB 切换到 AOF,建议先使用动态切换方式,再修改配置文件,重启数据库。(不能直接修改配置文件,重启数据库,否则数据库中数据就为空了。)
在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF:
为最新的 dump.rdb 文件创建一个备份,将备份放到一个安全的地方。执行以下两条命令:
127.0.0.1:6379 CONFIG SET dir /apps/redis/data/redis-8836
127.0.0.1:6379 CONFIG SET appendonly yes
127.0.0.1:6379 CONFIG SET save
确保命令执行之后,数据库的键的数量没有改变。确保写命令会被正确地追加到 AOF 文件的末尾。
步骤 2 是开启了 AOF 功能,Redis 会阻塞直到初始 AOF 文件创建完成为止,之后 Redis 会继续处理命令请求,并开始将写入命令追加到 AOF 文件末尾。
步骤 3 用于关闭 RDB 功能,这一步是可选的,如果你愿意的话,也可以同时使用 RDB 和 AOF 这两种持久化功能。
看完上述内容,你们掌握如何进行 Redis 持久化 RDB 和 AOF 的分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!