Redis 是一个内存数据库,所以其运行效率非常高。但也存在一个问题:内存中的数据是不持久的,若主机宕机或 Redis 关机重启,则内存中的数据全部丢失。当然,这是不允许的。Redis 具有持久化功能,其会按照设置以快照或操作日志的形式将数据持久化到磁盘。
持久化的分类与优先级
根据持久化使用技术的不同,Redis 的持久化分为两种:RDB 与 AOF。
RDB 是默认持久化方式,但 Redis 允许 RDB 与 AOF 两种持久化技术同时开启,此时系统会使用 AOF 方式做持久化,即 AOF 持久化技术的优先级要更高。同样的道理,两种技术同时开启状态下,系统启动时若两种持久化文件同时存在,则优先加载 AOF 持久化文件。
RDB 与 AOF 对比
RDB 优势与不足
RDB 优势
- RDB 文件较小
- 数据恢复较快
RDB 不足
- 数据安全性较差
- 写时复制会降低性能
- RDB 文件可读性较差
AOF 优势与不足
AOF 优势
- 数据安全性高
- AOF 文件可读性强
AOF 不足
- AOF 文件较大
- 写操作会影响性能
- 数据恢复较慢
持久化技术选型
官方推荐使用 RDB 与 AOF 混合式持久化。
若对数据安全性要求不高,则推荐使用纯 RDB 持久化方式。
不推荐使用纯 AOF 持久化方式。
若 Redis 仅用于缓存,则无需使用任何持久化技术。
RDB 持久化
RDB,Redis DataBase,是指将内存中某一时刻的数据快照全量写入到指定的 rdb 文件的持久化技术。RDB 持久化默认是开启的。当 Redis 启动时会自动读取 RDB 快照文件,将数据从硬盘载入到内存,以恢复 Redis 关机前的数据库状态。
RDB持久化的执行
RDB 持久化的执行有三种方式:手动 save 命令、手动 bgsave 命令,与自动条件触发。
- 通过在 redis-cli 客户端中执行 save 命令可立即进行一次持久化保存。save 命令在执行期间会阻塞 redis-server 进程,直至持久化过程完毕。而在 redis-server 进程阻塞期间,Redis不能处理任何读写请求,无法对外提供服务。
- 通过在 redis-cli 客户端中执行 bgsave 命令可立即进行一次持久化保存。不同于 save 命令的是,正如该命令的名称一样,background save,后台运行 save。bgsave 命令会使服务器进程 redis-server 生成一个子进程,由该子进程负责完成保存过程。在子进程进行保存过程中,不会阻塞 redis-server 进程对客户端读写请求的处理。
- 自动条件触发的本质仍是 bgsave 命令的执行。只不过是用户通过在配置文件中做相应的设置后,Redis 会根据设置信息自动调用 bgsave 命令执行。
127.0.0.1:6379> bgsave
Background saving started
bgsave子进程的工作原理
由于子进程可以继承父进程的所有资源,且父进程不能拒绝子进程的继承权。所以,bgsave 子进程有权读取到 redis-server 进程写入到内存中的用户数据,使得将内存数据持久化到 dump.rdb 成为可能。
bgsave 子进程在持久化时首先会将内存中的全量数据 copy 到磁盘中的一个 RDB 临时文件,copy 结束后,再将该文件 rename 为 dump.rdb,替换掉原来的同名文件。
不过,在进行持久化过程中,如果 redis-server 进程接收到了用户写请求,则系统会将内存中发生数据修改的物理块 copy 出一个副本。等内存中的全量数据 copy 结束后,会再将副本中的数据 copy 到 RDB 临时文件。这个副本的生成是由于 Linux 系统的写时复制技术(Copy-On-Write)实现的。
查看持久化时间
通过 lastsave 命令可以查看最近一次执行持久化的时间,其返回的是一个 Unix 时间戳。
127.0.0.1:6379> lastsave
(integer) 1673711654
RDB配置相关
RDB的配置在redis.conf中的 SNAPSHOTTING 版块中。
# 默认配置
# 每3600秒期间执行过一次写入,每300秒期间执行过100次写入,每60秒期间执行过10000次写入,即条件触发bgsave命令执行持久化
# 如果不启用RDB持久化,只需设置 save 的参数为空串即可:save ""
# save 3600 1 300 100 60 10000
# 当条件触发的bgsave命令持久化失败,redis将停止写入,以提醒使用者,当bgsave正常执行后写入也会自动恢复。
# 如果有配置了redis持久化的监控,可以关闭该配置
stop-writes-on-bgsave-error yes
# 转储rdb数据文件时是否压缩,如果不压缩该文件可能会很大,压缩会消耗一些cpu资源
rdbcompression yes
# 从RDB5开始,RDB文件的CRC64校验和就被放置在了文件末尾。这使格式更能抵抗RDB文件的损坏,但在保存和加载RDB文件时,性能会受到影响(约10%),因此可以设置为no禁用校验和以获得最大性能。在禁用校验和的情况下创建的RDB文件的校验和为零,这将告诉加载代码跳过校验检查。默认为 yes,开启了校验功能。
# 建议默认
rdbchecksum yes
# 该配置用于设置在加载 RDB 文件或进行持久化时是否开启对 zipList、listPack 等数据的全面安全检测。该检测可以降低命令处理时发生系统崩溃的可能。其可设置的值有三种选择:
· no:不检测
· yes:总是检测
· clients:只有当客户端连接时检测。排除了加载 RDB 文件与进行持久化时的检测。
# 默认值本应该是 clients,但其会影响 Redis 集群的工作,所以默认值为 no,不检测。
# 建议默认
# sanitize-dump-payload no
# 指定RDB文件的默认名称,默认为 dump.rdb
dbfilename dump.rdb
# 主从复制时,是否删除用于同步的从机上的RDB文件。默认是 no,不删除。不过需要注意,只有当从机的RDB和AOF持久化功能都未开启时才生效。
rdb-del-sync-files no
# 指定RDB与AOF文件的生成目录。默认为redis-server所在目录。
# 注意,必须在此处指定目录,而不是文件名。
dir ./
AOF 持久化
AOF,Append Only File,是指 Redis 将每一次的写操作都以日志的形式记录到一个 AOF文件中的持久化技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之前的内存数据状态。
AOF配置相关
AOF的配置在redis.conf中的 APPEND ONLY MODE 版块中。
# 默认配置
# 默认情况下 AOF 持久化是没有开启的,通过修改配置文件中的 appendonly 属性为 yes可以开启。
appendonly no
# AOF文件名配置
appendfilename "appendonly.aof"
# Redis 7 在这里发生了重大变化。原来只有一个 appendonly.aof 文件,现在具有了三类多个文件:
· 基本文件:可以是 RDF 格式也可以是 AOF 格式。其存放的内容是由 RDB 转为 AOF 当时内存的快照数据。该文件可以有多个。
· 增量文件:以操作日志形式记录转为 AOF 后的写入操作。该文件可以有多个。
· 清单文件:用于维护 AOF 文件的创建顺序,保障激活时的应用顺序。该文件只有一个。
# 如果appendfilename设置为默认的appendonly.aof,则以上三类文件的文件名:
· appendonly.aof.1.base.rdb作为基本文件
· appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof作为增量文件
· appendonly.aof.manifest作为清单文件
# AOF 持久化文件指定存放目录,默认为redis-server所在目录,默认配置会在该目录下自动创建appendonlydir目录。
appenddirname "appendonlydir"
# AOF 写入的三种模式
· always 表示每次写入都执行fsync,以保证数据同步到磁盘,慢,但是最安全。
· everysec 表示每秒执行一次fsync,可能会导致丢失这1s数据,每秒写一次。
· no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
appendfsync everysec
# 自动重写AOF文件,Redis能够通过 BGREWRITEAOF 自动重写AOF日志文件。
# auto-aof-rewrite-percentage设置指定百分比,默认100%,指定为 0,表示禁用自动 rewrite。
# auto-aof-rewrite-min-size设置允许重写的最小AOF文件大小,默认 64M。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 如果设置为yes,如果一个因异常被截断的AOF文件被redis启动时加载进内存,redis将会发送日志通知用户
# 如果设置为no,rerdis将会拒绝启动。此时需要用"redis-check-aof"工具修复文件。
aof-load-truncated yes
# 混合式持久化开启
# 对于基本文件可以是 RDF 格式也可以是 AOF 格式。通过 aof-use-rdb-preamble 属性可以选择。其默认值为 yes,即默认 AOF 持久化的基本文件为 rdb 格式文件,也就是默认采用混合式持久化。
aof-use-rdb-preamble yes
# 支持在AOF中记录时间戳,可以在特定时间恢复数据,但会改变AOF格式,可能跟已经存在的AOF文件不兼容。
aof-timestamp-enabled no
AOF 文件格式
AOF 文件包含三类文件:基本文件、增量文件与清单文件。其中基本文件一般为 rdb 格式,就是 rdb 持久化的数据文件。下面主要是增量文件与清单文件的内容格式。
Redis 协议
增量文件扩展名为.aof,采用 AOF 格式。AOF 格式其实就是 Redis 通讯协议格式,AOF持久化文件的本质就是基于 Redis 通讯协议的文本,将命令以纯文本的方式写入到文件中。
Redis 协议规定,Redis 文本是以行来划分,每行以\r\n 行结束。每一行都有一个消息头,以表示消息类型。消息头由六种不同的符号表示,其意义如下:
- ( + ) 表示一个正确的状态信息
- ( - ) 表示一个错误信息
- ( * ) 表示消息体总共有多少行,不包括当前行
- ( $ ) 表示下一行消息数据的长度,不包括换行符长度\r\n
- ( 空 ) 表示一个消息数据
- ( : ) 表示返回一个数值
查看 AOF 文件
打开 appendonly.aof.1.incr.aof 文件,可以看到如下格式内容
cat /usr/local/bin/appendonlydir/appendonly.aof.1.incr.aof
*2
$6
SELECT
$1
1
*3
$3
set
$4
test
$5
hello
以上内容中是两条条命令,一条数据库切换命令 SELECT 1,一条 set 命令。它们的意义如下:
*2 -- 表示当前命令包含2个参数
$6 -- 表示第1个参数包含6个字符
SELECT -- 第1个参数
$1 -- 表示第 2 个参数包含1个字符
0 -- 第 2 个参数
*3 --表示当前命令包含3个参数
$3 -- 表示第1个参数包含3个字符
set -- 第1个参数
$4 -- 表示第2个参数包含4个字符
test -- 第2个参数
$5 -- 表示第3个参数包含5个字符
hello -- 第3个参数
清单文件
打开清单文件 appendonly.aof.manifest,查看其内容如下:
# cat /usr/local/bin/appendonlydir/appendonly.aof.manifest
file appendonly.aof.1.base.rdb seq 1 type b
file appendonly.aof.1.incr.aof seq 1 type i
该文件首先会按照 seq 序号列举出所有基本文件,基本文件 type 类型为 b,然后再按照seq 序号再列举出所有增量文件,增量文件 type 类型为 i。
对于 Redis 启动时的数据恢复,也会按照该文件由上到下依次加载它们中的数据。
Rewrite 机制
Redis 引入了 Rewrite 机制来对 AOF 文件进行压缩,所谓 Rewrite 其实就是对 AOF 文件进行重写整理。当 Rewrite 开启后,主进程 redis-server 创建出一个子进程 bgrewriteaof,由该子进程完成 rewrite 过程。其首先对现有 aof 文件进行rewrite 计算,将计算结果写入到一个临时文件,写入完毕后,再 rename 该临时文件为原 aof 文件名,覆盖原有文件。
rewrite 计算
rewrite 计算也称为 rewrite 策略。rewrite 计算遵循以下策略:
- 读操作命令不写入文件
- 无效命令不写入文件
- 过期数据不写入文件
- 多条命令合并写入文件
手动开启 rewrite
使用 bgrewriteaof 命令,该命令会使主进程 redis-server 创建出一个子进程 bgrewriteaof,由该子进程完成 rewrite 过程。而在 rewrite 期间,redis-server 仍是可以对外提供读写服务的。
127.0.0.1:6379[1]> bgrewriteaof
Background append only file rewriting started
自动开启 rewrite
配置文件是默认开启的,可以修改其值
- auto-aof-rewrite-percentage:开启 rewrite 的增大比例,默认 100%。指定为 0,表示禁用自动 rewrite。
- auto-aof-rewrite-min-size:开启 rewrite 的 AOF 文件最小值,默认 64M。该值的设置主要是为了防止小 AOF 文件被 rewrite,从而导致性能下降。