Redis是内存数据库,其将自己的数据存储在内存里面,当Redis服务器进程退出时,服务器中的数据也会消失。为解决以上问题,Redis 提供了 RDB
、 AOF
、RDB和AOF混合使用
三种持久化方式,将 redis 内存中的数据保存到磁盘,避免服务进程停止后数据丢失。
Redis 三种方式持久化方式:
1、RDB
:在指定的时间间隔能对数据进行快照存储,类似于 MYSQL中的dump备份文件。
2、AOF
:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据(Mysql 的 binlog).
3、RDB 和 AOF 混合使用
,这是 Redis 4.0 版本开始的新特性。在两种模式混合时,AOF 读取 RDB 数据重建原始数据集,两种模式的优势都能体现。
RDB 持久化既可以手动执行,也可根据服务器配置选项定期执行。RDB 功能将某个时间点上的redis数据,以压缩的二进制格式保存到一个RDB文件中。如果需要,可以通过RDB 文件,恢复生成该RDB文件时间点的数据。
Redis 有两个命令可以用于生成 RDB 文件,一个是 save
,另一个是 bgsave
save 命令会阻塞 Redis 服务器进程
,直到 RDB 文件创建完毕为止,在服务器进程阻塞期间,Redis 服务器不能处理任何命令请求。bgsave 命令会派生出一个子进程,然后由子进程负责创建 RDB 文件
,Redis服务器进程 (父进程) 继续处理命令请求。
关于RDB 文件的载入工作,是在Redis服务器启动时自动执行的,只要 Redis 服务器在启动时检测到 RDB 文件存在,它就会自动载入 RDB 文件。服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止
。
我们可以配置 Redis 在 n 秒内如果超过 m 个 key 被修改就自动做快照,下面是默认的快照保存配置,如果 save 900 1、save 300 10、save 60 10000 这三个选项都注释屏蔽掉,那表示 RDB 被禁用。
# 先找到 redis 的配置文件,没有的化就新建,创建配置目录
mkdir -p /usr/local/redis/conf
# 创建配置文件
vim /usr/local/redis/conf/redis.conf
# 我们这里 就不考虑配置文件中的其他配置项了,这里案例仅考虑 RDB 相关
# 以下是 redis.conf 文件中 RDB 相关的配置 -->>>
# 900 秒内如果超过一个 key 改动,则发起快照保存
save 900 1
# 300 秒内如果超过10个 key 改动,则发起快照保存
save 300 10
# 60 秒内如果超过 1万个 key 改动,则发起快照保存
save 60 10000
快照,可以理解为拍照,把整个内存数据映射到硬盘中,保存一份到硬盘,所以恢复数据起来比较快,把数据映射回去就可以了,不像AOF,需要一条一条的去执行操作命令。
快照是默认的持久化方式,该方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb ,可以通过配置设置自动做快照持久化的方式。
会产生快照的几种情况 : |
---|
① 手动 bgsave 执行 |
② 手动 save 执行 |
③ 根据配置文件自动执行 |
④ 客户端发送 shutdown,系统会先执行 save 命令阻塞客户端,然后关闭服务器 |
⑤ 当有主从架构时,从服务器向主服务器发送sync命令来执行复制操作时,主服务器会执行bgsave操作 |
Redis 默认会将快照文件,存储在 Redis 当前进程的工作目录中的 dump.rdb 文件中,可以通过配置 dir 和 dbfilename 两个参数,分别指定快照文件的存储路径和文件名。
RDB 优点 : | RDB 缺点 : |
---|---|
① 紧凑压缩的二进制文件 |
① 生成快照的时机、频率问题,可能会导致部分数据丢失 |
② fork 子进程性能最大化 |
② fork 子进程的开销问题 |
③ 启动效率高 |
— |
RDB 文件用于保存和还原 Redis 服务器中,所有的键值对数据。
save
命令由服务器进程直接执行保存操作,所以该命令 会阻塞服务器
。
bgsave
命令 由子进程执行保存操作
,所以该命令 不会阻塞服务器
。
服务器状态中会保存所有用 save 选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行 bgsave 命令。
RDB 文件是一个经过压缩的二进制文件,由多个部分组成。
对于不同类型的键值对,RDB文件会使用不同的方式来保存它们。
Redis 除了 RDB 持久化之外,还提供了 AOF (Append Only File) 持久化功能,AOF 通过 保存 Redis 服务器所执行的写命令
,来记录 关系型数据库Redis 的数据。AOF 持久化功能的实现可分为 命令追加(append)
、文件写入
、文件同步(sync)
三个步骤。
命令追加(append) : 当AOF 持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令,追加到服务器状态的 aof_buf 缓冲区的末尾。
Redis 服务器进程,是一个事件循环(loop),循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复。时间事件则负责执行需要定时运行的函数,比如 serverCron 函数。
服务器再处理文件事件时,可能会执行写命令,使得一些内容被追加到 aof_buf 缓冲区里,故Redis服务器每次结束一个事件循环之前,它都会调用 flushAppendOnlyFile 函数,根据appendfsync 选项值,判断是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件中。
flushAppendOnlyFile 函数行为由 appendfsync 配置项的值来决定:
appendfsync 值 | flushAppendOnlyFile 函数的行为 |
---|---|
always | 将 aof_buf 缓冲区中的所有内容写入并同步到 AOF 文件,会 极大消弱 Redis 性能 ,因为这种模式下每次 write 后都会调用 fsync |
everysec | 将 aof_buf 缓冲区中的所有内容写入到AOF文件,如果上次同步AOF文件的时间距离现在超过一秒钟,那么再次对AOF文件进行同步,并且这个同步操作是由一个线程专门负责执行的。(缺省策略 ) |
no | 将 aof_buf 缓冲区中的所有内容写入到 AOF 文件,但并不对 AOF 文件进行同步,何时同步由操作系统来决定。(性能最好 ) |
Redis 三种 AOF 同步策略配置方法:
# 每秒同步,该策略为AOF的缺省策略
appendfsync everysec
# 每次有数据修改发生时,都会写入AOF文件
appendfsync always
# 从不同步,高效但是数据不会主动被持久化
appendfsync no
关于文件的写入与同步 :
操作系统层面,为了提高文件的写入效率,当用户调用 write 函数将数据写入文件时,操作系统会将要写入的数据,暂时保存在一个内存缓冲区里,等缓冲区的空间被填满、或者超过了指定的时限后,才将缓冲区的数据写入磁盘。这样如果计算机突然停机,那缓冲区的数据会丢失。为避免该问题,系统提供了 fsync 和 fdatasync 两个同步函数,可以强制让操作系统立即将缓冲区的数据写入磁盘。
AOF 的频率高的话会对 Redis 带来性能影响,每次都是刷盘操作,跟Mysql 就一样了。Redis 每次都是先将命令放到缓冲区,然后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操作。
如果配置的策略为 always ,那就是典型阻塞。如果是 everysec 每秒的话,那么会开一个同步线程区每秒进行刷盘操作,对主线程影响稍小。
Redis 读取 AOF 文件并还原数据库状态(Redis 数据)的详细步骤:
1、创建一个不带网络连接的伪客户端 (fake client),伪客户端执行命令的效果,和带网络连接的客户端执行命令的效果一样。 使用伪客户端是因为,reids 命令只能在客户端上下文中执行,而载入 AOF 文件时,使用的命令直接来源于 AOF 文件,而不是网络链接。
2、从 AOF 文件中分析并读取出一条写命令。
3、使用伪客户端执行被读出的写命令。
4、一直执行步骤2 和 步骤3,直到AOF 文件中的所有写命令都被处理完毕为止。
如果不小心执行了 FLUSHALL 命令,只要 AOF 文件未被重写,那仅需停止服务,移除 AOF 文件末尾的 FLUSHALL 命令,然后重启 Redis 服务,就可以将数据恢复到 执行 FLUSHALL 命令之前的状态。
为什么需要 AOF 重写功能 ?
AOF 持久化是通过保存被执行的写命令,来记录数据库状态(这里指非关系型数据库Redis的数据)的,随着Redis 服务器运行时间的流逝,AOF 文件中的内容会越来越大,文件体积也会越来越大,这样可能会对Redis 服务器、甚至是整个宿主机产生影响。同时,AOF 文件越大,使用 AOF 文件来进行数据还原所需的时间就越长。Redis 的重写机制对AOF文件做出了优化,比如一个相同的Key 值多次写入的情况。
通过 Redis 重写(rewrite)功能,Redis 服务器可以创建一个新的AOF文件,来代替现有的 AOF 文件,新旧两个AOF文件所保存的数据库状态(这里指非关系型数据库Redis的数据)相同,但新的 AOF 文件不会包含任何浪费空间的冗余命令,所以新的AOF文件体积,通常比旧的AOF文件体积小很多。
Redis 的 AOF 重写程序是在子进程中执行的
,这样有两个好处:1、子进程进行 AOF 重写期间,服务器进程(父进程)可以继续处理命令请求。2、子进程带有服务器进程的数据副本,子进程不是线程,可以避免使用锁的情况下,保证数据的安全性。虽有好处,但是也会产生问题,子进程做AOF重写时,父进程有新的命令需要处理时,那子进程带有的数据副本,就会和父进程有差异,这就需要AOF 重写缓冲区来解决了。
Redis 服务器设置了一个 AOF 重写缓冲区,在创建 AOF重写子进程后,这个 AOF 重写缓冲区就开始使用。当Redis 服务器执行完一个写命令后,他会将这条命令同时发给 AOF 缓冲区 和 AOF 重写缓冲区。当 AOF 重写子进程完成重写后,子进程会向父进程发生一个信号,父进程在接收到信号后,会调用一个信号处理函数,信号处理函数将AOF 重写缓冲区的所有内容写到新的 AOF 文件中,然后对新的AOF 文件改名,原子地(atomic)覆盖现有的AOF文件
。
重点: 整个 AOF 后台重写过程中,只有父进程的 信号处理函数执行时,会对服务器进程(父进程)造成阻塞。
重写触发条件 : |
---|
① 客户端执行 bgrewriteaof 命令 |
② auto-aof-rewrite-min-size 64mb |
③ auto-aof-rewrite-percentage 100 |
AOF 常用配置 :
# 默认 appendonly 为 no, 开启 AOF
appendonly yes
appendfilename "appendonly.aof"
# fsync 持久化策略
appendfsync everysec
# AOF 重写期间是否禁止 fsync : 如果启用该选项,可以减轻文件重写时 CPU
# 和硬盘的负载(尤其是硬盘) 但 …… 间的数据。需要在负载和安全性之间进行平衡
no-appendfsync-on-rewrite no
# 当前 AOF 文件大于多少字节后开始触发重写
auto-aof-rewrite-min-size 64mb
# 当前写入AOF日志文件的大小超过上一次rewrite之后的文件大小的百分之100时,
# 也就是 2 倍时触发 rewrite
auto-aof-rewrite-percentage 100
# 如果 AOF 文件结尾损坏, redis 启动时是否仍然载入 AOF 文件
aof-load-truncated yes
# RDB文件和AOF文件所在目录
dir /usr/local/redis/data
AOF 的优缺点 :
优点 | 缺点 |
---|---|
① 数据不易丢失 | ① AOF 文件恢复数据慢 |
② 自动重写机制 | ② AOF 持久化效率低 |
③ 文件易懂易恢复 | _ |
AOF 重点总结 :
整个 AOF 后台重写过程中,只有父进程的 信号处理函数执行时,会对服务器进程(父进程)造成阻塞。
Redis 4.0 开始支持 RDB 和 AOF 混合模式,开启方式:aof-use-rdb-preamble true
。
开启混合模式后,AOF在重写时会直接读取 RDB 中的内容。新的 AOF 文件中,一部分数据来自 RDB 文件,一部分来自Redis 运行过程中的增量数据。
混合模式AOF 重写过程 :
1、子进程会把内存中的数据以 RDB 的方式写入 AOF 中。
2、把重写缓冲区中的增量命令以 AOF 方式写入到文件。
3、将含有 RDB 和 AOF 格数的 AOF 文件覆盖旧的 AOF 文件。
混合模式的数据恢复 :
当我们开启了混合持久化时,启动 Redis 依然优先加载 AOF 文件,AOF 文件加载可能存在两种情况:
优点:既能快速备份又能避免大量数据丢失。
缺点:RDB是压缩格式,AOF在读取它时可读性较差。
动态切换持久化模式:
# Redis2.2及以上版本,在不重启服务情况下,从RDB切到AOF模式
# 开启 AOF,执行该命令后,Redis 会阻塞直到初始AOF文件创建完成为止,
# 之后Redis 会继续处理命令请求,并开始将写入命令追加到AOF文件末尾
redis-cli config set appendonly yes
# 关闭 RDB
redis-cli config set save ""
关于容灾备份,需要编写脚本定时备份 RDB 文件.
.