Redis08_持久化

Redis作为内存数据库默认数据存储在RAM中,重启会导致数据丢失,因此提供RDB和AOF两种持久化机制。RDB通过定时快照保存数据,恢复快但可能丢失两次快照间的数据;AOF记录每个写命令,数据更完整但文件较大。两者各有优缺点,可根据需求选择或结合使用。

作品集: Redis学习
作者头像
LumiBee
22 天前 · 53 0
分享

持久化

必要性

Redis 主要是一个基于内存的数据库,这意味着所有数据默认存储在服务器的RAM中。RAM的读写速度非常快,这是Redis高性能的关键原因之一。但是,如果Redis服务器因为断电、崩溃或其他原因重启,内存中的所有数据都会丢失。为了解决这个问题,Redis提供了持久化机制。

RDB持久化

什么是RDB

RDB(Redis DataBase)持久化通过在指定的时间间隔内创建数据集的时间点快照 (point-in-time snapshot) 来工作。它会生成一个经过压缩的二进制文件(默认为 dump.rdb),其中包含了在特定时刻Redis数据库中的所有数据。

RDB如何工作

当满足RDB持久化的触发条件时(手动或自动),Redis会执行以下操作:

  1. Fork子进程:Redis 主进程会 fork() 一个子进程。fork() 操作会创建一个与父进程几乎完全相同的副本。
    • Copy-On-Write (COW写时复制): fork() 之后,父子进程共享相同的内存页。父进程继续处理客户端请求。如果父进程需要修改某个内存页,操作系统会将该页复制一份,父进程在新复制的页上进行修改,而子进程仍然读取旧的、未修改的页。这确保了子进程看到的是 fork() 时刻的数据快照,并且父进程的性能影响降到最低。
  2. 子进程写RDB文件: 子进程负责将内存中的数据快照写入到一个临时的RDB文件中。
  3. 替换旧文件: 当子进程完成RDB文件的写入后,它会用这个新的临时文件替换掉旧的 dump.rdb 文件。
  4. 子进程退出: 完成替换后,子进程退出。

如何触发RDB

  1. SAVE 命令 (手动,同步阻塞):
  • 客户端执行 SAVE 命令。
  • Redis主进程亲自执行RDB保存过程,期间会阻塞所有其他客户端请求,直到RDB文件创建完毕。
  • 生产环境严禁使用,因为它会导致服务在保存期间不可用。
  1. BGSAVE 命令 (手动,异步非阻塞):
  • 客户端执行 BGSAVE 命令。
  • Redis主进程 fork() 一个子进程,由子进程负责RDB的保存。
  • 主进程继续处理客户端请求,不会阻塞。这是推荐的手动触发方式。
  1. 配置文件自动触发 (redis.conf): 可以在 redis.conf 文件中通过 save 配置项来设定自动触发 BGSAVE 的条件。格式为: save <seconds> <changes> 可以配置多条 save 规则,满足任意一条规则即会触发。
  • 例如,默认配置通常类似:

    save 900 1     # 900秒(15分钟)内至少有1个key被修改
    save 300 10    # 300秒(5分钟)内至少有10个key被修改
    save 60 10000  # 60秒(1分钟)内至少有10000个key被修改
    
  • 如果想禁用自动RDB,可以将所有 save 规则注释掉,或者配置 save ""

  1. 执行 FLUSHALLFLUSHDB 命令时: 如果没有禁用RDB,执行清空数据库的命令也会触发RDB保存一个空的 dump.rdb 文件。

  2. 主从复制时: 当从服务器连接到主服务器并进行全量同步时,主服务器会自动执行 BGSAVE 生成RDB文件发送给从服务器。

RDB的优缺点

优点:

  • 性能影响相对较小(对主进程): BGSAVE 使用子进程进行持久化,主进程可以继续服务客户端请求,对性能影响较小(除了fork()操作本身可能带来的短暂延迟,尤其是在大数据集下)。

  • 恢复速度快: RDB文件是经过压缩的二进制文件,包含了某个时间点上的完整数据快照。因此,在数据恢复时,Redis只需要直接读取和解析这个文件即可,通常比AOF的恢复速度快(尤其是在AOF文件很大且没有使用RDB序言的情况下)。

  • 文件紧凑: RDB文件经过压缩,占用的磁盘空间通常比AOF文件小。

  • 适合备份和灾难恢复: 单个紧凑的RDB文件非常适合进行全量备份,例如每天备份一次,然后可以轻松地将其传输到远程数据中心或存储服务。

