Redis数据持久化

一、为什么要持久化

Redis是内存数据库,宕机后数据会消失。
Redis重启后快速恢复数据,要提供持久化机制
Redis持久化是为了快速的恢复数据而不是为了存储数据
Redis有两种持久化方式:RDB和AOF
注意:Redis持久化不保证数据的完整性。
当Redis用作DB时,DB数据要完整,所以一定要有一个完整的数据源(文件、mysql)
在系统启动时,从这个完整的数据源中将数据load到Redis中
数据量较小,不易改变,比如:字典库(xml、Table)
通过info命令可以查看关于持久化的信息:

# Persistence
loading:0
rdb_changes_since_last_save:1
rdb_bgsave_in_progress:0
rdb_last_save_time:1589363051
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
aof_current_size:58
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0

二、RDB持久化数据

RDB(Redis DataBase),是redis默认的存储方式,RDB方式是通过快照( snapshotting )完成的。只关注这一刻的数据,不关心过程。

2.1 RDB执行流程

在这里插入图片描述

  1. Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof(aof文件重写命令)的子进程,如果在执行则bgsave命令直接返回。
  2. 父进程执行fork(调用OS函数复制主进程)操作创建子进程,这个复制过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令。
  3. 父进程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父进程,并可以响应其他命令。
  4. 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。(RDB始终完整)
  5. 子进程发送信号给父进程表示完成,父进程更新统计信息。
  6. 父进程fork子进程后,继续工作。

2.2 RDB 文件结构

在这里插入图片描述

  1. 头部5字节固定为“REDIS”字符串
  2. 4字节“RDB”版本号(不是Redis版本号),当前为9,填充后为0009
  3. 辅助字段,以key-value的形式
字段名字段值
redis-ver5.0.5
redis-bits64/32
ctime当前时间戳
used-mem使用内存
aof-preamble是否开启
repl-stream-db主从复制
repl-id主从复制
repl-offset主从复制
  1. 存储数据库号码
  2. 字典大小
  3. 过期key
  4. 主要数据,以key-value的形式存储
  5. 结束标志
  6. 校验和,就是看文件是否损坏,或者是否被修改。

2.3 RDB的优缺点

优点
RDB是二进制压缩文件,占用空间小,便于传输(传给slaver)主进程fork子进程,可以最大化Redis性能,主进程不能太大,Redis的数据量不能太大,复制过程中主进程阻塞。
缺点
Redis 的数据持久化使用了「RDB 数据快照」的方式来实现宕机快速恢复。但是 过于频繁的执行全量数据快照,有两个严重性能开销:
• 频繁生成 RDB 文件写入磁盘,磁盘压力过大。会出现上一个 RDB 还未执行完,下一个又开始生成,陷入死循环。
• fork 出 bgsave子进程会阻塞主线程,主线程的内存越大,阻塞时间越长。

三、AOF持久化

AOF(append only file)是Redis的另一种持久化方式。Redis默认情况下是不开启的。开启AOF持久化后Redis 将所有对数据库进行过写入的命令(及其参数)(RESP)记录到 AOF 文件, 以此达到记录数据库状态的目的,这样当Redis重启后只要按顺序回放这些命令就会恢复到原始状态了。AOF会记录过程,RDB只管结果。

3.1 AOF持久化实现

配置 redis.conf文件

# 可以通过修改redis.conf配置文件中的appendonly参数开启
appendonly yes
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。
dir ./
# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof

3.2 AOF原理

写前日志(Write Ahead Log, WAL): 在实际写数据之前,将修改的数据写到日志文件中,故障恢复得以保证。
写后日志: 先执行「写」指令请求,将数据写入内存,再记录日志。写后才记录日志,不会阻塞当前的「写」指令执行。
在这里插入图片描述

AOF文件中存储的是redis的命令,同步命令到 AOF 文件的整个过程可以分为三个阶段:
命令传播:Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。
缓存追加:AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话,fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。

3.2.1 命令传播

