目录
1. RDB持久化
1.1 触发机制
1.2 流程说明
1.3 RDB文件的处理
1.4 RDB机制演示
1.5 RDB的优缺点
2. AOF持久化
2.1 使用AOF与基本演示
2.2 AOF的工作流程
2.3 文件同步(缓冲区刷新策略)
2.4 重写机制
2.5 AOF重写流程
2.6 启动时数据恢复
持久化功能有效地避免因进程退出造成数据丢失问题当下次重启时利用之前持久化的文件即可实现数据恢复,(比如重启机器、机器故障之后恢复数据),或者是为了做数据同步(比如 Redis 集群的主从节点通过 RDB 文件同步数据)。
Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持 3 种持久化方式:
- 快照(snapshotting,RDB)
- 只追加文件(append-only file, AOF)
- RDB 和 AOF 的混合持久化(Redis 4.0 新增)
1. RDB持久化
RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB持久化过程分为手动触发和自动触发。Redis 创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用。
1.1 触发机制
1. 手动触发分别对应 save 和 bgsave 命令:
- save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例造成长时间阻塞,基本不采用。
- bgsave 命令:Redis 进程执行fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。
Redis 内部的所有涉及 RDB 的操作都采用类似 bgsave 的方式。
2. Redis 自动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。
- 使用 save 配置。如"save m n" 表示 m 秒内数据集发生了n次修改,自动 RDB 持久化。(快照持久化是 Redis 默认采用的持久化方式,在 redis.conf 配置文件中默认有此下配置,后见1.4小节会详细讲)
- 从节点进行全量复制操作时,主节点自动进行 RDB 持久化,随后将 RDB 文件内容发送给从结点。
- 执行 shutdown 命令关闭 Redis 时,执行 RDB 持久化。
1.2 流程说明
bgsave 是主流的 RDB 持久化方式,上图是它的运作流程。
- 执行 bgsave 命令,Redis 父进程判断当前进是否存在其他正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。
- 父进程执行 fork 创建子进程,fork 过程中父进程会阻塞,通过info stats 命令查看latest_fork_usec 选项,可以获取最近一次 fork 操作的耗时,单位为微秒。
- 父进程 fork完成后,bgsave 命令返回"Background saving started"信息并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave 命令可以获取最后一次生成 RDB 的时间,对应info 统计的 rdb_last_save_time选项。
- 进程发送信号给父进程表示完成,父进程更新统计信息。
思考:如果当前Redis服务器中存储的数据特别多,内存消耗特别大(比如100GB),此时,进行上述的fork操作,是否会有很大的性能开销?
答:此时的性能开销,其实是挺小的。fork在进行内存拷贝的时候,不是简单无脑的直接把所有的数据都拷贝一遍,而是“写时拷贝”的机制来完成的!
具体来说,
fork
只会在内存被修改时才实际复制数据,而在未修改时,父子进程共享同一份物理内存。因此,即使有大量数据,内存的实际拷贝成本也能得到控制,从而在处理高内存使用情况下的性能影响降到最低。这使得Redis在高负载时仍然能够有效运行。
1.3 RDB文件的处理
保存
reids生成的rdb文件,存放在redis的工作目录中,也是在redis配置文件中进行设置的。
打开目录看一看:
这里的 dump.rdb就是rbd机制生成的文件,以压缩的方式,保存到二进制文件中。(压缩需要消耗一定的cpu资源,但是能够节省存储空间)(Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。)
rbd持久化是可以被多次触发的,那么这个dump.rdb文件按照什么机制来“完成”的呢?
当执行生成rdb镜像操作的时候,此时会把要生成的快照数据,先保存到一个临时文件中,当快照要生成结束之后,再删除之前的rdb文件,把新生成的rdb文件名字修改成刚才的dump.rdb。
校验
如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redis-check-dump 工具检测 RDB 文件并获取对应的错误报告。
这里的redis-check-rdb* 就是检查工具。
1.4 RDB机制演示
1. 连接到redis,清空数据,观察工作目录(/var/lib/redis)下的dump.rdb大概是什么样子:
2. 插入几个key-value数据,再次观察rdb文件:
此时看到是没有变化的,这是因为rdb触发时机并不是插入后就会立即更新的。我们前面提到手动触发和命令触发,两种方式都没能达到啊。手动触发没有使用可以理解,那么自动触发的条件究竟是怎么触发呢?
继续来看看redis的配置文件,在/etc/redis/redis.conf
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发bgsave命令创建快照。save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发bgsave命令创建快照。save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发bgsave命令创建快照。
可见我们现在的修改确实达不到,任何一种自动触发机制。【配置文件中的数值可以修改,但是要注意,修改的基本原则就是:生成一次rbd是一个比较高的成本,不宜让这个操作的执行过于频繁】
3. 手动触发RDB
虽然是二进制文件,但是隐隐约约才是能够看到rdb文件确实发生了变化。我们可以重启redis服务器来观察是否重启后,可以通过持久化的RDB文件来恢复数据。
4. 重启Redis,观察持久化是否成功
可以看到数据确实恢复了,哪怕redsi服务器重启,数据也是不会丢失的。因为它加载了rdb文件中的内容恢复到了之前的状态。
如果插入新的key后,没有通过手动bgsave来触发RDB机制,这时候重新启动Redis,服务中新添加的数据就会丢失。那么是不是这样的呢?
其实并不是这样的,除了手动触发之外:
- 通过刚才配置文件中 save 执行 M 时间内,修改 N 次.…..
- 通过 shutdown 命令(redis 里的一个命令) 关闭 redis 服务器,也会触发.(service redis-server restart)
- redis 进行主从复制的对候,主节点也会自动生成 rdb 快照,然后把 rdb 快照文件内容传输给从节点
5. 继续添加新元素,然后使用service redis-server restart 重启服务
除了手动执行bgsave之外,也可以通过配置save配置文件来修改自动触发的条件。这里就不再演示。
1.5 RDB的优缺点
- RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6小时执行bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中(如 hdfs)用于灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
- RDB 方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork创建子进程,属于重量级操作,频繁执行成本过高。
- RDB 文件使用特定二进制格式保存,Redis版本演进过程中有多个 RDB版本,兼容性可能有风险。
2. AOF持久化
AOF(Append Only File)持久化: 以独立日志的方式记录每次写命令,重启时再重新执行 AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,目前已经是
Redis 持久化的主流方式。(当开启AOF后,RDB就不再生效)
2.1 使用AOF与基本演示
AOF默认是不开启的,需要通过配置文件配置:appendonly yes后,开启AOF。
修改完配置文件后,重启服务:service redis-server restart
添加新的数据
暴力kill redis服务,是否会恢复数据?
从图中结果来看,数据是不会丢失的。符合我们的预期,以上就是大概的AOF持久化机制的基本使用过程。
2.2 AOF的工作流程
1. 所有的写⼊命令会追加到 aof_buf(缓冲区)中。2. AOF 缓冲区根据对应的策略向硬盘做 同步操作 。 (具体是哪些文件同步策略下文2.3会详细介绍)这样可以减少写磁盘的次数。【缓冲区还是为了追求高的效率,如果 突然断电 ,缓冲区中的数据还没有来得及写磁盘,这时候还是会出现 数据丢失 的情况的】3. 随着 AOF ⽂件越来越⼤,需要定期对 AOF ⽂件进⾏ 重写 ,达到压缩的⽬的。4. 当 Redis 服务器启动时,可以加载 AOF ⽂件进⾏数据恢复。
2.3 文件同步(缓冲区刷新策略)
Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync控制,不同值的含义如下所
示。刷新频率越高,性能影响就越大,同时数据的可靠性也就越高;反之则反。
always:刷新频率最高,数据的可靠性最高,但是性能最低;
everysec:刷新频率低一丢丢,数据的可靠性稍降低,性能同时稍高;(默认刷新方式)
no:频率最低,数据可靠性也是最低,但是性能是最好的。
2.4 重写机制
随着命令不断写入AOF,文件会越来越大(redis重启后需要读取aof内容,太大的话肯定影响效率),为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积。AOF文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF文件。重写后的 AOF为什么可以变小?有如下原因:
- 进程内已超时的数据不再写入文件。
- 旧的 AOF 中的无效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本。
- 多条写操作合并为一条,例如lpush list a、lpush listb、lpush list 从可以合并为 lpush list a b c.
整体的思想就是剔除其中冗余的操作,并且合并一些操作(记录最终状态),能够达到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重写时,就会通过运行流程来执行重写。2.5节所示
2.5 AOF重写流程
2.6 启动时数据恢复
当Redis启动的时候,会根据RDB和AOF文件的内容,进行数据恢复。
3. 总结
1. RDB(Redis Database)快照
优点
- 性能影响较小:RDB持久化的过程由Redis在后台子进程执行,因此对主进程的读写性能影响较小。
- 数据恢复速度快:由于RDB文件是一个紧凑的二进制文件,可以快速加载到内存中,因此数据恢复速度通常比AOF更快。
- 适用于定期备份:RDB文件是完整的数据快照,适合用于定期全量备份,便于长期数据保存和迁移。
缺点
- 数据丢失风险较高:RDB是定期执行的(默认每5分钟或1小时执行一次,视配置而定),因此在两次快照之间的数据将会丢失。如果Redis在快照完成之前崩溃,会导致最新的数据丢失。
- 不灵活:RDB持久化只能定期执行,无法根据实际业务需求灵活地设置持久化频率。
2. AOF(Append-Only File)
优点
- 数据丢失风险低:AOF记录每个写操作的日志,并支持多种同步策略(如每次写操作、每秒写操作、操作系统自动同步等),可以实现较高的数据持久化频率,最大程度减少数据丢失。
- 更可控的持久化机制:AOF提供多种同步方式,用户可以根据性能与数据安全的需求调整同步频率,获得灵活的持久化控制。
- 文件内容可读:AOF文件是以Redis命令格式保存的,具有可读性,方便用户对数据进行恢复和诊断。
缺点
- 文件体积大:由于AOF会记录每一条写操作指令,随着时间的推移,文件会比RDB大得多,导致持久化文件占用大量磁盘空间。
- 数据恢复速度较慢:AOF文件在恢复时需要逐条执行日志中的命令,因此恢复速度通常比RDB慢。
- 对性能影响更大:频繁的写操作会导致性能开销,尤其是在设置为“每次写操作”同步时,对Redis的性能影响较大。
总结
- RDB适用于:希望最小化对Redis性能影响、对数据持久化频率要求不高,或者需要定期备份的场景。
- AOF适用于:对数据持久性要求高,不能接受较多数据丢失的场景,但需要注意性能和磁盘空间的占用。