目录
- 持久化
- RDB
- 触发机制
- 流程说明
- RDB ⽂件的处理
- RDB 的优缺点
- AOF
- 使⽤ AOF
- 命令写⼊
- ⽂件同步
- 重写机制
- 启动时数据恢复
- 混合持久化
- 小结
持久化
回顾 MySQL 的事务的特性:
- 原子性
- 一致性
- 持久性(持久化)
- 隔离性
持久化:把数据存储在硬盘上就是持久的(重启进程/主机,数据还会存在),把数据存储在内存上就是不持久。
Redis 是一个内存数据库,要想做到持久,就要把数据存储到硬盘上,为了保证速度快就要存在内存,要想持久化就要存在硬盘上,因此 Redis 是内存和硬盘都存储数据,这两份数据理论上是完全相同的,实际上可能有一点小差异,取决于怎么进行持久化。
当要插入一个新数据时,就要同时写入到内存和硬盘(说是两边都写入,但还是有不同的策略保证整体的效率);当要查询某个数据时,直接从内存读取
硬盘的数据只是在 Redis 重启的时候,用来恢复内存的数据的
这么做的代价就是消耗了更多的空间,同一份数据存储了两遍
Redis ⽀持 RDB(Redis DataBase) 和 AOF(Append Only File) 两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题,当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。本章内容:
- 介绍 RDB、AOF 的配置和运⾏流程,以及控制持久化的命令,如 bgsave 和 bgrewriteaof。
- 对常⻅持久化问题进⾏分析定位和优化。
这两个机制的大策略上是 RDB 是定期备份,AOF 是实时备份
RDB
定期备份
RDB(Redis DataBase)持久化是把当前进程数据⽣成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和自动触发。
触发机制
⼿动触发分别对应 save 和 bgsave 命令:
- save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为⽌,对于内存⽐较⼤的实例造成⻓时间阻塞,基本不采⽤。
因为 Redis 是单线程的,所以会阻塞
- bgsave(background save)命令:Redis 进程执⾏ fork 操作创建⼦进程,RDB 持久化过程由⼦进程负责,完成后⾃动结束。阻塞只发⽣在 fork 阶段,⼀般时间很短。
这个不会影响 Redis 服务器处理其他客户端的请求和命令。
这里不是 Redis 弄了个多线程,这是一个并发编程的场景,不只有多线程才能实现这样的效果,可以通过其他方式
Redis 内部的所有涉及 RDB 的操作都采⽤类似 bgsave 的⽅式。
除了⼿动触发之外,Redis 运⾏⾃动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。
- 使⽤ save 配置。如 “save m n” 表⽰ m 秒内数据集发⽣了 n 次修改,⾃动 RDB 持久化。
- 从节点进⾏全量复制操作时,主节点⾃动进⾏ RDB 持久化,随后将 RDB ⽂件内容发送给从结点。
- 执⾏ shutdown 命令关闭 Redis 时,执⾏ RDB 持久化。
流程说明
bgsave 是主流的 RDB 持久化⽅式,下⾯根据图 4-1 了解它的运作流程。
图 4-1 bgsave 命令的运作流程
-
执⾏ bgsave 命令,Redis ⽗进程判断当前进是否存在其他正在执⾏的⼦进程,如 RDB/AOF ⼦进程,如果存在 bgsave 命令直接返回。
-
⽗进程执⾏ fork 创建⼦进程,fork 过程中⽗进程会阻塞,通过 info stats 命令查看latest_fork_usec 选项,可以获取最近⼀次 fork 操作的耗时,单位为微秒。
fork 是 Linux 系统提供的一个创建子进程的 api(系统调用),如果是类似 Windows 之类的,创建子进程就不是 fork(CreateProcess…)。
fork 创建子进程,就是直接把当前的进程(父进程)复制一份作为子进程,复制完成后这两个进程就是独立的两个进程了,各自执行各自的。
这里的复制会复制 pcb,虚拟地址空间(内存的数据),文件描述符表…,这个子进程的内存里也会存在和父进程一模一样的变量。因此这个子进程数据和父进程是一样的,然后安排子进程执行“持久化“操作,就相当于把父进程本体这里的内存数据持久化了。
父进程打开一个文件,fork 了之后,子进程也会同样使用这个文件,也就导致了子进程持久化写入的那个文件和父进程本来要写的文件是同一个了。
如果当前 Redis 服务器存储的数据特别多,内存消耗特别大,比如超过 100GB,此时进行上述的复制操作是否会有很大的性能开销?
不会,其实开销挺小的,因为 fork 进行内存拷贝时,不是把所有的数据都拷贝一份,而是“写时拷贝”。如果子进程的内存数据和父进程的内存数据完全一样,就共用一份内存数据。但这两进程的内存空间是各自独立的,一旦某一方针对这个内存数据做出了修改,就会立即触发真正的 物理内存 上的数据拷贝。整体思想上和‘懒汉模式“类似。
- ⽗进程 fork 完成后,bgsave 命令返回 “Background saving started” 信息并不再阻塞⽗进程,可以继续响应其他命令。
- ⼦进程创建 RDB ⽂件,根据⽗进程内存⽣成临时快照⽂件,完成后对原有⽂件进⾏原⼦替换。执⾏ lastsave 命令可以获取最后⼀次⽣成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选项。
- 进程发送信号给⽗进程表⽰完成,⽗进程更新统计信息。
RDB ⽂件的处理
保存:RDB ⽂件保存再 dir 配置指定的⽬录(默认 /var/lib/redis/)下,⽂件名通过 dbfilename 配置(默认 dump.rdb)指定。可以通过执⾏ config set dir {newDir} 和 config set dbfilename{newFilename} 运⾏期间动态执⾏,当下次运⾏时 RDB ⽂件会保存到新⽬录。
Redis 生成的 RDB 文件是存放在 Redis 的工作目录中的,也是在 Redis 配置文件中进行设置的。
我们之前设置为了 /var/lib/redis,那行命令是
dir /var/lib/redis
dump.rdb 是 RDB 机制生成的镜像文件,Redis 服务器默认就是开启了 RDB 的,这是一个二进制文件,内存中的数据是以压缩的形式保存到这个二进制文件的,这是需要消耗一定的 CPU 资源,但能节省存储空间。
这个文件最多通过 vim 的方式打开看看即可,一旦把数据格式改错了,后续 Redis 服务器重启,就会尝试加载这个 rdb 文件,发现格式错误就会加载数据失败。
当执行生成 rdb 镜像时,此时就会把要生成的快照数据,先保存到一个临时文件中,当这个快照生成完毕之后,再删除之前的 rdb 文件,把新生成的临时文件的 rdb 文件名字改成刚开始时的 dump.rdb。保证了自始至终,rdb 文件只有一个
压缩:Redis 默认采⽤ LZF 算法对⽣成的 RDB ⽂件做压缩处理,压缩后的⽂件远远⼩于内存⼤⼩,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
虽然压缩 RDB 会消耗 CPU,但可以⼤幅降低⽂件的体积,⽅便保存到硬盘或通过⽹络发送到从节点,因此建议开启。
校验:如果 Redis 启动时加载到损坏的 RDB ⽂件会拒绝启动。这时可以使⽤ Redis 提供的 redis-check-dump ⼯具检测 RDB ⽂件并获取对应的错误报告。
Redis 提供了 rdb 文件的检查工具,
redis-check-rdb
,这个是在 /usr/bin 目录下的。
rdb 文件的数据不是一插入数据就立即更新的,触发时机是手动或者自动的。只插入几个键值对,没有运行手动触发的命令,也达不到自动触发的条件,就不会更新了。
自动触发的条件是在配置文件中,默认的应该是这样的
save 900 1 save 300 10 save 60 10000
第一个数字是秒数,第二个数字是修改次数。举例第一个,过了 900 秒后,即 15 分钟后,修改次数至少为 1 次就会触发更新操作
这些数据都可以修改,不过最好不要。生成一次 rdb 快照的成本是比较高的,不能频繁执行这样的操作。正因如此,快照里的数据,和当前实时的数据情况可能存在偏差
这样的更新快照的条件有数据丢失的风险,两次快照之间的数据变更在发生故障时可能丢失。比如一个电商平台的购物车系统使用 Redis 来存储用户的购物车信息。如果平台设置了
save 300 10
的条件,而在一次快照之后和下一次触发快照之前,服务器突然宕机,那么这段时间内所有购物车的更新都将丢失,可能导致用户体验不佳。
RDB 持久化机制的操作流程:
- 可以手动执行 save/bgsave 触发一次生成快照。
- 不手动执行 save/bgsave
- 通过配置文件中 save 执行 M 时间内,修改 N 次的条件
- 或者通过 shutdown 命令(Redis 自带的命令)关闭 Redis 服务器也会触发,比如
service redis-service restart
- 又或者 Redis 进行主从复制时,主节点也会自动生成 rdb 快照,然后把 rdb 快照文件内容传输给从节点(后续再讲)
对于第 2 种方式里的关闭操作,如果是异常关闭而不是正常关闭,那就不会触发一次生成快照
- bgsave 操作流程是创建子进程,子进程完成持久化操作,这个操作的速度是很快的,难以观察,但持久化会把数据写入到新的文件中,然后用新的文件替换旧的文件,这个是可以观察的。
- 可以使用 Linux 的 stat 命令,查看文件的 inode 编号。经过 bgsave 后的文件的 inode 编号是不同的
- 如果直接使用 save 是不会触发 子进程&文件替换 的逻辑,就是直接在当前进程中往同一个文件中写入数据了
Linux 文件系统
文件系统典型的组织方式,ext4,主要是把整个文件分成了三大部分:
- 超级块:放的是一些管理信息
- inode 区:存放 inode 节点,每个文件都会分配一个 inode 数据结构,包含了文件的各种元数据
- block 区:存放文件的数据内容
- 通过修改配置文件自动生成 rdb 快照,就是修改那个 save 那部分。对于 Redis 来说,配置文件一旦修改就要重启后才能生效,如果想立即生效可以通过命令的方式修改
如果设置为
save ""
这样的空字符串,就是关闭自动生成快照
- 如果把 rdb 文件故意改坏了,会怎么样?
- 手动把 rdb 文件修改坏
- 通过 kill 进程的方式重新启动 Redis 服务器,如果通过
service redis-server restart
重启,就会在 Redis 服务器退出时重新生成 rdb快照,就会把改坏的文件替换了 - kill 进程之后应该 Redis又自启了,一看进程号应该就不同了。但此时你可能发现 redis 服务器没受到什么影响,还是能正常启动、正常获取到 key。那是因为你改坏的地方是对正文内容没什么影响的,如果改的是关键的内容就一定会出错了,连自启都不会了
- 当 redis 挂了之后,你可以去到
/var/log/redis/
目录看看日志信息,这个路径是配置文件默认设置的,查看 redis-server.log 文件 - 然后你可以通过 redis-check-rdb 这个检查工具检查 rdb 文件是否符合要求,语法格式
redis-check-rdb dump.rdb
类似这样,不然就是启动 redis 服务器
RDB 的优缺点
- RDB 是⼀个紧凑压缩的⼆进制⽂件,代表 Redis 在某个时间点上的数据快照。⾮常适⽤于备份,全量复制等场景。⽐如每 6 ⼩时执⾏ bgsave 备份,并把 RDB ⽂件复制到远程机器或者⽂件系统中(如 hdfs)⽤于灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的⽅式。
RDB 使用 二进制 的方式组织数据,AOF 使用 文本 的方式组织数据,前者是一定快于后者的,因为不用解析转换
- RDB ⽅式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运⾏都要执⾏ fork 创建⼦进程,属于重量级操作,频繁执⾏成本过⾼。
这是最大的问题,有可能在两次生成快照之间,实时的数据可能会随着重启而丢失
- RDB ⽂件使⽤特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风险。
AOF
实时备份
AOF(Append Only File)持久化:以独⽴⽇志的⽅式记录每次写命令,重启时再重新执⾏ AOF ⽂件中的命令达到恢复数据的⽬的。AOF 的主要作⽤是解决了数据持久化的实时性,⽬前已经是Redis 持久化的主流⽅式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能⾮常有帮助。
类似于 MySQL 的 binlog,会把用户的每个操作都记录到文件中,redis 重启时会读取这个 aof 这个文件的内容,用来恢复数据。
使⽤ AOF
开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF ⽂件名通过 appendfilename 配置(默认是 appendonly.aof)设置。保存⽬录同 RDB 持久化⽅式⼀致,通过 dir配置指定。AOF 的⼯作流程操作:命令写⼊(append)、⽂件同步(sync)、⽂件重写(rewrite)、重启加载(load),如图 4-2 所⽰。
当开启 aof 时,rdb 就不生效了,启动的时候就不再读取 rdb 文件内容了。
aof 默认一般是关闭状态,通过修改配置文件,开启 aof 功能。这一行配置在配置文件的第 700 行。把
appendonly no
改为appendonly yes
就是开启了下面大概第 704 行可以配置 aof 的文件名
appendfilename "appendonly.aof"
,文件所在的位置和 rdb 所在的目录一样,都是 /var/lib/redis,不过是可配置的AOF 是一个文本文件,每次进行的操作,都会被记录到文本文件中。通过一些特殊符号作为分隔符,来对命令的细节做出区分
图 4-2 AOF ⼯作流程
-
所有的写⼊命令会追加到 aof_buf(缓冲区)中。
-
AOF 缓冲区根据对应的策略向硬盘做同步操作。
-
随着 AOF ⽂件越来越⼤,需要定期对 AOF ⽂件进⾏重写,达到压缩的⽬的。
-
当 Redis 服务器启动时,可以加载 AOF ⽂件进⾏数据恢复。
命令写⼊
AOF 命令写⼊的内容直接是⽂本协议格式。例如 set hello world 这条命令,在 AOF 缓冲区会追加如下⽂本:
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
此处遵守 Redis 格式协议,Redis 选择⽂本协议可能的原因:⽂本协议具备较好的兼容性;实现简单;具备可读性。
AOF 过程中为什么需要 aof_buf 这个缓冲区?Redis 使⽤单线程响应命令,如果每次写 AOF ⽂件都直接同步硬盘,性能从内存的读写变成 IO 读写,必然会下降。先写⼊缓冲区可以有效减少 IO 次数,同时,Redis 还可以提供多种缓冲区同步策略,让⽤⼾根据⾃⼰的需求做出合理的平衡。
Redis 虽然是一个单线程的服务器,但是速度很快,快的原因是只是操作内存。引入 AOF 之后又要写内存又要写硬盘,还会和之前一样快吗?
实际上没有影响,并不会影响到 redis 处理请求的速度
- AOF 机制并非是直接让工作线程把数据写入硬盘,而是先写入一个内存的缓冲区,积累一波后再统一写入硬盘,大大降低了写入硬盘的次数。对于写硬盘这个操作,写入数据的多少对性能影响不大,但写入硬盘的次数就影响很大了
- 硬盘上读写数据,顺序读写的速度是比较快的(但还是比内存慢很多),但随机访问的速度是比较慢的。AOF 是每次把新的操作写入到原有文件的末尾,属于顺序写入
⽂件同步
Redis 提供了多种 AOF 缓冲区同步⽂件策略,由参数 appendfsync 控制,不同值的含义如表 4-1 所⽰。
Redis 给出一些选项,让程序员自主决定缓冲区的刷新策略:
- 刷新频率越高,性能影响越大,数据的可靠性越高
- 刷新频率越低,性能影响越小,数据的可靠性越低
表 4-1 AOF 缓冲区同步⽂件策略
- always:写入就刷新,频率最高,可靠性最高
- everysec:每秒刷新一次,频率低了一些,可靠性较高,这是默认策略。
- no:自行刷新,频率最低,可靠性最低
这些可以在配置文件设置,在第 730 行
appendfsync everysec
,这是默认的
系统调⽤ write 和 fsync 说明:
- write 操作会触发延迟写(delayed write)机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区⻚空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
- Fsync 针对单个⽂件操作,做强制硬盘同步,fsync 将阻塞直到数据写⼊到硬盘。
- 配置为 always 时,每次写⼊都要同步 AOF ⽂件,性能很差,在⼀般的 SATA 硬盘上,只能⽀持⼤约⼏百 TPS 写⼊。除⾮是⾮常重要的数据,否则不建议配置。
- 配置为 no 时,由于操作系统同步策略不可控,虽然提⾼了性能,但数据丢失⻛险⼤增,除⾮数据重要程度很低,⼀般不建议配置。
- 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。
重写机制
随着命令不断写⼊ AOF,⽂件会越来越⼤,为了解决这个问题,Redis 引⼊ AOF 重写机制压缩⽂件体积。AOF ⽂件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF ⽂件。重写后的 AOF 为什么可以变⼩?有如下原因:
- 进程内已超时的数据不再写⼊⽂件。
- 旧的 AOF 中的⽆效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本。
- 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a bc。
较⼩的 AOF ⽂件⼀⽅⾯降低了硬盘空间占⽤,⼀⽅⾯可以提升启动 Redis 时数据恢复的速度。
Redis 启动的时候要读取 aof 文件的内容,其中有一些内容是冗余的。比如
- lpush key 111
- lpush key 222
- lpush key 333
这三个操作就相当于 lpush key 111 222 333
又比如
- set key 111
- set key 222
- set key 333
这三个操作就相当于 set key 333
又比如
- set key 111
- del key
- set key 222
- del key
这四个操作相当于什么都没干
实际上 Redis 重启的时候只关注最终结果,因此 Redis 存在这样的机制,能够针对 aof 文件进行 整理 操作,这个整理就是能够剔除其中的冗余操作,并且合并一些操作,达到个 aof 文件瘦身的效果。这个就是重写机制
AOF 重写过程可以⼿动触发和⾃动触发:
- ⼿动触发:调⽤ bgrewriteaof 命令。
- ⾃动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时机。
- auto-aof-rewrite-min-size:表⽰触发重写时 AOF 的最⼩⽂件⼤⼩,默认为 64MB。
- auto-aof-rewrite-percentage:代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。
当触发 AOF 重写时,图 4-3 介绍它的运⾏流程。
图 4-3 AOF 重写流程
-
执⾏ AOF 重写请求。如果当前进程正在执⾏ AOF 重写,请求不执⾏。如果当前进程正在执⾏ bgsave 操作,重写命令延迟到 bgsave 完成之后再执⾏。
-
⽗进程执⾏ fork 创建⼦进程。父进程仍负责接收请求,子进程负责针对 aof 文件进行重写。
重写时不关心 aof 文件原来有什么,只关心内存中最终的数据状态
内存中的数据的状态,已经相当于是把 AOF 文件结果整理后的模样了。这里子进程写数据的时候非常类似于 RDB 生成一个镜像快照,只不过 RDB 是按照二进制的方式来生成的,AOF 重写,则是按照 AOF 这里要求的文本格式来生成。都是为了把当前内存中的所有数据状态记录到文件中
-
重写
-
主进程 fork 之后,继续响应其他命令。所有修改操作写⼊ AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证旧 AOF ⽂件机制正确。
-
⼦进程只有 fork 之前的所有内存信息,⽗进程中需要将 fork 之后这段时间的修改操作写⼊ AOF 重写缓冲区中。
子进程写新 aof 文件的同时,父进程仍然在不停的接收客户端的新的请求,父进程还是会先把这些请求产生的 aof 数据先写入到缓冲区,再刷新到原有的 aof 文件里
在创建子进程的一瞬间,子进程就继承了当前父进程的内存状态
因此子进程里的内存数据是父进程 fork 之前的状态,fork 之后,新来的请求对内存造成的修改子进程是不知道的。此时父进程这里准备了一个 aof_rewrite_buf 缓冲区,专门放 fork 之后收到的数据。
-
-
⼦进程根据内存快照,将命令合并到新的 AOF ⽂件中。
-
⼦进程完成重写
- 新⽂件写⼊后,⼦进程发送信号给⽗进程。
- ⽗进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF ⽂件中。
- ⽤新 AOF ⽂件替换⽼ AOF ⽂件。
子进程这边把 aof 数据写完之后,会通过 信号 通知父进程,父进程再把 aof_rewrite_buf 缓冲区中的内容也写入到新 aof 文件里
问:如果在执行 bgrewriteaof 的时候,当前 Redis 已经在进行 aof 重写了,会怎么样?
答:此时不会再执行 aof 重写,直接返回了。
问:如果在执行 bgrewriteaof 的时候,当前 Redis 正在生成 rdb 文件的快照,会怎么样?
答:此时 aof 重写操作就会等待,等待 rdb 快照生成完毕之后再记性执行 aof 重写。
问:AOF 重写流程中子进程已经能写出新的 aof 文件了,为什么还需要 3.1) 这个旧的 aof 文件呢?
答:父进程 fork 之后就已经让子进程写新的 aof 文件了,并且随着时间推移,子进程很快写完了新的 aof 文件,要让新的 aof 文件代替旧的了。父进程此时继续写这个旧的 aof 文件的意义就是为了避免出现,重写的过程中重写一半服务器挂了,这种情况下子进程内存写的数据就都没了,新的 aof 文件内容还不完整,父进程写的旧的 aof 文件就能保证重启之后数据的完整性了。
问:rdb 对于 fork 之后的新数据就直接置之不理,aof 则对于 fork 之后的数据采取了 aof_rewrite_buf 缓冲区 的方式来处理,为什么 rdb 不效仿 aof 这样处理,那样不就克服了之前备份文件不够及时的问题了吗?
答:如果 rdb 效仿了 aof,那 rdb 就变成了 aof 了。rdb 本身的设计理念就是定期备份,只要是定期备份就难以和最新数据保持一致,如果效仿了 aof,那就变成了实时备份。
实时备份不一定比定期备份更好,还要看实际场景。不过现在的系统资源一般是比较充裕的,aof 的开销也不算大了,因此 aof 适用场景也更多一些。
问:简单解释一下这个 AOF 重写流程中的 “信号通知父进程”
信号这个东西,可以认为是 Linux 的神经系统,进程之间的相互作用(也可以视为是进程间通信的一种手段),但是 Java 生态中并不鼓励使用多进程模型编程(网络通信的场景除外)。
信号能表达的信息有限,不像 socket 一样能够传输任意的数据。但像上述 父子进程 场景中,子进程表达“我做完了”这种简单的信息传递,使用信号是完全足够了。
信号在 Java 体系中,最接近的 js 里的“事件”。
事件包含事件源、事件的类型、事件的处理函数
信号包含信号源(其实更关注信号发给谁)、信号的类型、信号的处理函数
启动时数据恢复
当 Redis 启动时,会根据 RDB 和 AOF ⽂件的内容,进⾏数据恢复,如图 4-4 所⽰。
当 Redis 同时存在 aof 文件和 rdb 快照的时候,以 aof 为主,因为 aof 里包含的数据比 rdb 更全。
图 4-4 Redis 根据持久化⽂件进⾏数据恢复
混合持久化
AOF 本来是按照文本的方式写入文件的,但是写文本的方式后续加载的成本比较高,因此就结合了 rdb 和 aof 的特点。这个就是混合持久化。
在配置文件的第 807 行中,
aof-use-rdb-preamble yes
,默认是启动混合持久化的
- 按照 aof 的方式,每一个请求/操作,都记录入文件
- 在触发 aof 重写之后,就会把当前内存的状态按照 rdb 的二进制格式写入到新的 aof 文件中,后续再进行的操作,仍然是按照 aof 文本的方式追加到文件末尾的
小结
-
Redis 提供了两种持久化⽅案:RDB 和 AOF。
-
RDB 视为内存的快照,产⽣的内容更为紧凑,占⽤空间较⼩,恢复时速度更快。但产⽣ RDB 的开销较⼤,不适合进⾏实时持久化,⼀般⽤于冷备和主从复制。
-
AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF ⽂件。
-
RDB 和 AOF 都使⽤ fork 创建⼦进程,利⽤ Linux ⼦进程拥有⽗进程内存快照的特点进⾏持久化,尽可能不影响主进程继续处理后续命令。