目录
Redis持久化机制
1.RDB持久化
(1)手动触发RDB持久化
(2)自动触发RDB持久化
(3)Redis文件相关处理
(4)RDB持久化的优缺点
2.AOF持久化
(1)AOF工作流程
(2)AOF缓冲区文件同步
(3)AOF重写机制
(4)Redis启动时数据恢复流程图
Redis持久化机制
众所周知,Redis的快主要依赖于它的数据是存储在内存当中的,数据存储和提取避免了读写硬盘这一非常耗时的操作,但是如果在运行过程中发生了进程中断,内存中的数据就会丢失,为了解决数据丢失的问题,Redis提供了RDB和AOF两种持久化机制,当Redis重启时可以利用之前持久化的文件实现数据恢复。
1.RDB持久化
(1)手动触发RDB持久化
- save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存⽐较⼤的实例造成长时间阻塞,基本不采⽤。
- bgsave 命令:Redis 进程执⾏ fork 操作创建⼦进程,RDB 持久化过程由⼦进程负责,完成后⾃动结束。阻塞只发⽣在 fork 阶段,⼀般时间很短。
具体操作展示如下:
在/etc/redis/redis.conf中Redis的配置文件中便可以找到Redis的工作目录Redis变会把工作时生成的文件放在这个目录下面。
下面这个配置项可以修改生成的rdb文件的名称。
进行如下操作可以看到我们确实进入到了dump.rdb所在路径。
打开可以看到里面是二进制文件,显示出来的即是乱码的情况
下面我们执行save/bgsave命令感受rdb文件的变化。
可以看到命令生效。
(2)自动触发RDB持久化
- 使⽤ save 配置。如 "save m n" 表⽰ m 秒内数据集发⽣了 n 次修改,⾃动 RDB 持久化。
- 从节点进⾏全量复制操作时,主节点⾃动进⾏ RDB 持久化,随后将 RDB ⽂件内容发送给从结点。
- 执⾏ shutdown 命令关闭 Redis 时,执⾏ RDB 持久化。
在配置文件中找到save配置项的相关信息,修改save后面的数字便可以自定义rdb文件自动生成的时间,可以依据实际工作需要进行修改。需要注意的是生成一次rdb文件,这个操作需要效果比较高的成本,不能让这个操作执行的太频繁。
(3)Redis文件相关处理
- 保存位置:RDB ⽂件保存再 dir 配置指定的⽬录(默认 /var/lib/redis/)下,⽂件名通过 dbfilename配置(默认 dump.rdb)指定。可以通过执⾏ config set dir {newDir} 和 config set dbfilename{newFilename} 运⾏期间动态执⾏,当下次运⾏时 RDB ⽂件会保存到新⽬录。
- 压缩:Redis 默认采⽤ LZF 算法对⽣成的 RDB ⽂件做压缩处理,压缩后的⽂件远远⼩于内存⼤⼩,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
- 校验:如果 Redis 启动时加载到损坏的 RDB ⽂件会拒绝启动。这时可以使⽤ Redis 提供的 redis-check-dump ⼯具检测 RDB ⽂件并获取对应的错误报告
tips: 虽然压缩 RDB 会消耗 CPU,但可以⼤幅降低⽂件的体积,⽅便保存到硬盘或通过⽹络发送到从节点,因此建议开启。
(4)RDB持久化的优缺点
- RDB 是⼀个紧凑压缩的⼆进制⽂件,代表 Redis 在某个时间点上的数据快照。⾮常适⽤于备份,全量复制等场景。⽐如每 6 ⼩时执⾏ bgsave 备份,并把 RDB ⽂件复制到远程机器或者⽂件系统中(如 hdfs)⽤于灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的⽅式。
- RDB ⽅式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运⾏都要执⾏ fork 创建⼦进程,属于重量级操作,频繁执⾏成本过⾼。
- RDB ⽂件使⽤特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有⻛险。
正是因为rdb文件每次生成的时候都需要把内存中所有的数据都进行转化为二进制并存储,这个操作不可能进行的非常频繁,这就会导致rdb文件中实际存储的内容并不可能与内存中的实时相同,虽然Redis在执行正常服务停止操作的时候还会再次进行一次rdb生成操作,但是遇到特殊情况导致进程终止,还是无法保证数据一致性。为了保证数据的一致性,Redis在进行rdb持久化的同时还在进行aof持久化。
2.AOF持久化
(1)AOF工作流程
开启AOF功能需要在配置文件中配置:appendonly yes,默认不开启。AOF文件名通过appendfilename配置(默认是 appendonly.aof)。保存⽬录同 RDB 持久化⽅式⼀致,通过 dir配置指定。AOF 的⼯作流程操作:命令写⼊(append)、⽂件同步(sync)、⽂件重写(rewrite)、重启加载(load)。
AOF的工作流程如下:
- 所有的写⼊命令会追加到 aof_buf(缓冲区)中。
- AOF 缓冲区根据对应的策略向硬盘做同步操作。
- 随着 AOF ⽂件越来越⼤,需要定期对 AOF ⽂件进行重写,达到压缩的⽬的。
- 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。
(2)AOF缓冲区文件同步
AOF机制会把每命令的操作记录在缓冲区内,达到一定规则便会向磁盘中以文本形式写入命令,我们可以更改Redis配置文件中下面参数的选项以此来适应不同环境的需要。
可配置项 | 说明 |
---|---|
always | 命令写⼊ aof_buf 后调⽤ fsync 同步,完成后返回 |
everysec | 命令写⼊aof_buf 后只执⾏ write 操作,不进⾏fsync。每秒由同步线程进⾏ fsync。 |
no | 命令写⼊ aof_buf 后只执⾏ write 操作,由 OS 控制fsync 频率。 |
系统调用write和fsync说明:
- write 操作会触发延迟写(delayed write)机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
- Fsync 针对单个⽂件操作,做强制硬盘同步,fsync 将阻塞直到数据写⼊到硬盘。
- 配置为 always 时,每次写入都要同步 AOF ⽂件,性能很差,在⼀般的 SATA 硬盘上,只能⽀持⼤约⼏百 TPS 写⼊。除⾮是⾮常重要的数据,否则不建议配置。
- 配置为 no 时,由于操作系统同步策略不可控,虽然提⾼了性能,但数据丢失⻛险⼤增,除⾮数据重要程度很低,⼀般不建议配置。
- 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。
(3)AOF重写机制
AOF文件内因为写入的是吗命令的文本文件,随着不断的写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。
为什么重写后的AOF体积可以变小,原因有以下几点:
- 进程内已超时的数据不再写⼊⽂件。
- 旧的 AOF 中的⽆效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本。
- 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list c可以合并为 lpush list a b c。
- ⼿动触发:调⽤ bgrewriteaof 命令。
- ⾃动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时机。
- auto-aof-rewrite-min-size:表⽰触发重写时 AOF 的最⼩⽂件⼤⼩,默认为 64MB。
- auto-aof-rewrite-percentage:代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。
AOF重写流程图:
- . 执⾏ AOF 重写请求。如果当前进程正在执⾏ AOF 重写,请求不执⾏。如果当前进程正在执⾏ bgsave 操作,重写命令延迟到 bgsave 完成之后再执⾏。
- ⽗进程执⾏ fork 创建⼦进程。
- 重写:(1)主进程 fork 之后,继续响应其他命令。所有修改操作写⼊ AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证旧 AOF ⽂件机制正确。(2)⼦进程只有 fork 之前的所有内存信息,⽗进程中需要将 fork 之后这段时间的修改操作写⼊AOF 重写缓冲区中。
- ⼦进程根据内存快照,将命令合并到新的 AOF ⽂件中。
- ⼦进程完成重写: (1)新⽂件写⼊后,⼦进程发送信号给⽗进程。 (2)⽗进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF ⽂件中。(3)⽤新 AOF ⽂件替换⽼ AOF ⽂件。