共计 5622 个字符,预计需要花费 15 分钟才能阅读完成。
丸趣 TV 小编给大家分享一下 Redis 中持久化机制是怎么样的,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
Redis 持久化机制
为什么要持久化
如果 Redis 再次访问时,发现 Redis 的数据是空的,就会形成缓存穿透。更重要的是,因为 Redis 的数据是空的,所以客户端想要访问的 key 都没有,就会造成大量的请求就会瞬间打到数据库上,造成缓存雪崩(少量的 key 是穿透,大量的 key 是雪崩)。
这个时候,数据库可能就挂掉。而又无法保证 redis 不宕机,所以需要当 redis 宕机后,迅速将里里面的内容恢复出来。因此需要做一个持久化。持久化是为了恢复数据用的,而不是存储数据用的。
RDB
RDB(Redis DataBase),是 Redis 默认的存储方式,RDB 方式是通过快照 (snapshotting) 完成的。
触发快照的方式
符合自定义配置的快照规则
save 900 1 # 表示 15 分钟 (900 秒钟) 内至少 1 个键被更改则进行快照。
save 300 10 # 表示 5 分钟 (300 秒) 内至少 10 个键被更改则进行快照。
save 60 10000 # 表示 1 分钟内至少 10000 个键被更改则进行快
N 秒内数据集至少有 M 个改动”这一条件被满足时,自动保存一次数据集。
执行 save 或者 bgsave 命令
执行命令 save 或 bgsave 可以生成 dump.rdb 文件,每次命令执行都会将所有 redis 内存快照到一个新的 rdb 文件里,并覆盖原有 rdb 快照文件。
save 与 bgsave 对比:
命令 savebgsaveIO 类型同步异步是否阻塞 redis 其它命令是否 (在生成子进程执行调用 fork 函数时会有短暂阻塞) 复杂度 O(n)O(n)优点不会消耗额外内存不阻塞客户端命令缺点阻塞客户端命令需要 fork 子进程,消耗内存
配置自动生成 rdb 文件后台使用的是 bgsave 方式。
执行 flushall
命令
flushall
清空 Redis 之前,保存当前 Redis 快照
执行主从复制操作 (第一次)
第一次主从复制时需要生成 rdb 文件,会保存当前 Redis 快照
RDB 执行流程
流程分析
父进程 fork 子进程后,继续工作。
子进程发送信号给父进程表示完成,父进程更新统计信息。
子进程创建 RDB 文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。(RDB 始终完整)
父进程 fork 后,bgsave 命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令。
父进程执行 fork(调用操作系统函数复制主进程)操作创建子进程,这个过程中父进程是阻塞的,Redis 不能执行来自客户端的任何命令。
Redis 父进程首先判断: 当前是否在执行 save 或 bgsave/bgrewriteaof(aof 文件重写命令)的子进程,如果在执行则 bgsave 命令直接返回。
RDB 文件结构
1、头部 5 字节固定为“REDIS”字符串
2、4 字节“RDB”版本号(不是 Redis 版本号),当前为 9,填充后为 0009
3、辅助字段,以 key-value 的形式
4、存储数据库号码
5、字典大小
6、过期 key
7、主要数据,以 key-value 的形式存储
8、结束标志
9、校验和,就是看文件是否损坏,或者是否被修改
RDB 的优缺点
优点
RDB 是二进制压缩文件,占用空间小,便于传输(传给 slaver)
主进程 fork 子进程,可以最大化 Redis 性能,主进程不能太大,复制过程中主进程阻塞
缺点
不保证数据完整性,会丢失最后一次快照以后更改的所有数据
AOF
AOF(append only file)是 Redis 的另一种持久化方式。Redis 默认情况下是不开启的。开启 AOF 持久化后,Redis 将所有对数据库进行过写入的命令 (及其参数)(RESP) 记录到 AOF 文件,以此达到记录数据库状态的目的,
这样当 Redis 重启后只要按顺序回放这些命令就会恢复到原始状态了。AOF 会记录过程,RDB 只管结果
AOF 持久化实现
配置 redis.conf
# 可以通过修改 redis.conf 配置文件中的 appendonly 参数开启
appendonly yes
# AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的。
dir ./
# 默认的文件名是 appendonly.aof,可以通过 appendfilename 参数修改
appendfilename appendonly.aof
AOF 原理
AOF 文件中存储的是 redis 的命令,同步命令到 AOF 文件的整个过程可以分为三个阶段:
命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。
缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加 到服务器的 AOF 缓存中。
文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话,fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。
命令传播
当一个 Redis 客户端需要执行命令时,它通过网络连接,将协议文本发送给 Redis 服务器。服务器在接到客户端的请求之后,它会根据协议文本的内容,选择适当的命令函数,并将各个参数从字符串文本转换为 Redis 字符串对象(StringObject)。每当命令函数成功执行之后,命令参数都会被传播到 AOF 程序。
缓存追加
当命令被传播到 AOF 程序之后,程序会根据命令以及命令的参数,将命令从字符串对象转换回原来的协议文本。协议文本生成之后,它会被追加到 redis.h/redisServer 结构的 aof_buf 末尾。
redisServer 结构维持着 Redis 服务器的状态,aof_buf 域则保存着所有等待写入到 AOF 文件的协议文本(RESP)
文件写入和保存
每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile 函数都会被调用,这个函数执行以下两个工作:
WRITE: 根据条件将 aof_buf 中的缓存写入到 AOF 文件。
SAVE: 根据条件调用 fsync 或 fdatasync 函数将 AOF 文件保存到磁盘中。
AOF 保存模式
Redis 目前支持三种 AOF 保存模式,它们分别是:
AOF_FSYNC_NO : 不保存。
AOF_FSYNC_EVERYSEC : 每一秒钟保存一次。(默认)
AOF_FSYNC_ALWAYS : 每执行一个命令保存一次。(不推荐)
AOF_FSYNC_NO
从不 fsync,将数据交给操作系统来处理。更快,也更不安全的选择。
SAVE 只会在以下任意一种情况中被执行:
Redis 被关闭
AOF 功能被关闭
系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。
AOF_FSYNC_EVERYSEC
SAVE 原则上每隔一秒钟就会执行一次,因为 SAVE 操作是由后台子线程 (fork) 调用的,所以它不会引起服务器主进程阻塞,并且在故障时只会丢失 1 秒钟的数据。
AOF_FSYNC_ALWAYS
每次执行完一个命令之后,WRITE 和 SAVE 都会被执行。每次有新命令追加到 AOF 文件时就执行一次 fsync,非常慢,也非常安全。
因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。
AOF 保存模式对性能和安全性的影响
三种模式的比较
AOF 重写
AOF 记录数据的变化过程,越来越大,需要重写“瘦身”
Redis 可以在 AOF 体积变得过大时,自动地在后台(Fork 子进程)对 AOF 进行重写。
重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。
所谓的“重写”其实是一个有歧义的词语,实际上,AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取,它针对的是数据库中键的当前值。
举例说明
set s1 11
set s1 22
set s1 33
lpush list1 1 2 3
lpush list1 4 5 6
AOF 重写后
set s1 33
lpush list1 1 2 3 4 5 6
Redis 不希望 AOF 重写造成服务器无法处理请求,所以 Redis 决定将 AOF 重写程序放到(后台)子进程里执行,
1、子进程进行 AOF 重写期间,主进程可以继续处理命令请求。
2、子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性。
不过,使用子进程也有一个问题需要解决:因为子进程在进行 AOF 重写期间,主进程还需要继续处理命令,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的 AOF 文件中的数据不一致。
为了解决这个问题,Redis 增加了一个 AOF 重写缓存,这个缓存在 fork 出子进程之后开始启用,Redis 主进程在接到新的写命令之后,除了会将这个写命令的协议内容追加到现有的 AOF 文件之外,还会追加到这个缓存中。
重写过程分析
Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
当子进程在执行 AOF 重写时,主进程需要执行以下三个工作:
处理命令请求。
将写命令追加到现有的 AOF 文件中。
将写命令追加到 AOF 重写缓存中
。这样一来可以保证:现有的 AOF 功能会继续执行,即使在 AOF 重写期间发生停机,也不会有任何数据丢失。所有对数据库进行修改的命令都会被记录到 AOF 重写缓存中。
当子进程完成 AOF 重写之后,它会向父进程发送一个完成信号,父进程在接到完成信号之后,会调用一个信号处理函数,并完成以下工作:
将 AOF 重写缓存中的内容全部写入到新 AOF 文件中。
对新的 AOF 文件进行改名,覆盖原有的 AOF 文件。
Redis 数据库里的 +AOF 重写过程中的命令 ——- 新的 AOF 文件 —- 覆盖老的当步骤 1 执行完毕之后,现有 AOF 文件、新 AOF 文件和数据库三者的状态就完全一致了。
当步骤 2 执行完毕之后,程序就完成了新旧两个 AOF 文件的交替。这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接受命令请求了
。在整个 AOF 后台重写过程中,只有最后的写入缓存和改名操作会造成主进程阻塞,在其他时候,AOF 后台重写都不会对主进程造成阻塞,这将 AOF 重写对性能造成的影响降到了最低。
AOF 重写触发方式
1、配置触发
# 表示当前 aof 文件大小超过上一次 aof 文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时 aof 文件大小为准
auto-aof-rewrite-percentage 100
#限制允许重写最小 aof 文件大小,也就是文件大小小于 64mb 的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
2、执行 bgrewriteaof 命令
127.0.0.1:6379 bgrewriteaof‘Backgroundappendonlyfilerewritingstarted
AOF 重写总结
混合持久化
RDB 和 AOF 各有优缺点,Redis 4.0 开始支持 rdb 和 aof 的混合持久化。
如果把混合持久化打开,aofrewrite 的时候就直接把 rdb 的内容写到 aof 文件开头。
RDB 的头 +AOF 的身体 —- appendonly.aof
开启混合持久化
aof-use-rdb-preambleyes
AOF 文件的载入与数据还原
如果开启了混合持久化,AOF 在重写时,不再是单纯将内存数据转换为 RESP 命令写入 AOF 文件,而是将重写这一刻之前的内存做 RDB 快照处理,并且将 RDB 快照内容和增量的 AOF 修改内存数据的命令存在一起,都写入新的 AOF 文件,新的文件一开始不叫 appendonly.aof,等到重写完新的 AOF 文件才会进行改名,覆盖原有的 AOF 文件,完成新旧两个 AOF 文件的替换。
于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。
1、创建一个不带网络连接的伪客户端(fake client)
因为 Redis 的命令只能在客户端上下文中执行,而载入 AOF 文件时所使用的命令直接来源于 AOF 文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行 AOF 文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样
2、从 AOF 文件中分析并读取出一条写命令
3、使用伪客户端执行被读出的写命令
4、一直执行步骤 2 和步骤 3,直到 AOF 文件中的所有写命令都被处理完毕为止
Redis 数据备份策略
1. 写 crontab 定时调度脚本,每小时都 copy 一份 rdb 或 aof 的备份到一个目录中去,仅仅保留最近 48 小时的备份
2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近 1 个月的备份
3. 每次 copy 备份的时候,都把太旧的备份给删了
4. 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏
RDB 和 AOF 对比
1、RDB 存某个时刻的数据快照,采用二进制压缩存储,AOF 存操作命令,采用文本存储(混合)
2、RDB 性能高、AOF 性能较低
3、RDB 在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF 设置为每秒保存一次,则最多丢 2 秒的数据
4、Redis 以主服务器模式运行,RDB 不会保存过期键值对数据,Redis 以从服务器模式运行,RDB 会保存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。AOF 写入文件时,对过期的 key 会追加一条 del 命令,当执行 AOF 重写时,会忽略过期 key 和 del 命令。
看完了这篇文章,相信你对“Redis 中持久化机制是怎么样的”有了一定的了解,如果想了解更多相关知识,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!