redis(二) 数据持久化-两种方式 :RDB和AOF

Redis提供了将数据定期自动持久化至硬盘的能力,包括RDB和AOF两种方案,两种方案分
别有其长处和短板,可以配合起来同时运行,确保数据的稳定性。
必须使用数据持久化吗?
Redis的数据持久化机制是可以关闭的。如果你只把Redis作为缓存服务使用,Redis中存
储的所有数据都不是该数据的主体而仅仅是同步过来的备份,那么可以关闭Redis的数据持
久化机制。
但通常来说,仍然建议至少开启RDB方式的数据持久化,因为: fork(分出)进程
•RDB方式的持久化几乎不损耗Redis本身的性能,在进行RDB持久化时,Redis主进程唯一
需要做的事情就是fork出一个子进程,所有持久化工作都由子进程完成
•Redis无论因为什么原因crash掉之后,重启时能够自动恢复到上一次RDB快照中记录的
数据。这省去了手工从其他数据源(如DB)同步数据的过程,而且要比其他任何的数据恢
复方式都要快
•现在硬盘那么大,真的不缺那一点地方

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RDB(默认)

1.原理

RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据备份。非常适合备份,全量复制等场景。比如每6小时执行 bgsave 备份,并把 RDB 文件拷贝到远程机器或者文件系统中,用于灾难恢复。
采用RDB持久方式,Redis会定期保存数据快照至一个rbd文件中,并在启动时自动加载
rdb文件,恢复之前保存的数据。可以在配置文件中配置Redis进行快照保存的时机:
save [seconds] [changes] 
意为在[seconds]秒内如果发生了[changes]次数据修改,则进行一次RDB快照保存,例
如
	save 60 100 
	会让Redis每60秒检查一次数据变更情况,如果发生了100次或以上的数据变更,则进行
	RDB快照保存。
可以配置多条save指令,让Redis执行多级的快照保存策略。
Redis默认开启RDB快照,默认的RDB策略如下:
	save 900 1 
	save 300 10 
	save 60 10000 
也可以通过BGSAVE命令手工触发RDB快照保存。

RDB的优点:
	•对性能影响最小。如前文所述,Redis在保存RDB快照时会fork出子进程进行,几乎
	不影响Redis处理客户端请求的效率。
	•每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照
	(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段。
	•使用RDB文件进行数据恢复比使用AOF要快很多。

RDB的缺点:
	•快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据。
	•RDB 方式数据没办法做到实时持久化,而 AOF 方式可以做到。
	•如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间(长至1秒),影响这期间的客户端请求。

在这里插入图片描述

什么时候fork子线程,或者什么时候出发rdb持久化机制
1.shut down(关闭redis实例) ,且没有开启AOP, 会触发
2.配置文件中默认使用RDB,执行save命令或bgsave命令, 
 save(例如save 300 10)只管保存存在阻塞.  
 bgsave:redis会在后台进行异步快照操作,同时还能够响应客户端请求.
3.执行Flushall 命令,但是rdb文件是空的,毫无意义.
(Redis Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key ))

AOF

1.原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

采用AOF持久方式时,Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。

AOF 持久化的实现

在这里插入图片描述

AOF 持久化功能的实现可以分为命令追加( append )、文件写入( write )、文件同步
(sync)、文件重写(rewrite)和重启加载(load)。其流程如下:
	所有的写命令会追加到 AOF 缓冲中。
	AOF 缓冲区根据对应的策略向硬盘进行同步操作。
	随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
	当 Redis 重启时,可以加载 AOF 文件进行数据恢复。
命令追加
当 AOF 持久化功能处于打开状态时,Redis 在执行完一个写命令之后,会以协议格式(也
就是RESP,即 Redis 客户端和服务器交互的通信协议 )将被执行的写命令追加到 Redis 
服务端维护的 AOF 缓冲区末尾。
比如说 SET mykey myvalue 这条命令就以如下格式记录到 AOF 缓冲中。
1.	"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"
Redis 协议格式本文不再赘述,AOF之所以直接采用文本协议格式,是因为所有写入命令都要进行追加操作,直接采用协议格式,避免了二次处理开销。
文件写入和同步
Redis 每次结束一个事件循环之前,它都会调用 flushAppendOnlyFile 函数,判断是
否需要将 AOF 缓存区中的内容写入和同步到 AOF 文件中。
flushAppendOnlyFile 函数的行为由 redis.conf 配置中的 appendfsync 选项的值
来决定。该选项有三个可选值,分别是 always、 everysec 和 no:
1.always:Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件,
并且同步 AOF 文件,所以 always 的效率是 appendfsync 选项三个值当中最差的一
个,但从安全性来说,也是最安全的。当发生故障停机时,AOF 持久化也只会丢失一个          事件循环中所产生的命令数据。