缺点:

  • 数据丢失风险较高: RDB是按时间间隔或修改次数进行快照的。如果在两次快照之间Redis服务器发生故障,那么从上一次快照到故障发生这段时间内的所有数据修改都会丢失。这个丢失窗口的大小取决于你的 save 配置。

  • fork()操作的成本: 虽然有COW机制,但在数据集非常大、内存使用率很高的情况下,fork() 操作本身可能会消耗较多的CPU时间和内存资源,甚至可能导致服务短暂卡顿。

  • 数据一致性: RDB文件保存的是某一时刻的快照,如果业务对数据一致性有非常严格的要求(例如,要求能恢复到故障前一秒的状态),RDB可能无法满足。

Redis.conf中与RDB相关的设置

  • save <seconds> <changes>: 自动触发BGSAVE的条件。

  • dbfilename dump.rdb: RDB文件的名称。

  • dir ./: RDB文件和AOF文件存放的目录。

  • stop-writes-on-bgsave-error yes: 当BGSAVE(后台保存)操作出错时,Redis是否停止接受写操作。设置为yes可以及时发现磁盘、权限等问题,防止数据无法持久化。

  • rdbcompression yes: RDB文件是否进行压缩。默认为yes,可以显著减小文件大小,但在保存和加载时会消耗一些CPU。

  • rdbchecksum yes: 在RDB文件的末尾是否加入CRC64校验和。默认为yes。开启后,加载RDB文件时会进行校验,可以提高数据完整性,但保存和加载时会增加约10%的性能消耗。

AOF持久化

什么是AOF

AOF(Append Only File)持久化通过记录服务器接收到的每一个写操作命令(以Redis协议的格式)到一个只追加的文件(默认为 appendonly.aof)中来实现。当Redis重启时,它会重新执行AOF文件中保存的所有写命令,从而恢复数据集。

AOF如何工作

  1. 命令追加 (Append): 当一个写命令被客户端发送到Redis并成功执行后,该命令会被追加到AOF文件的末尾。

  2. 文件同步 (Sync): AOF机制的核心在于如何以及何时将AOF缓冲区中的数据真正写入到磁盘上的AOF文件中。这由 appendfsync 配置项控制。

  • appendfsync always: 每个写命令执行完毕后,都立即调用 fsync() 将AOF缓冲区的数据同步到磁盘。这是最安全的方式,能保证数据基本不丢失(最多丢失一个事件循环中的命令),但性能开销极大,严重影响Redis的QPS。
  • appendfsync everysec (默认值): 每秒调用一次 fsync()。这种方式在性能和数据安全性之间取得了很好的平衡。即使发生故障,最多也只会丢失过去1秒内的数据。
  • appendfsync no: 不主动调用 fsync(),完全依赖操作系统的文件同步机制。数据将由操作系统决定何时刷新到磁盘。速度最快,但数据丢失风险最高。

AOF重写(Rewrite)

随着时间的推移,AOF文件会因为记录了大量的写命令而变得越来越大。例如,对一个计数器执行100次 INCR,AOF文件中会记录100条 INCR 命令,而实际上最终只需要一条 SET 命令就能表示这个计数器的当前值。

