Redis 持久化策略

常见的 Redis 持久化策略有以下四种:

  • RDB:指定时间间隔生成数据集的时间点快照
  • AOF:记录服务端执行的所有写操作命令,并在服务端启动时重新执行命令还原数据集
  • 混合持久化:两者都使用,优先使用 AOF,因为 AOF 文件保存的数据相对更完整
  • 关闭持久化:保证 Redis 性能

RDB:类似快照,在规定时间点将 Redis 在内存中的数据库信息保存到磁盘中,生成的 dump.rdb 文件是压缩过的二进制格式

RDB 文件可以通过以下 Redis 命令生成:

SAVE:阻塞主进程,服务端暂时无法处理客户端请求
BGSAVE:fork 子进程来生成 RDB 快照文件,阻塞只会发生在 fork 子进程的时候,之后主进程可以正常处理请求

为了不影响客户端正常使用,一般情况下不使用 SAVE 命令

RDB 通过 save point 配置开启,满足配置条件后生成一次 RDB 文件,常见配置如下:

save x y :x 秒内有 y 个 key 发生改变就生成 RDB 文件
save "" :删除之前所有 save point 配置

RDB 的优点:

  • 占用空间小,可保存多份不同时间点的备份,根据文件恢复到任意时间点
  • 可以将 RDB 文件传到不同机器恢复,适合容灾机制
  • fork 出子进程完成持久化,不影响主进程服务
  • RDB 数据恢复速度相比 AOF 更快

RDB 的缺点:

  • 服务端故障时不能持久化,可能会丢失一部分数据。
  • 每次 RDB 文件生成需要遍历所有键值对,本身属于比较重的操作,可能产生性能问题,需控制频率
  • linux fork 子进程采用 copy-on-write 机制,fork 开始时子进程和主进程使用共享内存,此时处理客户端请求需要主进程将内存拷贝出来,极端情况所有键值对都复制一份,内存占用量变为原来两倍

copy-on-write 机制:写操作时复制副本,操作副本,后续同步回主内存。类似 Java 线程模型中主内存的处理


AOF:保存 redis 服务端所执行的所有写操作命令,并在数据库执行时通过重新执行命令来还原数据库

AOF 通过配置 appendonly yes 开启 AOF,appendonly no 关闭 AOF 持久化

AOF 持久化过程可分为以下三个阶段:

  1. 命令追加:服务器在执行完命令后,将被执行的命令写入 AOF 缓冲区末尾
  2. 文件写入:出于性能考虑,AOF 缓冲区并没有直接写入磁盘,而是先写入页缓存(page cache)
  3. 文件同步:将页缓存中的数据同步到磁盘,一般通过 fsync / fdatasync 命令强制刷盘(同步数据)

一般通过 appendfsync 参数控制缓冲区中的数据是否同步到磁盘,常见配置有以下三种:

  • always:每处理一条命令就同步到 AOF 文件,也就是每条命令都触发刷盘
  • everysec:每秒钟刷盘一次,异步操作
  • no:由系统决定何时刷盘,redis 只负责写入 page cache

AOF 的优点:

  • AOF 更可靠,我们可以配置不同的 fsync 策略,Redis 默认每秒钟进行一次,即使出现问题,最多丢失一秒钟的数据
  • AOF 是一个只进行追加操作的日志文件,当 AOF 文件体积过大时,后台自动对 AOF 文件进行重写
  • AOF 文件以 Redis 协议的格式保存写入操作,相对很容易理解,当我们执行错误命令需要恢复时,只需要找到错误命令重新执行 AOF 文件即可

AOF 的缺点:

  • 相同数据集,AOF 文件体积通常大于 RDB 文件
  • AOF 的恢复速度通常会慢于 RDB
  • AOF 在记录某些 Redis 指令后续恢复时可能会报错