当一个 Redis 客户端需要执行命令时,它通过网络连接,将协议文本发送给 Redis 服务器。服务器在接到客户端的请求之后,它会根据协议文本的内容,选择适当的命令函数,并将各个参数从字符串文本转换为 Redis 字符串对象( StringObject )。每当命令函数成功执行之后, 命令参数都会被传播到AOF程序。

3.2.2 缓存追加

当命令被传播到 AOF 程序之后,程序会根据命令以及命令的参数,将命令从字符串对象转换回原来的协议文本。协议文本生成之后,它会被追加到 redis.h/redisServer 结构的 aof_buf 末尾。
redisServer 结构维持着 Redis 服务器的状态,aof_buf域则保存着所有等待写入到 AOF文件的协议文本(RESP)。

3.2.3 文件写入和保存

每当服务器常规任务函数被执行、或者事件处理器被执行时,aof.c/flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作:
WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件。
SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

3.2.4 AOF保存模式

Redis 目前支持三种 AOF 保存模式,它们分别是:
AOF_FSYNC_NO :不保存。
AOF_FSYNC_EVERYSEC :每一秒钟保存一次。(默认)
AOF_FSYNC_ALWAYS :每执行一个命令保存一次。(不推荐)
1. 不保存
在这种模式下, 每次调用 flushAppendOnlyFile 函数, WRITE 都会被执行, 但 SAVE 会被略过。在这种模式下, SAVE 只会在以下任意一种情况中被执行:
Redis 被关闭
AOF 功能被关闭
系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。
2. 每一秒保存一次
在这种模式中, SAVE 原则上每隔一秒钟就会执行一次, 因为 SAVE 操作是由后台子线程(fork)调用的, 所以它不会引起服务器主进程阻塞。
3. 每执行一个命令保存一次
在这种模式下,每次执行完一个命令之后, WRITE 和 SAVE 都会被执行。另外,因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。
AOF 保存模式对性能和安全性的影响
对于三种 AOF 保存模式, 它们对服务器主进程的阻塞情况如下:
在这里插入图片描述

3.3 AOF重写机制

AOF记录数据的变化过程,越来越大,需要重写“瘦身”。Redis可以在 AOF体积变得过大时,自动地在后台(Fork子进程)对 AOF进行重写。重写后的新 AOF文件包含了恢复当前数据集所需的最小命令集合。 所谓的“重写”其实是一个有歧义的词语, 实际上,AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取, 它针对的是数据库中键的当前值。
Redis 不希望 AOF 重写造成服务器无法处理请求, 所以 Redis 决定将 AOF 重写程序放到(后台)子进程里执行, 这样处理的最大好处是:
1、子进程进行 AOF 重写期间,主进程可以继续处理命令请求。
2、子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性。
不过, 使用子进程也有一个问题需要解决: 因为子进程在进行 AOF 重写期间, 主进程还需要继续处理命令, 而新的命令可能对现有的数据进行修改, 这会让当前数据库的数据和重写后的 AOF 文件中的数据不一致。
为了解决这个问题, Redis 增加了一个 AOF 重写缓存, 这个缓存在 fork 出子进程之后开始启用,Redis 主进程在接到新的写命令之后, 除了会将这个写命令的协议内容追加到现有的AOF 文件之外,还会追加到这个缓存中。
在这里插入图片描述

3.3.1 重写过程分析

Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
当子进程在执行 AOF 重写时, 主进程需要执行以下三个工作:

  1. 处理命令请求。
  2. 将写命令追加到现有的 AOF 文件中。
  3. 将写命令追加到 AOF 重写缓存中。

