Redis RDB 和 AOF 持久化

前言

Redis 是内存数据库,一旦 Redis 进程因为某种原因发生退出,内存中的数据就会全部丢失,即使只是把 Redis 当做缓存使用,在高并发的情况下也可能引起 缓存雪崩影响系统正常运行。

为了解决这个问题,Redis 提供了两种持久化方式: RDB(Redis DataBase) AOF(Append Only File),它们可以将内存中的数据保存到磁盘,在 Redis 进程异常退出重启后,可以从磁盘里把数据重新读回到内存。

RDB 持久化

RDB 持久化是将 Redis 在某一时刻的数据集快照(内存快照)写入 RDB 文件,在 Redis 重启时,把 RDB 文件载入内存就可以完成数据的恢复。

此外,RDB 文件还可以用于数据备份、主从节点间的数据同步等。

触发机制

RDB 持久化有两种触发机制:使用指令手动触发通过 redis.conf 配置自动触发

手动触发

Redis 提供两个命令实现手动触发:save bgsave

  • save 命令 由主线程完成 RDB 持久化,在这个过程中,主线程不能处理读写请求,直到完成 RDB 持久化,所以线上一定要谨慎使用;
  • bgsave 命令 主线程会 fork 一个子进程来完成 RDB 文件的写入,这样也就避免了主线程的阻塞。

自动触发

除了手动触发,还可以通过配置文件来设定一定的触发条件,Redis 检测到条件满足后,会自动触发持久化。

自动触发执行过程和 bgsave 命令一样,也是 fork 一个子进程来完成文件写入。

save 900 1 # 900秒(15分钟)内有1个写入
save 300 10 # 300秒(5分钟)内有10个写入
save 60 10000 # 60秒(1分钟)内有10000个写入

save "" # 关闭 RDB 持久化  

RDB 文件生成

首先,主线程 fork 一个子进程,fork 采用操作系统的 写时复制技术,子进程只会拷贝主进程的 内存页表项,以后子进程生成 RDB 文件时通过内存映射可以找到真正的物理内存。

如果在生成 RDB 文件的过程中,主线程要修改数据,它需要先拷贝数据得到一份数据副本,然后修改该副本,而子进程继续使用原来的数据写入到 RDB 文件。

RDB 存在的问题

1、虽然通过 fork 子进程在 RDB 文件生成阶段不会影响主线程的正常读写,但是 fork 本身是需要耗时的,在 fork 执行时,主线程是会被阻塞的,内存数据越多,页表也越大,fork 耗时也就越久,而 RDB 持久化记录的是内存在某一时刻的全部数据,因此,这个耗时不可忽略。

2、因为采用 写时复制,主子进程共享内存数据。如果在文件生成过程中,主线程存在大量的写命令,此时,操作系统必须分配大量的内存用于保存数据副本,这样会加大内存的占用,如果超过系统物理内存,数据就会在磁盘和内存之间来回置换,影响性能。(如果没有开启 swap 机制,会直接 OOM 报错)。

3、从 1 和 2 可以看出来,RDB 持久化不宜执行的太频繁,但是如果 RDB 执行间隔时间太久,又会引发另一个问题:一旦发生 Redis 宕机,那在上一次生成 RDB 文件之后到宕机发生这一时刻之间的所有数据都会丢失。

AOF 持久化

AOF 日志

AOF 日志记录发生在写命令后,以 Redis 协议的格式 保存,采用追加的方式写入文件中。这句话有几个要点:

1、只有写命令才会产生 AOF 日志;

2、写日志发生在写命令之后,即先修改数据,然后再记录日志;

3、日志文件中记录的是 Redis 协议格式的写命令;

4、每执行一个写命令,都会产生一条日志记录追加到日志文件。

为什么要采用 写后日志,它有什么好处呢?

因为采用写后日志可以省去命令检查,也就是说如果命令有误,在执行命令时就会出错返回,不用记录日志。

如果采用写前日志,就需要先检查命令是否正确,这会带来一定的开销。

三种写回策略

在所有写文件的场景都要考虑到文件系统的内存缓存 page cache,应用程序调用 write() 函数一般都只是写到 page cache 中,而不是直接同步到磁盘,而程序一般都会提供一个同步磁盘的策略配置,它指的就是将 page cache 中的内容同步到磁盘的时机。

我么看下redis 提供的配置项 appendfsync

  • Always: 同步写回。写命令执行完,立即同步写到磁盘;​​​​​​​
  • Everysec:每秒写回。写命令执行完,将命令日志写入到 AOF 日志的 page cache,每隔一秒将缓存区中的数据写到磁盘;
  • No:redis 不控制写回,由操作系统决定。写命令执行完,将命令日志写入到 AOF 日志的 page cache,由操作系统决定何时将缓存区的数据写到磁盘

选择哪种策略要根据业务特点来决定。要求高性能且允许数据丢失就选择 No,要高可靠就选择 Always。

