暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis 持久化

星河之码 2021-07-22
512

Redis 如果仅仅只是将数据缓存在内存里面,在Redis 宕机重启后内存里的数据就丢失了。因此必须用 redis 的持久化机制,将数据写入内存的同时,异步的慢慢的将数据写入磁盘文件里,进行持久化。redis 宕机重启,自动从磁盘上加载之前持久化数据,可以避免可能出现缓存雪崩问题。

redis 的持久化有哪几种方式

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

  • RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化。快照模式
  • AOF:AOF 机制对每条写入命令作为日志,以 append-only
    的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。

通过 RDB 或 AOF,都可以将 redis 内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云等云服务。redis 挂了之后重新启动 ,redis 就会自动到指定的目录中根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务。

RDB持久化

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

redis的持久化依赖save和bgsave命令bgsave是主流的触发RDB持久化方式

1.手动触发RDB的持久

  • save命令

    • 优点:节约系统资源。

    • 缺点:阻塞当前Redis进程,阻塞期间,服务器无法响应其他的处理,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用

  • bgsave命令

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

    • 缺点:由于会fork一个进程,因此更消耗内存。

2.自动触发RDB的持久

  • 使用save相关配置,如“save m n”。表示m秒内数据集存在n次修改 时,自动触发bgsave。

  • 如果从节点执行全量复制操作,主节点自动执行bgsave生成RDB文件并发送给从节点。

  • 执行debug reload命令重新加载Redis时,也会自动触发save操作。

  • 默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则 自动执行bgsave。

3.bgsave执行过程

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

4.RDB文件的处理

RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配置指定。可以通过执行config set dir{newDir}和config set dbfilename{newFileName}运行期动态执行,当下次运行时RDB文件会保存到新目录。

5.RDB的优缺点

  • RDB的优点:

    • RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。可以将这种完整的数据文件发送到一些远程的安全存储上去,用于灾难恢复。

    • Redis加载RDB恢复数据远远快于AOF的方式。

    • RDB 对 redis 对外提供的读写服务,影响非常小,可以让 redis 保持高性能,因为 redis 主进程只需要 fork 一个子进程,让子进程执行磁盘 IO 操作来进行 RDB 持久化即可。

  • RDB的缺点:

    • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运 行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。

    • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式 的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。

    • 一般来说,RDB 数据快照文件,都是每隔 5 分钟,或者更长时间生成一次,这个时候就得接受一旦 redis 进程宕机,那么会丢失最近 5 分钟的数据。

AOF持久化

AOF持久化:以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的。

AOF的主要作用:是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

1. AOF使用

  • 开启AOF:需要设置配置:appendonly yes,默认不开启。

  • AOF文件名:通过appendfilename配置设置,默认文件名是appendonly.aof。

  • 保存路径:同RDB持久化方式一致,通过dir配置指定。

2. AOF的工作流程

  • 命令写入 (append)
  • 文件同步(sync)
  • 文件重写(rewrite)
  • 重启加载 (load)流程说明:

1. 所有的写入命令会追加到aof_buf(缓冲区)中。

AOF把命令追加到aof_buf中原因

  • Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。
  • Redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡

2. AOF缓冲区根据对应的策略向硬盘做同步操作。

3. 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。

AOF重写降低了文件占用空间,更小的AOF 文件可以更快地被Redis加载

重写后的AOF文件可以变小原因:

  • 进程内已经超时的数据不再写入文件。

  • 旧AOF文件含有历史的无效命令。重写使用进程内数据直接生成,新的AOF文件只保留最终数据的写入命令。

  • 合并多条写命令为一个,为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。

3.AOF重写

AOF重写分为手动触发和自动触发两种方式。

  • 手动触发:直接调用bgrewriteaof命令。

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

    • auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB。

    • auto-aof-rewrite-percentage:代表当前AOF文件空间 (aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。

自动触发时机=aof_current_size>auto-aof-rewrite-min-size &&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage

其中aof_current_size和aof_base_size可以在info Persistence信息中查看。

4. AOF数据恢复。

当Redis服务器重启时,可以加载AOF文件进行数据恢复。流程说明:

1)AOF持久化开启且存在AOF文件时,优先加载AOF文件,打印如下日志:

DB loaded from append only file: 5.841 seconds

2)AOF关闭或者AOF文件不存在时,加载RDB文件,打印如下日志:

DB loaded from disk: 5.586 seconds

3)加载AOF/RDB文件成功后,Redis启动成功。

4)AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。

AOF 优缺点

  • AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次fsync
    操作,最多丢失 1 秒钟的数据。
  • AOF 日志文件以 append-only
    模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。
  • AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在 rewrite
    log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。
  • AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复
  • 对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大。
  • AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync
    一次日志文件,当然,每秒一次 fsync
    ,性能也还是很高的。(如果实时写入,那么 QPS 会大降,redis 性能会大大降低)
  • AOF 就是为了避免 rewrite 过程导致的 bug,因此每次 rewrite 并不是基于旧的指令日志进行 merge 的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。

RDB 和 AOF 到底该如何选择

  • 不要仅仅使用 RDB,因为那样会导致丢失很多数据;
  • 也不要仅仅使用 AOF,因为那样有两个问题:
    • 第一,通过 AOF 做冷备,没有 RDB 做冷备来的恢复速度更快;
    • 第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug;
  • redis 支持同时开启开启两种持久化方式,可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。

总结

  • Redis提供了两种持久化方式:RDB和AOF。

  • RDB使用一次性生成内存快照的方式,产生的文件紧凑压缩比更高,因此读取RDB恢复速度更快。由于每次生成RDB开销较大,无法做到实时持久化,一般用于数据冷备和复制传输。

  • save命令会阻塞主线程不建议使用,bgsave命令通过fork操作创建子 进程生成RDB避免阻塞。

  • AOF通过追加写命令到文件实现持久化,通过appendfsync参数可以控制实时/秒级持久化。因为需要不断追加写命令,所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积。

  • AOF重写可以通过auto-aof-rewrite-min-size和auto-aof-rewritepercentage参数控制自动触发,也可以使用bgrewriteaof命令手动触发。

  • 子进程执行期间使用copy-on-write机制与父进程共享内存,避免内存消耗翻倍。AOF重写期间还需要维护重写缓冲区,保存新的写入命令避免数据丢失。

  • 持久化阻塞主线程场景有:

    • fork阻塞:fork阻塞时间 跟内存量和系统有关。
    • AOF追加阻塞:AOF追加阻塞说明硬盘资源紧张。
- END -
文章转载自星河之码,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论