聊聊 Redis 高可用之持久化AOF和RDB分析

Redis 持久化概述

Redis 是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将 Redis 中的数据以某种形式把内存中的数据保存到磁盘中;当 Redis 重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

Redis 提供了两种不同的持久化方法来讲数据存储到硬盘上 :

  • RDB:一种称为快照的方式,是 将某一时刻内存中的所有数据以快照的形式写入硬盘上。
  • AOF:一种称为只追加文件的方式,它会是将每次执行的写命令以追加的形式保存到硬盘上。

下面依次介绍 RDB 持久化和 AOF 持久化。

RDB 持久化

RDB ( Redis Database ) 持久化就是把存储在内存里的数据在某个时间点上写入到硬盘上。在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本,也可以当Redis 重新启动时,读取快照文件恢复数据。

1 创建快照的方式

  • 可以在客户端通过向 Redis 发送 BGSAVE 命令创建快照。接到命令后,Redis 会调用 fork 来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程可以继续处理命令请求。
  • 可以在客户端通过向 Redis 发送 SAVE 命令来创建快照,接到 SAVE 命令后,Redis 服务器直接在主进程中创建快照,在创建快照期间,Redis 服务不再响应任何其他命令。
  • redis.conf 配置文件中设置了 save 配置选项, 比如 save 60 10000, 是指当“60 秒之内有10000次写入” 这个条件满足是,Redis 会自动触发 BGSAVE 命令。如果设置了多个 save 配置选项,那么当任意一个满足是,Redis 就会触发一次 BGSAVE 命令。
  • 当 Redis 接收到 SHUTDOWN 命令关闭服务器请求时,或者接收到标准 TERM 信号时,会执行 SAVE 命令,阻塞所有客户端请求,并在 SAVE 命令执行完毕之后关闭服务器。
  • 当一个 Redis 服务器第一次连接另一个 Redis 服务器,并向对方发送 psync 命令来开始复制操作时,如果主服务当前没有正在执行 BGSAVE 操作,那么主服务器就会执行 BGSAVE 命令。

2 原理分析

上文我们提到了创建 RDB 快照的几种方式,总结可以发现这几种方式无非就是通过 SAVEBGSAVE 命令来生成快照。

  • SAVE 命令: 此命令是在 Redis 服务器的主进程中执行,我们知道 Redis 是单线程的,那么,在执行此命令是就会阻塞当前 Redis 服务器,而无法执行其他命令的请求,对于内存比较大的实例会造成长时间阻塞。
  • BGSAVE 命令:此命令是 Redis 执行 fork 操作创建子进程,RDB 持久化过程有子进程处理。阻塞只发生在 fork 阶段,fork 结束后,Redis 主进程还可以继续处理其他命令请求。

由于 SAVE 命令会造成长时间阻塞,而 BGSAVE 命令阻塞时间较短,所以,一般很少使用SAVE 命令,而是用BGSAVE 命令,接下来我们进一步讲解一下 BGSAVE 命令。

虽然 SAVE 命令一直阻塞 Redis 直到快照生成完毕, 但是因为它不需要创建子进程, 并且没有子进程争抢资源,所以 SAVE 创建快照的速度比 BGSAVE 创建快照的速度快些。

fork系统调

fork 系统调用会产生一个子进程,它与父进程共享相同的内存地址空间,这样子进程在这一时刻就能拥有与父进程的相同的内存数据。

虽然子进程与父进程共享同一块内存地址空间,但是在 fork 子进程时,操作系统需要拷贝父进程的内存页表给子进程,如果整个 Redis 实例内存占用很大,那么它的内存页也会很大,在拷贝是就会比较耗时,同时这个过程会消耗大量的 CPU 资源。在完成拷贝之前父进程也处于阻塞状态,无法处理客户端请求。

fork 执行完之后,子进程就可以扫描自身所有的内存数据,然后把全部数据写入到 RDB 文件中。

fork 操作的流程如下所示:

在这里插入图片描述

Copy On Write

前面介绍了 BGSAVE 命令不会造成阻塞主进程接收其他命令的请求,有 fork 系统调用可知,子进程共享主进程的内存数据,那么,当 Redis 服务器接收到写命令时,修改内存数据时,子进程读取同一内存地址的数据时,就会出现脏数据。

如果为了快照而暂停写操作,肯定是不能接受的。所以,Redis 借助了操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

当父进程接收到写操作时,如果要修改的数据在内存中已经存在,那么,主进程就会拷贝一份数据,重新分配新的内存地址空间,这样,父进程就在新申请的内存空间中修改数据,不在与子进程共享,这个过程就是 Copy On Write(写实复制)。

比如我们修改上图的 物理页13 的数据,Copy On Write 后的图如下所:

在这里插入图片描述

这样父子进程的内存就会逐渐分离,父进程申请新的内存空间并更改内存数据,子进程的内存数据不受影响。

由此可以看出,在生成 RDB 文件时,不仅消耗 CPU 资源,还有需要占用最多一倍的内存空间。所以,我们应该保证 Redis 机器拥有 足够的CPU和内存资源,并合理设置生成 RDB 的时机。

3 RDB 的优缺点

RDB 的优点:

  • RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。
  • RDB 是派生子进程来生成快照文件,最大限度的减少了父进程阻塞时间,从而 RDB 最大限度的提高了 Redis 的性能。
  • Redis 加载 RDB 恢复数据要比 AOF 快的多。