AOF 重写:随着写入命令的不断增加,AOF 文件越来越大,需要优化。举个例子,键 X 分别设置过十个值,目前只有最后一个值是再使用的,前九次 Set 操作实际上都可以省略,也就是说:AOF 文件对于每个 key 只需要记录一条关键性语句即可

为了处理这种情况,Redis 对 AOF 文件引入重写机制,重写过程安全并且不打断服务端正常服务。新的 AOF 文件会替代旧的 AOF 文件,重写过程中旧的 AOF 文件正常使用,即使重写出现问题,也不会导致数据丢失。

重写时进程遍历所有数据集中的键,从数据库读取现在的值,然后通过一条命令去记录。

重写通过两条 Redis 指令触发:

REWRITEAOF:阻塞主进程执行重写操作,重写期间服务端不处理客户端请求
BGREWRITEAOF:fork 子进程重写,阻塞发生在 fork 子进程期间,之后主进程正常服务

一般情况下不用 REWRITEAOF,BGREWRITEAOF 可以通过以下配置启动和禁止:

// 文件大小相比上次重写后增长比率超过 100
auto-aof-rewrite-percentage 100 
// 当前文件大于 64mb
auto-aof-rewrite-min-size 64mb
// 关闭 AOF 自动重启
auto-aof-rewrite-percentage 0

使用 BGREWRITEAOF 可能存在问题:由于重写期间主进程正常服务,已经保存在新 AOF 文件的中的键值对可能在重写期间赋新值,此时新 AOF 文件中的键值对和实际键值对不统一

ps:并不是重写期间所有的指令都会造成数据不一致,假设重写期间 key x1,x2 的值都被修改,但 x2 是修改后写入 aof 文件,x1 是修改前写入 aof 文件,此时只有 x1 对应的值 aof 文件和实际上线不一致

为了解决重写完数据不一致问题,Redis 引入重写缓冲区的概念,重写缓冲区在 Redis fork 子进程时创建,重写期间服务端执行的指令不仅会写入 AOF 缓冲区,还会写入重写缓冲区。重写完成后,将 AOF 重写缓冲区中所有内容写入新的 AOF 文件,此时新的 AOF 文件所保存的数据状态就可以保证和线上一致。写入完毕后用新的 AOF 文件替换旧的 AOF 文件,至此重写操作全部完成


混合持久化并不是一种新的持久化技术,而是对已有方式的优化。混合持久化发生于 AOF 重写过程中,重写后的 AOF 文件,前半段是 RDB 格式的全量数据,后半段是 AOF 格式的增量数据。所谓增量数据是指 RDB 格式生成期间服务端执行的操作指令。

混合持久化通过参数 aof-use-rdb-preamble yes 开启,aof-use-rdb-preamble no 关闭,从 redis 5.0 开始默认开启

开启混合持久化时,fork 出的子进程先将所有键值对写入 RDB dump 文件中,然后将 AOF 重写缓冲区的增量命令写入文件,写完后通知主进程替换文件,生成的文件前半段 RDB 格式,后半段 AOF格式

混合持久化模式下,aof 文件加载流程如下:

  • aof 文件开头是 rdb 的格式, 先加载 rdb 内容再加载剩余的 aof
  • aof 文件开头不是 rdb 的格式,直接以 aof 格式加载整个文件

总得来说,混合持久化策略使用 rdb 保存全量数据,aof 保存生成 rdb 期间执行的新指令。这样可以兼顾两者的优点,更好用


如何选择:

  • 非常在意数据,可以接受几分钟内的数据丢失,采用 RDB 模式
  • 尽可能保证安全性,采用混合模式
  • 完全不在意数据,关闭持久化,保证 Redis 性能

一般情况下不建议单独使用 aof,因为 rdb 更适合容灾机制,速度更快,aof 虽然数据安全性更高,但性影响较大。Redis 本身就是为了追求效率的内存数据库,如果要求数据一定安全,建议使用 MySQL 等非内存数据库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值