这样一来可以保证:
现有的 AOF 功能会继续执行,即使在 AOF 重写期间发生停机,也不会有任何数据丢失。所有对数据库进行修改的命令都会被记录到 AOF 重写缓存中。当子进程完成 AOF 重写之后, 它会向父进程发送一个完成信号, 父进程在接到完成信号之后, 会调用一个信号处理函数, 并完成以下工作:

  1. 将 AOF 重写缓存中的内容全部写入到新 AOF 文件中。
  2. 对新的 AOF 文件进行改名,覆盖原有的 AOF 文件。
    Redis数据库里的+AOF重写过程中的命令------->新的AOF文件---->覆盖老的
    当步骤 1 执行完毕之后, 现有 AOF 文件、新 AOF 文件和数据库三者的状态就完全一致了。
    当步骤 2 执行完毕之后, 程序就完成了新旧两个 AOF 文件的交替。
    这个信号处理函数执行完毕之后, 主进程就可以继续像往常一样接受命令请求了。 在整个 AOF 后台重写过程中, 只有最后的写入缓存和改名操作会造成主进程阻塞, 在其他时候, AOF 后台重写都不会对主进程造成阻塞, 这将 AOF 重写对性能造成的影响降到了最低。
    在这里插入图片描述

3.3.2 触发方式

1. 配置触发
在redis.conf中配置

# 表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为准
auto-aof-rewrite-percentage 100
# 限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb

2. 执行bgrewriteaof命令

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started

3.3.3 混合持久

RDB和AOF各有优缺点,Redis 4.0 开始支持 rdb 和 aof 的混合持久化。如果把混合持久化打开,aof rewrite 的时候就直接把 rdb 的内容写到 aof 文件开头。
RDB的头+AOF的身体---->appendonly.aof
开启混合持久

aof-use-rdb-preamble yes

在这里插入图片描述
我们可以看到该AOF文件是rdb文件的头和aof格式的内容,在加载时,首先会识别AOF文件是否以REDIS字符串开头,如果是就按RDB格式加载,加载完RDB后继续按AOF格式加载剩余部分。

3.4 AOF文件的载入和数据还原

因为AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。
Redis读取AOF文件并还原数据库状态的详细步骤如下:1、创建一个不带网络连接的伪客户端(fake client):因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
2、从AOF文件中分析并读取出一条写命令
3、使用伪客户端执行被读出的写命令
4、一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止。
当完成以上步骤之后,AOF文件所保存的数据库状态就会被完整地还原出来,整个过程如下图所示:
在这里插入图片描述

四、总结

4.1 RDB和AOF的对比

  1. RDB存某个时刻的数据快照,采用二进制压缩存储,AOF存操作命令,采用文本存储(混合)
  2. RDB性能高、AOF性能较低
  3. RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF设置为每秒保存一次,则最多丢2秒的数据
  4. Redis以主服务器模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令。

4.2 应用场景

内存数据库:rdb+aof 数据不容易丢
有原始数据源: 每次启动时都从原始数据源中初始化 ,则不用开启持久化(数据量较小)
缓存服务器:rdb一般,AOF性能高
在数据还原时:
有rdb+aof 则还原aof,因为RDB会造成文件的丢失,AOF相对数据要完整。
只有rdb,则还原rdb

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis数据持久化有两种方式:快照持久化(RDB)和写日志持久化(AOF)。 RDB持久化是通过将Redis数据集在指定的时间间隔内保存到硬盘上的快照,以二进制形式存储。这种方式的缺点是耗时和耗性能,因为需要经常fork子进程来保存数据集到硬盘上。当数据集很大时,fork的过程会非常耗时,可能导致Redis在一些毫秒级内不能响应客户端请求。另外,如果Redis意外停止工作,可能会丢失一些数据。 AOF持久化是把每一个对Redis服务器的修改操作都记录到一个日志文件中。这种方式的优点是可以保证数据的耐久性,因为每个写操作都会被写入日志文件。当Redis重启时,会通过重新执行日志文件中的命令来恢复数据。但AOF持久化相对于RDB持久化来说,会占用更多的磁盘空间,并且写操作会造成额外的I/O开销。 为了更好地控制数据持久化的行为,你可以通过配置文件设置Redis在指定条件下自动进行数据集保存操作。例如,你可以设置当数据集在N秒内至少有M个改动时,自动进行数据集保存操作。 综上所述,RDB持久化适用于对数据集的完整性要求不高、对性能要求较高的场景,而AOF持久化则适用于对数据耐久性要求较高的场景。根据具体需求和性能要求,可以选择适合的持久化方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Redis持久化详解(简单易懂)](https://blog.csdn.net/GSl0408/article/details/126742048)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值