【Redis】持久化


一、Redis为什么要持久化?

首先,要知道我们为什么要对redis做持久化?

因为,Redis本身运行时数据保存在内存中,如果不进行持久化,那么在Redis出现非正常原因宕机或者关闭Redis的进程或者关闭计算机后数据肯定被会操作系统从内存中清掉。

很多人又会问,“明明我们在本地自己搭Redis环境的时候没有多余的配置操作呀,但是就算自己重启Redis或者重启计算机后,甚至过了几个月后,Redis中的数据却仍然存在呢!?”。

当然,Redis本身默认采用了一种持久化方式,即RDB,文章下面会给出介绍。

二、持久化的实现方式

Redis 支持 RDB(Redis Database) 和 **AOF(Append Only File)**两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。

1.RDB

RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和自动触发。

触发机制

手动触发分别对应 savebgsave 命令:

  • save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例造成长时间 阻塞,基本不采用。

  • bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

注:Redis 内部的所有涉及 RDB 的操作都采用类似 bgsave 的方式。
除了手动触发之外,Redis 运行自动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。 - 在配置文件中使用 save 配置。如 "save m n" 表示 m 秒内数据集发生了 n 次修改,自动 RDB 持久化。
# 表示900秒内有一次更改,或者900秒内有10次更改,或者60秒内有10000此更改执行同步操作
save 900 1
save 300 10
save 60 10000

另外,如果想不使用RDB做持久化了,可以不配置任何的save,或者将save配成空字符串,如下图所示。

save ""
  • 从节点进行全量复制操作时,主节点自动进行 RDB 持久化,随后将 RDB 文件内容发送给从结点。
  • 执行 shutdown 命令关闭 Redis 时,执行 RDB 持久化。

运作流程

bgsave工作流程

  • 执行 bgsave 命令,Redis 父进程判断当前进是否存在其他正在执行的子进程,如 RDB/AOF 子进
    程,如果存在 bgsave 命令直接返回。
  • 父进程执行 fork 创建子进程,fork 过程中父进程会阻塞,通过 info stats 命令查看
    latest_fork_usec 选项,可以获取最近一次 fork 操作的耗时,单位为微秒。
  • 父进程 fork 完成后,bgsave 命令返回 “Background saving started” 信息并不再阻塞父进程,可
    以继续响应其他命令。
  • 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执
    行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time
    项。
  • 进程发送信号给父进程表示完成,父进程更新统计信息。

RDB 文件处理

保存:RDB 文件保存再 dir 配置指定的目录(默认 /var/lib/redis/)下,文件名通过 dbfilename
配置(默认 dump.rdb)指定。可以通过执行 config set dir {newDir}config set dbfilename
{newFilename}
运行期间动态执行,当下次运行时 RDB 文件会保存到新目录。

压缩:Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大
小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。

注:虽然压缩 RDB 会消耗 CPU,但可以大幅降低文件的体积,方便保存到硬盘或通过网络发送到从节点,因此建议开启。

校验:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redis-check-dump 工具检测 RDB 文件并获取对应的错误报告。

RDB 的优缺点

  • RDB 是一个紧凑压缩的⼆进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每 6 小时执行
  • bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中 (如 hdfs)用于灾备
  • Redis 加载 RDB恢复数据远远快于AOF 的方式。
  • RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork创建子进程,属于重量级操作,频繁执行成本过高。
  • RDB 文件使用特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB版本,兼容性可能有风险

2.AOF

AOF(Append Only File)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF
文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是Redis 持久化的主流方式。

使用 AOF

开启 AOF 功能需要设置配置:appendonly yes默认不开启。AOF 文件名通过
appendfilename 配置(默认是 appendonly.aof)设置。保存目录同 RDB 持久化方式一致,通过 dir
配置指定。AOF 的工作流程操作:命令写入(append)、文件同步(sync)、文件重写
rewrite)、重启加载(load)。
AOF工作流程

  1. 所有的写入命令会追加到 aof_buf(缓冲区)中。
  2. AOF 缓冲区根据对应的策略向硬盘做同步操作
  3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
  4. 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。

命令写入

AOF 命令写入的内容直接是文本协议格式。例如 set hello world 这条命令,在 AOF 缓冲区会追加如下
文本:

1 *3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

此处遵守 Redis 格式协议,Redis 选择文本协议可能的原因:文本协议具备较好的兼容性;实现简单;具备可读性。
AOF 过程中为什么需要 aof_buf 这个缓冲区?Redis 使用单线程响应命令,如果每次写 AOF 文件都直接同步硬盘,性能从内存的读写变成 IO 读写,必然会下降。先写入缓冲区可以有效减少 IO 次数,同时,Redis 还可以提供多种缓冲区同步策略,让用户根据自己的需求做出合理的平衡。

