Redis进阶-持久化机制
Redis 持久化机制
Redis是一个支持持久化的内存数据库,也就是说 redis 需要经常将内存中的数据同步到硬盘来保证持久化
Redis持久化主要分为两种方式,分别是RDB和AOF,当然实际场景下还会使用这两种的混合模式
前言
Redis的数据正常都是存储在内存内,如果宕机突然发生,数据就会全部丢失,因此需要提供一种方式保证 redis 的数据不会因为故障而丢失,这种机制就是 redis 的持久化机制
目前 Redis 主流的持久化机制有两种:RDB 方式 和 AOF 方式
RDB 持久化
RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为 手动触发 和 自动触发
手动触发
手动触发分别对应 save 和 bgsave 命令
- save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用
- bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短
bgsave 命令是针对 save 阻塞问题做的优化,因此Redis内部所有涉及到RDB操作都采用 bgsave 的方式,而
save命令可以废弃
bgsave流程图如下所示👇
具体流程如下:
- redis 客户端执行 bgsave 命令或者自动触发bgsave命令;
- 主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回;
- 如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;
- 子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
- 同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)
自动触发
在以下4种情况时会自动触发
redis.conf中配置
save m n
,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;
执行 debug reload 命令重新加载 redis 时也会触发bgsave操作;
默认情况下执行shutdown命令时,如果没有开启 aof持久化,那么也会触发bgsave操作
redis.conf中配置RDB
- 配置设置自动做快照持久化方式
# 周期性执行条件的设置格式为
save <seconds> <changes>
# 默认的设置为:
save 900 1
save 300 10
save 60 10000
# 以下设置方式为关闭RDB快照功能
save ""
以上三项默认信息设置代表的意义是:
- 如果900秒内有1条Key信息发生变化,则进行快照;
- 如果300秒内有10条Key信息发生变化,则进行快照;
- 如果60秒内有10000条Key信息发生变化,则进行快照。读者可以按照这个规则,根据自己的实际请求压力进行设置调整
# 文件名称
dbfilename dump.rdb
# 文件保存路径
dir /home/work/app/redis/data/
# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes
# 是否压缩
rdbcompression yes
# 导入时是否检查
rdbchecksum yes
dbfilename: 配置文件名,可以通过执行
config set dir {newDir}
和config set dbfilename {newFileName}
运行期动态执行,当下次运行时RDB文件会保存到新目录dir: 可以通过执行
config set dir {newDir}
和config set dbfilename {newFileName}
运行期动态执行,当下次运行时RDB文件会保存到新目录压缩: Redis默认采用 LZF算法 对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数
config set rdbcompression {yes|no}
动态修改。校验: 如果Redis加载损坏的RDB文件时拒绝启动,这个功能大概会多损失10%左右的性能,但获得了更高的数据可靠性。所以如果您的Redis服务需要追求极致的性能,就可以将这个选项设置为 no
RDB 的优缺点
优点:
- RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景
- Redis加载RDB文件恢复数据要远远快于AOF方式
缺点:
- RDB方式实时性不够,无法做到秒级的持久化;
- 每次调用bgsave都需要fork子进程,fork子进程属于重量级操作,频繁执行成本较高;
- RDB文件是二进制的,没有可读性,AOF文件在了解其结构的情况下可以手动修改或者补全;
- 版本兼容RDB文件问题
针对RDB不适合实时持久化的问题,Redis提供了 AOF持久化 方式来解决
AOF 持久化
AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。
AOF的主要作用是解决了数据持久化的实时性,目前已经是 Redis持久化的主流方式
而AOF日志采用写后日志,即 先写内存,后写日志
Redis要求高性能,采用写日志有两方面好处:
- 避免额外的检查开销:Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查。所以,如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,Redis 在使用日志恢复数据时,就可能会出错。
- 不会阻塞当前的写操作
但这种方式存在潜在风险:
- 如果命令执行完成,写日志之前宕机了,会丢失数据。
- 主线程写磁盘压力大,导致写盘慢,阻塞后续操作
如何实现 AOF
AOF日志记录Redis的每个写命令,步骤分为:命令追加(append)、文件写入(write)和文件同步(sync)
命令追加 当AOF持久化功能打开了,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的 aof_buf 缓冲区。
文件写入和同步 关于何时将 aof_buf 缓冲区的内容写入AOF文件中,Redis提供了三种写回策略
- Always - 同步写回:每个写命令执行完,立马同步地将日志写回磁盘
Everysec(推荐)
- 每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘- No - 操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘(不推荐)
Conf 配置AOF
默认情况下,Redis是没有开启AOF的,可以通过配置redis.conf文件来开启AOF持久化,关于AOF的配置如下:
# appendonly参数开启AOF持久化
appendonly no
# AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof"
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./
# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no
# aof重写期间是否同步
no-appendfsync-on-rewrite no
# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加载aof出错如何处理
aof-load-truncated yes
# 文件重写策略
aof-rewrite-incremental-fsync yes
以下是Redis中关于AOF的主要配置信息:
appendonly
:默认情况下AOF功能是关闭的,将该选项改为yes以便打开Redis的AOF功能。appendfilename
:这个参数项很好理解了,就是AOF文件的名字appendfsync
:这个参数项是AOF功能最重要的设置项之一,主要用于设置操作命令向AOF文件中同步的策略
RDB和AOF混合方式
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作
这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了
这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势, 实际环境中用的很多