Redis中的持久化

持久化

.

RDB

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

手动触发

save命令

阻塞当前Redis服务器,知道RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,因此这个方法基本不采用

bgsave命令

Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束,阻塞只发生在fork阶段,一般时间很短,因此,Redis内部的所有设计RDB的操作都采用类似bgsave的方式

自动触发

  1. 使用save配置,如"save m n"表示m秒内数据集发生了n次修改之后,就会自动触发RDB持久化
  2. 从节点进行全量复制操作时,主节点自动进行RDB持久化,随后将RDB文件内容发送给从节点
  3. 执行shutdown命令关闭Redis时,执行RDB持久化

bgsave的具体流程

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

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-dump工具检测RDB文件并获取对应的错误报告

RDB的优缺点

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

AOF

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

AOF的工作流程如下:

命令写入->文件同步->文件重写->重启加载

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

命令写入

AOF命令写入的内容格式是文本协议格式,因为这样更具备较好的兼容性,可读性,更简单
为什么要使用AOF缓冲区:

redis是单线程执行的,如果每次进行命令写入都直接与硬盘交互,就从对内存的读写变为了对硬盘IO的读写,性能就必然会严重下降,而采用缓冲区过后,减少了IO的次数

文件同步

Redis提供了多种AOF缓冲区同步文件策略,由参数appendfsync控制

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

系统调用wirte和fsync说明

• write 操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提供硬盘 IO 性能。write 操作在写入系统缓冲区后立即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。

同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。

• Fsync 针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到数据写入到硬盘。

• 配置为 always 时,每次写入都要同步 AOF 文件,性能很差,在⼀般的 SATA 硬盘上,只能支持大约几百 TPS 写入。除非是非常重要的数据,否则不建议配置。

• 配置为 no 时,由于操作系统同步策略不可控,虽然提高了性能,但数据丢失风险大增,除非数据重要程度很低,一般不建议配置。

• 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。

重写机制

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

  1. 进程内已超时的数据不再写入文件
  2. 旧的AOF中的无效命令,只需保留数据的最终版本
  3. 多条写操作合并为一条

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

手动触发: 调用bgrewriteaof命令

自动触发: 根据auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时机

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

启动时恢复数据

本章重点回顾

  1. Redis 提供了两种持久化方案:RDB 和 AOF。
  2. RDB 视为内存的快照,产生的内容更为紧凑,占用空间较小,恢复时速度更快。但产生 RDB 的开
    销较大,不适合进行实时持久化,⼀般用于灾备和主从复制。
  3. AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF文件。
  4. RDB 和 AOF 都使用fork 创建子进程,利用 Linux 子进程拥有父进程内存快照的特点进行持久化,
    尽可能不影响主进程继续处理后续命令。
相关推荐
煎饼小狗4 小时前
Redis五大基本类型——Zset有序集合命令详解(命令用法详解+思维导图详解)
数据库·redis·缓存
秋意钟6 小时前
缓存雪崩、缓存穿透【Redis】
redis
简 洁 冬冬6 小时前
046 购物车
redis·购物车
soulteary7 小时前
突破内存限制:Mac Mini M2 服务器化实践指南
运维·服务器·redis·macos·arm·pika
wkj0018 小时前
php操作redis
开发语言·redis·php
菠萝咕噜肉i8 小时前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
登云时刻10 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(二)
redis·容器·kubernetes
Dlwyz13 小时前
redis-击穿、穿透、雪崩
数据库·redis·缓存
工业甲酰苯胺15 小时前
Redis性能优化的18招
数据库·redis·性能优化
Oak Zhang18 小时前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存