一般推荐 Everysec 策略,每秒将数据写回磁盘不会影响 Redis 性能,同时最多也只会丢失一秒的数据。

AOF 重写机制

随着写命令的不断执行,AOF 文件会变得越来越大,这会形成一定的问题:

1、文件系统本身对单个文件大小存在限制;

2、往大文件追加内容的效率较低;

3、在 Redis 进程重启时,要利用 AOF 日志文件恢复数据,日志文件越大,恢复时间就越长。

所以 Redis 实现了重写机制,它可以让 AOF 日志文件变小。那它是基于什么实现的呢?

先前说过,AOF 日志记录的是所有的写命令,那么某个 key 当前的值可能是经历过多个写命令之后形成的。

在重写的时候,Redis 会读取当前缓存中所有数据的最新状态,并用 一条命令 记录到 新的 AOF 日志文件中

比如 某个字符串键值 key = 10, 它是经历过多条命令之后最新的值,

那在重写的时候,我们只要记录一条 set key 10 即可。

AOF 重写过程

AOF 重写是将数据库当前数据的最新状态通过一条写命令来实现回放,这个过程是比较耗时的。为了避免阻塞主线程,Redis 会 fork 一个子进程来完成重写

在开始重写时,先 fork 一个子进程,子进程首先拷贝一份当前进程的 内存页表,此后再通过内存页表查询真实物理内存 将数据写到 新的日志文件

在重写过程中,当前进程不会阻塞,可以正常接收读写请求,为了不丢失最新的数据,对于所有的写命令,Redis 要把这个写命令记录一份到 旧的 AOF 日志文件,同时还要记录一份到 重写日志缓冲区,在子进程将拷贝的数据都写入新的 AOF 日志文件后,重写日志缓冲区里的内容也要写入到新的 AOF 日志文件,最后用新的 AOF 日志文件替换旧的文件。

AOF 重写为什么要写一个新的日志文件?

因为两个进程同写一个文件会存竞争问题,影响性能,而且,如果 AOF 重写过程失败,如果复用原来的日志文件,那这个文件也已经被污染变的不可用。

AOF 重写在哪几个时刻会阻塞主线程?

1、fork 子进程时需要拷贝内存页表,此时会阻塞主线程;

2、fork 使用写时复制技术,在主线程执行写命令时需要拷贝内存数据,也会阻塞主线程;

3、子进程完成拷贝数据的重写后,要将 AOF 重写缓冲区的数据也追加到新的AOF 日志文件,此时也会阻塞主线程。

小结

不管是 RDB 持久化 还是 AOF 持久化,虽然他们在生成文件的时候都不会阻塞主线程,但是他们都包含一个 fork 子进程的动作,而执行这个动作的时候进程必然是阻塞的,阻塞时间由 fork 时间决定,fork 子进程需要拷贝主进程的内存页表,内存越大,页表越大,fork 耗时也就越久,主线程被阻塞的时间就越久,因此,Redis 单个实例内存都不要搞的太大

此外,fork 子进程采用写时复制技术,在主线程执行写命令时,父进程要重新分配内存空间来保存数据副本。对于 bigkey 的修改,需要重新申请大量的内存,这不仅会增加主线程的阻塞时间,严重时还可能导致内存使用超出物理内存大小,因此一定要尽量减少 bigKey 的存在。

知识扩展

写时复制

写时复制(英语:Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者(callers)同时要求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。

在 Linux 程序中,fork 调用会产生一个和父进程完全相同的子进程,但大多时候子进程在此后会执行 exec 系统调用,出于效率考虑,linux中引入了 写时复制 技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

fork 这里不深入讨论,下次再写,夜已深,不卷了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RedisRDBAOF是两种不同的持久化机制。RDB全称Redis Database Backup file,它是将内存中的所有数据记录在磁盘上的快照文件。当Redis实例故障重启后,可以从磁盘中的RDB文件读取数据来进行恢复。RDB文件默认保存在当前运行目录,每次触发RDB时会生成一个新的RDB文件来覆盖旧文件,以保证备份数据的最新性。 AOF全称Append Only File,它是将Redis的操作以日志的形式追加到文件中。AOF文件的保存路径与RDB的路径一致。如果同时开启了RDBAOFRedis会优先根据AOF文件来进行数据恢复。 RDBAOF的目的都是为了将Redis中的数据持久化到磁盘中,以防止数据丢失。因为Redis中的数据是基于内存的,一旦服务器断电或宕机,数据就会直接丢失。通过使用RDBAOF,可以在Redis实例故障重启后,根据备份文件进行数据恢复。 总结来说,RDB是将内存中的数据直接拷贝到文件中的持久化方式,而AOF是将Redis的操作以日志的形式追加到文件中的持久化方式。根据配置的不同,可以选择使用RDBAOF或同时使用两者来实现数据持久化。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* *4* [详解RedisRDBAOF](https://blog.csdn.net/u014225032/article/details/125856164)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis持久化的两种方式:RDBAOF(详解)](https://blog.csdn.net/starboyxyh/article/details/127503310)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值