文件同步

Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制,不同值的含义如下表所
示。

可配置值说明
always命令写入 aof_buf 后调用 fsync 同步,完成后返回
everysec命令写入aof_buf 后只执行 write 操作,不进行fsync。每秒由同步线程进行 fsync。
no命令写入 aof_buf 后只执行 write 操作,由 OS 控制fsync 频率。

系统调用 write 和 fsync 说明:

  • write 操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提供硬盘 IO 性能。write
    操作在写入系统缓冲区后立即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失
  • fsync 针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到数据写入到硬盘。
  • 配置为 always 时,每次写入都要同步AOF 文件,性能很差,在一般的 SATA 硬盘上,只能支持大约几百 TPS 写入。除非是非常重要的数据,否则不建议配置
  • 配置为no 时,由于操作系统同步策略不可控,虽然提高了性能,但数据丢失风险大增,除非数据重要程度很低,一般不建议配置
  • 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。

重写机制

随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文
件体积。AOF文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF文件。

重写后的 AOF 为什么可以变小?有如下原因:

  • 进程内已超时的数据不再写入文件。
  • 旧的 AOF 中的无效命令,例如 del、hdel、srem等重写后将会删除,只需要保留数据的最终版 本。
  • 多条写操作合并为一条,例如 lpush list a、lpush listb、lpush list 从可以合并为 lpush list a b c。
  • 较小的 AOF文件一方面降低了硬盘空间占用,一方面可以提升启动 Redis 时数据恢复的速度。

重写的触发

AOF 重写过程可以手动触发自动触发

  • 手动触发:调用 bgrewriteaof 命令。
  • 自动触发:根据 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage参数确定自动触发时机。
    • auto-aof-rewrite-min-size:表示触发重写时 AOF 的最小文件大小,默认为 64MB。
    • auto-aof-rewrite-percentage:代表当前 AOF 占用大小相比较上次重写时增加的比例

当触发 AOF 重写时,它的运行流程如下。
重写流程

  1. 执行 AOF 重写请求。如果当前进程正在执行 AOF 重写,请求不执行。如果当前进程正在执行 bgsave 操作,重写命令延迟到 bgsave 完成之后再执行。
  2. 父进程执行 fork 创建子进程。
  3. 重写
  • a. 主进程 fork 之后,继续响应其他命令。所有修改操作写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证旧 AOF 文件机制正确。
  • b. 子进程只有 fork 之前的所有内存信息,父进程中需要将 fork 之后这段时间的修改操作写入AOF 重写缓冲区中。
  1. 子进程根据内存快照,将命令合并到新的 AOF 文件中。
  2. 子进程完成重写
  • a. 新文件写入后,子进程发送信号给父进程。
  • b. 父进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF 文件中。
  • c. 用新 AOF 文件替换老AOF 文件。

AOF 的优缺点

AOF的优点AOF只是追加日志文件,因此对服务器性能影响较小,速度比RDB要快,消耗的内存较少。
AOF的缺点AOF方式生成的日志文件太大,即使通过AFO重写,文件体积仍然很大恢复数据的速度比RDB慢

3. 数据恢复

当 Redis 启动时,会根据 RDB 和 AOF 文件的内容,进行数据恢复,具体流程如下Redis根据持久化文件进行数据恢复

4. 选择RDB还是AOF呢?

通过上面的介绍,我们已经大致了解了RDB与AOF各自的优点与缺点,到底要如何选择呢?

我们可以从几个方面对比一下RDB与AOF,在应用时,要根本自己的实际需求,选择RDB或者AOF,其实,如果想要数据足够安全,可以两种方式都开启,但两种持久化方式同时进行IO操作,会严重影响服务器性能,因此有时候不得不做出选择。

方式RDBAOF
启动优先级
体积
恢复速度
数据安全性会丢失数据由策略决定
轻重
注:当RDB与AOF两种方式都开启时,Redis会优先使用AOF日志来恢复数据,因为AOF保存的文件比RDB文件更完整。

三、小结

文章对Redis的持久化机制进行了大致的介绍

其实,如果你只是单纯把Redis作为缓存服务器,那么可以完全不用考虑持久化,但是,在如今的大多数服务器架构中,Redis的单单只是扮演一个缓存服务器的角色,还可以作为数据库,保存我们的业务数据,此时,我们则需要好好了解有关Redis持久化策略的区别与选择。


如果文章对你有帮助的话给个免费的关注和点赞吧,感谢!!!
感谢

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值