RDB 的缺点:

  • RDB 方式没办法做到实时持久化 / 秒级持久化。会造成数据丢失。
  • RDB 需要 fork 创建子进程,进行持久化,如果数据集很大,CPU 性能不好,可能会导致 Redis 阻塞服务几毫秒甚至一秒钟,频繁执行成本过高。

AOF 持久化

AOF 全称成为 Append Only File ( 只追加文件)。简单来说,AOF 持久化会把执行的写命令写到 AOF 文件的末尾,以此来记录数据发生的变化。因此,Redis 只要从头到尾执行一次 AOF 文件中的文件,就可以恢复数据。

1 开启 AOF

Redis 中 AOF 默认是关闭的,在 redis.conf 配置文件中添加如下配置开启。

# 开启AOF
appendonly yes

# AOF文件名
appendfilename "appendonly.aof"

# 文件刷盘方式
appendfsync everysec

2 文件同步

开启 AOF 后,所有的写入命令都会追加到 AOF缓冲区 中, Redis 会根据刷盘策略把 AOF 缓冲区中的数据保存到磁盘中,为了保证数据文件的安全性,Redis 提供了如下刷盘策略:

  • appendfsync always:每个 Redis 写命令都会被写入硬盘,在一般 SATA 硬盘上,Redis 只能支持大约几百的 TPS 写入,对性能影响大;而 SSD 硬盘能处理几万的TPS,但是频繁的吸入会造成 SSD 硬盘的寿命缩短。所以 always 占用磁盘 I/O 比较高,数据安全性高。
  • appendfsync everysec:Redis 每秒对 AOF 文件进行同步一次。对性能影响较小,Redis 宕机时最多丢失 1 秒钟的数据。一般建议配置此种刷盘策略。
  • appendfsync no:按照操作系统的机制刷盘,对性能影响最小,数据安全性低,Redis 宕机丢失数据取决于操作系刷盘机制。

3 重写/压缩 AOF 文件

随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入了 AOF 重写机制压缩文件体积。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF文件的过程。

文件变小原因

  1. 进程内一超时的数据不再写入文件。
  2. 旧文件含有的无效命令,重写使用内存数据直接生成,这样新文件中只保留最终数据的写入命令。
  3. 多条写命令合并为一个。

触发方式

AOF 重写可以手动触发和自动触发:

  • 手动触发:直接调用 BGREWRITEAOF命令。

  • 自动触发:根据 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 参数确定自动触发机制,当满足条件时,就会调用 Redis 的 BGREWRITEAOF 命令。

    // AOF文件距离上次文件增长超过多少百分比则触发重写
    auto-aof-rewrite-percentage 100
    // AOF文件体积最小多大以上才触发重写
    auto-aof-rewrite-min-size 64mb

重写机制

BGREWRITEAOF 命令 与 BGSAVE 命令相似,在执行 BGREWRITEAOF 命令后,父进程 调用 fork 创建一个子进程执行 AOF 的重写操作。流程如下所示:

在这里插入图片描述

流程说明:
1、执行 AOF 重写请求

2、父进程执行 fork 创建子进程

3.1、fork 完成后,主进程继续响应其他命令,所有修改命令写入 AOF 缓冲区

3.2、接收的写命令同时也写入 AOF 重写缓冲区中。

4、子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件。

5.1、新 AOF文件写完成后,子进程发送信号给父进程。

5.2、父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件

5.3、使用新 AOF 文件替换老文件,完成 AOF 重写。

4 AOF 追加阻塞

当开启 AOF 持久化时,常用的同步硬盘策略是 everysec ,用于平衡性能和数据安全性。对于这种方式,Redis 使用另一个线程执行 fsync 同步刷盘。当系统硬盘资源繁忙是,会造成 Redis 主线程阻塞。

阻塞流程

  1. 主线程负责写入 AOF 缓冲区。
  2. AOF 线程负责每秒执行一次同步磁盘操作,并记录最近一次同步时间。
  3. 主线程负责对比上次 AOF 同步时间:
    • 如果距上次同步成功时间在 2 秒内,主线程直接返回。
    • 如果距上次同步成功时间超过 2 秒,主线程将会阻塞,直到同步操作完成。

阻塞流程发现问题

  1. everysec 配置最多可能丢失 2 秒数据,而不是 1 秒。
  2. 如果系统 fsync 缓慢,将会导致 Redis 主线程阻塞影响效率。

5 AOF 优缺点

AOF优点:

  1. AOF 可以更好的保护数据不丢失,一般 AOF 会以每隔 1 秒,通过后台的一个线程去执行一次 fsync 操作,如果 Redis 挂掉了,最多丢失 1 秒的数据。
  2. AOF 以 append-only 的模式写入,所以没有任何的磁盘寻址的开销,写入性能非常的高。
  3. AOF 日志文件的命令通过非常可读的方式进行记录,这个非常适合做灾难性的误删除紧急恢复,如果某人不小心用 flushall 命令清空了所有数据,只要这个时候还没有执行 Rewrite,那么就可以将日志文件中的flushall 删除,进行恢复。

AOF缺点:

  1. 对于同一份数据备份文件,AOF 比 RDB大
  2. AOF 开启后支持写的 QPS 会比 RDB 支持的写的 QPS 低,因为 AOF 一般会配置成每秒 fsync 操作,每秒的 fsync 操作还是很高的。
  3. 数据恢复比较慢,不适合做冷备。

参考资料:
《Redis 开发与运维》
《Redis 设计与实现》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容