支持一下我的开源项目:开源项目
REDIS 持久化 RDB快照
Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。
RDB 持久化生成的 RDB 文件是一个经过压缩的二进制文件,也可以称之为快照文件,通过该文件可以还原生成 RDB 文件时的数据库状态。
在指定的时间间隔内,Redis 会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程就是「快照」。自动触发(bgsave)执行时,Redis会创建一个子进程进行执行RDB备份,执行完成后自动清除。
RDB持久化配置
# 根据 Redis 配置文件 redis.conf 中的配置自动进行快照。
# 当在规定的时间内,Redis发生了写操作的个数满足条件,会触发发生BGSAVE命令。
# save <seconds> <changes>
# 当用户设置了多个save的选项配置,只要其中任一条满足,Redis都会触发一次BGSAVE操作
save 900 1
save 300 10
# 以上配置的含义:900秒之内至少一次写操作、300秒之内至少发生10次写操作,只要满足任一条件,均会触发bgsave
RDB快照实现过程
- Redis 调用执行 fork 函数复制一份当前进程(父进程)的副本(子进程),也就是同时拥有父进程和子进程。
- 父进程与子进程各自分工,父进程继续处理来自客户端的命令请求,而子进程则将内存中的数据写到硬盘上的一个临时 RDB 文件中。
- 当子进程把所有数据写完后,也就表示快照生成完毕,此时旧的 RDB 文件将会被这个临时 RDB 文件替换,这个旧的 RDB 文件也会被删除。这个过程就是一次快照的实现过程。
-
当 Redis 调用执行 fork 函数时,操作系统会使用写时复制策略。也就是在执行 fork
函数的过程中,父、子进程共享同一内存数据,当父进程要修改某个数据时(执行一条写命令),操作系统会将这个共享内存数据另外复制一份给子进程使用,以此来保证子进程的正确运行。因此,新的
RDB 文件存储的是执行 fork 函数过程中的内存数据。 -
写时复制策略也保证了在执行 fork
函数的过程中生成的两份内存副本在内存中的占用量不会增加一倍。但是,在进行快照的过程中,如果写操作比较多,就会造成 fork
函数执行前后数据差异较大,此时会使得内存使用量变大。因为内存中不仅保存了当前数据库数据,还会保存 fork 过程中的内存数据。 -
在进行快照生成的过程中,Redis 不会修改 RDB 文件。只有当快照生成后,旧的 RDB 文件才会被临时 RDB 文件替换,同时旧的
RDB 文件会被删除。在整个过程中,RDB 文件是完整的,因此我们可以使用 RDB 文件来实现 Redis 数据库的备份。
RDB文件的创建
SAVE 命令: 会阻塞 Redis 服务器进程,此时 Redis 服务器将不能继续执行其他命令请求,直到 RDB 文件创建完毕为止。
BGSAVE 命令: 会派生出一个子进程,交由子进程将内存中的数据保存到硬盘中,创建 RDB 文件;而 BGSAVE
命令的父进程可以继续处理来自客户端的命令请求。 执行 BGSAVE 命令会返回 Background saving started
信息,但我们并不能确定 BGSAVE 命令是否已经成功执行,此时可以使用 LASTSAVE 命令来查看相关信息。 执行 LASTSAVE
命令返回一个 UNIX 格式的时间戳,表示最近一次 Redis 成功将数据保存到硬盘中的时间。
RDB文件压缩
在默认情况下,Redis 服务器会自动对 RDB 文件进行压缩。在 Redis 配置文件 redis.conf 中,默认开启压缩。配置如下:
自动压缩RDB快照
rdbcompression yes
Redis 采用 LZF 算法进行 RDB 文件压缩。在压缩 RDB 文件时,不要误认为是压缩整个 RDB 文件。实际上,对 RDB文件的压缩只是针对数据库中的字符串进行的,并且只有当字符串达到一定长度(20 字节)时才会进行压缩。
RDB 持久化的优劣
RDB 持久化优点:
RDB 文件是一个经过压缩的二进制文件,文件紧凑,体积较小,非常适用于进行数据库数据备份。
RDB 持久化适用于灾难恢复,而且恢复数据时的速度更快。
Redis 采用 RDB 持久化可以很大程度地提升性能。父进程在保存 RDB
文件时会启动一个子进程,将所有与保存相关的功能交由子进程处理,而父进程可以继续处理其他相关的操作。
RDB 持久化缺点:
- 在服务器出现故障时,如果没有触发 RDB 快照执行,那么它可能会丢失大量数据。RDB
快照的持久化方式决定了必然做不到实时持久化,会存在大量数据丢失。 - 当数据量非常庞大时,在保存 RDB 文件的时候,服务器会启动一个子进程来完成相关的保存操作。这项操作比较耗时,将会占用太多 CPU
时间,从而影响服务器的性能。