2.everysec:Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件
中,并且每隔一秒就要在子线程中对 AOF 文件进行一次同步。从效率上看,该模式足够
快。当发生故障停机时,只会丢失一秒钟的命令数据。

3.no:Redis 在每一个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件。而
 AOF 文件的同步由操作系统控制。这种模式下速度最快,但是同步的时间间隔较长,出现
 故障时可能会丢失较多数据。

Linux 系统下 write 操作会触发延迟写( delayed write )机制。Linux 在内核提
供页缓存区用来提供硬盘 IO 性能。write 操作在写入系统缓冲区之后直接返回。同步硬
盘操作依赖于系统调度机制,例如:缓冲区页空间写满或者达到特定时间周期。同步文件
之前,如果此时系统故障宕机,缓冲区内数据将丢失。而 fsync 针对单个文件操作,对
其进行强制硬盘同步, fsync 将阻塞直到写入磁盘完成后返回,保证了数据持久化。
appendfsync的三个值代表着三种不同的调用 fsync的策略。调用 fsync周期越频繁,
读写效率就越差,但是相应的安全性越高,发生宕机时丢失的数据越少。
AOF 数据恢复

AOF 文件里边包含了重建 Redis 数据所需的所有写命令,所以 Redis 只要读入并重新执行一遍 AOF 文件里边保存的写命令,就可以还原 Redis 关闭之前的状态。
在这里插入图片描述

Redis 读取 AOF 文件并且还原数据库状态的详细步骤如下:
	创建一个不带网络连接的的伪客户端( fake client),因为 Redis 的命令只能在
客户端上下文中执行,而载入 AOF 文件时所使用的的命令直接来源于 AOF 文件而不是网
络连接,所以服务器使用了一个没有网络连接的伪客户端来执行 AOF 文件保存的写命令,
1.伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样的。
从 AOF 文件中分析并取出一条写命令。
2.使用伪客户端执行被读出的写命令。
3.一直执行步骤 2 和步骤3,直到 AOF 文件中的所有写命令都被处理完毕为止。
当完成以上步骤之后,AOF 文件所保存的数据库状态就会被完整还原出来。
AOF 重写
因为 AOF 持久化是通过保存被执行的写命令来记录 Redis 状态的,所以随着 Redis 长
时间运行,AOF 文件中的内容会越来越多,文件的体积也会越来越大,如果不加以控制的
话,体积过大的 AOF 文件很可能对 Redis 甚至宿主计算机造成影响。
为了解决 AOF 文件体积膨胀的问题,Redis 提供了 AOF 文件重写( rewrite) 功能。
通过该功能,Redis 可以创建一个新的 AOF 文件来替代现有的 AOF 文件。新旧两个
AOF 文件所保存的 Redis 状态相同,但是新的 AOF 文件不会包含任何浪费空间的荣誉
命令,所以新 AOF 文件的体积通常比旧 AOF 文件的体积要小得很多。

在这里插入图片描述

如上图所示,重写前要记录名为 list的键的状态,AOF 文件要保存五条命令,而重写
后,则只需要保存一条命令。
AOF 文件重写并不需要对现有的 AOF 文件进行任何读取、分析或者写入操作,而是通过
读取服务器当前的数据库状态来实现的。首先从数据库中读取键现在的值,然后用一条命
令去记录键值对,代替之前记录这个键值对的多条命令,这就是 AOF 重写功能的实现原
理。
在实际过程中,为了避免在执行命令时造成客户端输入缓冲区溢出,AOF 重写在处理列
表、哈希表、集合和有序集合这四种可能会带有多个元素的键时,会先检查键所包含的元
素数量,如果数量超过 REDISAOFREWRITEITEMSPER_CMD ( 一般为64 )常量,则使用多
条命令记录该键的值,而不是一条命令。

rewrite的触发机制主要有一下三个:
1.手动调用 bgrewriteaof 命令,如果当前有正在运行的 rewrite 子进程,则本次
rewrite 会推迟执行,否则,直接触发一次 rewrite。
2.通过配置指令手动开启 AOF 功能,如果没有 RDB 子进程的情况下,会触发一次
 rewrite,将当前数据库中的数据写入 rewrite 文件。