为了解决AOF文件过大的问题,Redis提供了AOF重写机制:

  1. 目的: 创建一个新的、更紧凑的AOF文件,这个新文件包含恢复当前数据集所需的最少命令集。
  2. 如何工作:
    • Redis主进程会 fork() 一个子进程(与BGSAVE类似,使用COW)。
    • 子进程读取当前内存中的数据库状态,并将其转换成一系列最简的写命令(例如,多个 LPUSH 可能被一个包含所有元素的 LPUSH 命令替代,或者一个计数器的多次 INCR 被一个 SET 命令替代)。
    • 子进程将这些命令写入到一个新的临时AOF文件中。
    • 在子进程重写期间,父进程接收到的新的写命令仍然会被追加到旧的AOF文件的末尾,同时也会被缓存到一块内存区域中(AOF重写缓冲区)。
    • 当子进程完成新AOF文件的写入后,父进程会将AOF重写缓冲区中的增量命令追加到新的AOF文件的末尾,以确保新旧数据一致。
    • 最后,Redis原子地用新的AOF文件替换旧的AOF文件,并开始向新的AOF文件追加后续命令。
  3. 触发方式:
    • BGREWRITEAOF 命令 (手动): 执行此命令会异步触发AOF重写。
    • 配置文件自动触发 (redis.conf):
      • auto-aof-rewrite-percentage 100: 当AOF文件的当前大小比上一次重写后的大小增长了100%(即翻倍)时,触发重写。
      • auto-aof-rewrite-min-size 64mb: 触发AOF重写的最小AOF文件大小。只有当AOF文件大小同时满足这两个条件时才会自动重写。

AOF文件的加载

当Redis启动时,如果AOF持久化被启用(appendonly yes),Redis会优先加载AOF文件来恢复数据,忽略RDB文件(除非AOF文件不存在或损坏,或者配置了特殊情况)。Redis会逐条执行AOF文件中的命令。

AOF RDB序言 (RDB Preamble - Redis 4.0+): 从Redis 4.0开始,AOF文件在重写时可以在文件开头包含一个RDB格式的快照,后面再跟着增量的AOF记录。这个特性(通过 aof-use-rdb-preamble yes 开启,在Redis 7.0+中默认为yes)极大地提高了AOF恢复的速度,因为它首先像加载RDB一样快速加载基础数据,然后只应用RDB快照之后的增量AOF命令。

AOF的优缺点

优点:

  • 数据更完整,丢失风险更低: 根据appendfsync策略,可以配置为每秒同步一次甚至每个命令同步一次,数据丢失的窗口非常小。everysec策略下最多丢失1秒的数据。

  • 文件可读性高(部分): AOF文件以Redis协议格式存储命令,除了RDB序言部分,大部分是文本格式,理论上可以理解和编辑(但不推荐直接编辑损坏的AOF文件,有专门的修复工具)。

  • 写入操作是追加模式: 如果AOF文件因为磁盘满或其他原因写入不完整,可以使用 redis-check-aof 工具轻松修复,它会移除末尾不完整的命令。

缺点:

  • 文件体积通常比RDB大: 即使经过重写,AOF文件通常也比相同数据集的RDB文件要大,因为它存储的是操作命令序列。

  • 恢复速度可能比RDB慢: 需要逐条执行命令来恢复数据。不过,有了RDB序言后,这个缺点在很大程度上得到了缓解。

  • 性能开销可能略高于RDB: 取决于appendfsync策略。always策略对性能影响很大,everysec策略通常也能接受。

Redis.conf中与AOF相关的设置

  • appendonly no: 是否启用AOF持久化。默认为no,需要改为yes来启用。

  • appendfilename "appendonly.aof": AOF文件的名称。

  • appendfsync everysec: AOF同步策略,可选 always, everysec, no

  • no-appendfsync-on-rewrite no: 在AOF重写期间,主进程是否对追加到旧AOF文件的命令执行fsync。通常设置为yes(或默认让其为no但依赖子进程的fsync)可以避免主进程阻塞。设置为no(即在重写时主进程的 append 操作也会 fsync)会更安全但影响性能。

  • auto-aof-rewrite-percentage 100: 触发自动AOF重写的增长百分比。

  • auto-aof-rewrite-min-size 64mb: 触发自动AOF重写的最小文件大小。

  • aof-load-truncated yes: 如果AOF文件在末尾损坏(例如由于系统崩溃导致写入不完整),Redis启动时是否加载这个不完整的AOF文件。加载后会打印日志通知用户。

  • aof-use-rdb-preamble yes: (Redis 4.0+) 在AOF重写时,是否在AOF文件头部使用RDB格式的序言。默认为yes (Redis 7.0+),建议开启以加速恢复。

阅读量: 53

评论区

登录后发表评论

正在加载评论...
相关阅读

暂无相关文章推荐

返回首页浏览更多文章