前言
持久化就是将Redis内存中的数据写入到磁盘中进行存储,因为Redis是内存数据库,数据都是存在内存中的,为了避免进程退出导致数据的丢失,所以需要将数据持久化到硬盘中,这样下次Redis重启后可以利用之前持久化的文件实现数据恢复。
一般有两种持久化方式:
- 快照 : Redis RDB
- 写日志: Redis AOF
下面对这两种方式一一进行详细阐述,关于更多Redis持久化深入介绍,可以拜读 Redis持久化的经典之作——Redis persistence demystified
RDB
RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,文件格式是二进制文件,这种利用快照方式保存数据,其实在很多领域都比较常见,比如云服务器备份数据,MySQL备份数据等等。
触发RDB持久化过程一般分为两种方式:
- 手动触发
- 自动触发
手动触发
手动触发又分别有两种命令:
- save命令:阻塞当前的Redis服务器,直到RDB过程完成为止
- bgsave命令(主流的触发RDB持久化方式): Redis 进程执行 fork操作创建子进程,RDB 持久化由子进程负责,完成后自动结束,阻塞只发生在 fork 阶段
save命令1
2127.0.0.1:6379> save
OK
执行 save
命令阻塞当前Redis,然后完成时返回一个 OK
bgsave
bgsave的执行流程如下图(出自《Redis开发与运维》):
- 执行 bgsave 命令,Redis 父进程 判断当前是否存在正在执行的子进程,如 RDB/AOF子进程,如果存在 bgsave 命令直接返回
- 父进程执行 fork 操作创建子进程,fork操作过程中父进程会阻塞,通过
info stats
命令 查看latest_fork_usec
选项,可以获取最近一个 fork 操作的耗时,单位是 微秒 - 父进程 fork 完成后,bgsave 命令 返回
Background saving started
信息并不会阻塞父进程,可以继续响应其他命令 - 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换
- 进程发送信号给父进程表示完成,父进程更新统计信息
自动触发
自动触发机制一般是在配置文件中使用 save m n
,表示 m 秒内数据集存在 n 次 修改时,自动触发 bgsave
,redis 默认的自动触发机制如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
比如 save 900 1
就表示当时间到 900s 时,如果Redis数据至少发生了一次修改,那么就会执行 bgsave
RDB的相关配置
在 redis.conf
有一系列关于 RDB的相关配置,如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# 快照的文件名
dbfilename dump.rdb
# 存放快照的目录
dir ./
# 在进行快照备份时,是否进行压缩。
# yes:压缩,但是需要一些cpu的消耗。
# no:不压缩,需要更多的磁盘空间。
rdbcompression yes
# 是否开启RDB文件的校验,在写入文件和读取文件时都起作用,关闭时,写入和启动文件有大约10%的性能提升,但无法检查RDB的损坏情况
rdbchecksum yes
#自动触发
#900秒后且至少1个key发生变化时创建快照
save 900 1
#300秒后且至少10个key发生变化时创建快照
save 300 10
#60秒后且至少10000个key发生变化时创建快照
save 60 10000
一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。例如,每隔5分钟或者更长的时间来创建一次快照,Redis停止工作时(例如意外断电)就可能丢失最近几分钟的数据。所以RDB 不适合实时持久化操作
其他机制
- 全量复制: 如果从节点执行全量复制,主节点自动执行 bgsave 命令 生成 RDB 文件并发送给从节点
- debug reload: 重新加载redis会触发 save操作
- shutdown命令: 如果没有开启 AOF 持久化功能则自动执行
bgsave
AOF
AOF (append only file) 持久化: 以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令以达到恢复数据的目的,类似于 MySQL binlog。
与 RDB 相比,AOF 的实时性更好。
开启AOF
在 redis.conf
配置文件中开启 AOF持久化1
2
3
4
5
6
7
8
9
10# 是否开启AOF,默认关闭(no)
appendonly yes
# AOF 文件名 (默认: "appendonly.aof")
appendfilename "appendonly.aof"
# 保存路径与 RDB 一样,可配置
dir ./
使用AOF流程:
- 命令写入(append): 所有的写入命令会追加到 aof_buf 缓冲区中
- 文件同步(sync): AOF 缓冲区根据对应的策略向硬盘做同步操作(sync)
- 文件重写(rewrite): 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的
- 重启加载(load): 当Redis重启时,加载AOF文件进行数据恢复
命令写入
Redis先把命令追加到 aof_buf
缓冲区中,该缓冲区是在系统的用户态缓冲区中,更具体的讲是在 Redis的缓冲内存中,缓冲内存主要包括: 客户端缓冲,复制积压缓冲区,AOF缓冲区。所以这里Redis实际上是将命令追加到AOF缓冲区。
之所以先写入缓冲区,是为了避免每次写 AOF 文件命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
AOF 命令写入的内容直接是文本协议格式,一种Redis制定的文本协议,详情请查阅相关资料。它是一种纯文本格式,具有很好的兼容性,开启AOF后,所有写入命令都包含追加操作,直接采用 协议格式,避免了二次处理开销。
文件同步方式
文件同步本质上将在用户态缓冲区(具体说是AOF缓冲区)中的数据 通过System call 刷入到操作系统的内核态中,进入刷入硬盘中去。
其实涉及的两个重要的系统调用(System Call):
- write: 通过 write 系统调用,将数据写入到内核缓冲区中后直接返回,后面的工作交由操作系统将内核缓冲区的数据写入硬盘,这样的好处是提高了IO性能
- fsync:通过 fsync 系统调用 将数据提交到硬盘中,强制硬盘同步,将一直阻塞到写入硬盘完成后返回
而文件同步又有三种策略,可在 redis.conf
配置文件中进行配置:
appendfsync always
: 单纯靠调用fsync
将数据刷入到硬盘,是最有保证的完全的持久化,但速度也是最慢的,因为fsync
存在阻塞,一般不推荐使用。appendfsync everysec
: 每隔一秒钟,数据会通过write写入到内核缓冲完成后返回。为了进一步保证持久化,又专门后台开一个线程通过fsync将数据刷新到磁盘,以避免内核缓冲内数据因系统故障宕机丢失。在性能和持久化方面做了很好的折中,是受推荐的方式。appendfsync no
: 通过write系统调用将数据写入到内核缓存,然后依赖OS的写入,将数据从内核缓存写入到硬盘,一般为30秒左右一次。性能最好但是持久化最没有保证,不被推荐,如果有系统宕机故障,最近30秒的数据有可能丢失
重写机制
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。 经过重写,比如多条命令合并成一条命令等操作,然后重写后的AOF文件可以变小,以便更快被Redis加载
AOF重写过程分为手动触发和自动触发:
- 手动触发:直接调用
bgrewriteaof
命令 - 自动触发: 两大参数
auto-aof-rewrite-min-size
:表示运行 AOF重写时文件最小体积,默认为64MBauto-aof-rewrite-percentage
: AOF增长率,当前AOF文件空间和上一次重写后AOF文件空间的比值
在redis.conf
配置文件中,自动触发参数设置如下:1
2
3#当AOF增长率为100%且达到了64mb时开始自动重写AOF
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
重新加载
Redis 持久化文件加载流程如下,如果 RDB 与 AOF同时开启,优先使用 AOF (下图摘自《Redis开发与运维》):