3.在 Redis 定时器中,如果有需要退出执行的 rewrite 并且没有正在运行的 RDB 
或者 rewrite 子进程时,触发一次或者 AOF 文件大小已经到达配置的 rewrite 条件
也会自动触发一次。
AOF 后台重写
AOF 重写函数会进行大量的写入操作,调用该函数的线程将被长时间阻塞,
所以 Redis 在子进程中执行 AOF 重写操作。
1.子进程进行 AOF 重写期间,Redis 进程可以继续处理客户端命令请求。
3.子进程带有父进程的内存数据拷贝副本,在不适用锁的情况下,也可以保证数据的安全
性。
但是,在子进程进行 AOF 重启期间,Redis接收客户端命令,会对现有数据库状态进行
修改,从而导致数据当前状态和 重写后的 AOF 文件所保存的数据库状态不一致。
为此,Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在服务器创建子进程之后开始使
用,当 Redis 执行完一个写命令之后,它会同时将这个写命令发送给 AOF 缓冲区和
 AOF 重写缓冲区。

在这里插入图片描述

当子进程完成 AOF 重写工作之后,它会向父进程发送一个信号,父进程在接收到该信号之
后,会调用一个信号处理函数,并执行以下工作:
1.将 AOF 重写缓冲区中的所有内容写入到新的 AOF 文件中,保证新 AOF 文件保存的数
据库状态和服务器当前状态一致。
2.对新的 AOF 文件进行改名,原子地覆盖现有 AOF 文件,完成新旧文件的替换
3.继续处理客户端请求命令。
在整个 AOF 后台重写过程中,只有信号处理函数执行时会对 Redis 主进程造成阻塞,在
其他时候,AOF 后台重写都不会阻塞主进程。
AOF默认是关闭的,如要开启,进行如下配置:
fsync :数据, 把文件在内存中的部分写回磁盘, 帧同步脉冲
appendonly yes 
AOF提供了三种fsync配置,always/everysec/no,通过配置项[appendfsync]指定:
	•appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快
	•appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢
	•appendfsync everysec:折中的做法,交由后台线程每秒fsync一次
	随着AOF不断地记录写操作日志,必定会出现一些无用的日志,例如某个时间点执行
	了命令SET key1 "abc",在之后某个时间点又执行了SET key1 "bcd",那么第一
	条命令很显然是没有用的。大量的无用日志会让AOF文件过大,也会让数据恢复的时
	间过长。所以Redis提供了AOF rewrite功能,可以重写AOF文件,只保留能够把数
	据恢复到最新状态的最小写操作集。
AOF rewrite可以通过BGREWRITEAOF命令触发,也可以配置Redis定期自动进行:
auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb 
上面两行配置的含义是,Redis在每次AOF rewrite时,会记录完成rewrite后的AOF日志大小,当AOF日志大小在该基础上增长了100%后,自动进行AOF rewrite。同时如果增长的大小没有达到64mb,则不会进行rewrite。
AOF的优点:
	•最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据。
	•AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。
	•AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
AOF的缺点:
	•AOF文件通常比RDB文件更大
	•性能消耗比RDB高
	•数据恢复速度比RDB慢

在这里插入图片描述

随着运行时间的增长,执行的命令越来越多,会导致AOF文件越来越大,当AOF文件过大
时,redis会执行重写机制来压缩AOF文件。这个压缩和上面提到的RDB文件的算法压缩不
同,重写机制主要是将文件中无效的命令去除。
比如:
	同一个key的值,只保留最后一次写入
	已删除或者已过期数据相关命令会被去除
	这样就避免了,aof文件过大而实际内存数据小的问题(如频繁修改数据时,
	命令很多,实际数据很少)

重写的触发方式:
 手动执行 bgrewriteaof 触发AOF重写
 在redis.conf文件中配置重写的条件,如:

auto-aof-rewrite-min-size 64MB   // 当文件小于64M时不进行重写
auto-aof-rewrite-min-percenrage 100  // 当文件比上次重写后的文件
大100%时进行重写

重写的过程:

从主进程中fork出子进程,并拿到fork时的AOF文件数据写到一个临时AOF文件中
在重写过程中,redis收到的命令会同时写到AOF缓冲区和重写缓冲区中,这样保证重写不
丢失重写过程中的命令
重写完成后通知主进程,主进程会将AOF缓冲区中的数据追加到子进程生成的文件中
redis会原子的将旧文件替换为新文件,并开始将数据写入到新的aof文件上

关于重写机制需要注意以下几点:

执行重写时如果发现有进程正在执行重写,那么直接返回。如果有进程正在执行BGSAVE,
那么会等BGSAVE执行完成后再执行重写。
Redis执行重写时会fork一个进程进行,其开销和RDB一样
重写过程不影响原有的AOF过程,write,save操作都不影响
重写过程中有几种时刻会阻塞主进程: 在fork子进程时,将重写缓冲区的数据写到磁
盘上时,使用新AOF文件替换旧文件时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值