4. Redis 持久化


文档摘要

Redis 持久化 Redis 持久化详解:代码实践与深度解析 在 Redis 的世界里,数据默认是存储在内存中的,这赋予了它极速的读写性能。然而,内存数据在服务器宕机或重启后会丢失,这对于需要数据持久性的应用场景是不可接受的。为了解决这个问题,Redis 提供了两种主要的持久化机制:RDB (Redis Database) 和 AOF (Append-Only File)。这两种机制各有优缺点,可以根据不同的应用场景和需求选择合适的持久化方案。 RDB 持久化 (快照持久化) RDB 持久化,也称为快照持久化,是指 Redis 将内存中的数据集快照 (snapshot) 以二进制文件的形式保存到磁盘上。

4. Redis 持久化

Redis 持久化详解:代码实践与深度解析

在 Redis 的世界里,数据默认是存储在内存中的,这赋予了它极速的读写性能。然而,内存数据在服务器宕机或重启后会丢失,这对于需要数据持久性的应用场景是不可接受的。为了解决这个问题,Redis 提供了两种主要的持久化机制:RDB (Redis Database)AOF (Append-Only File)。这两种机制各有优缺点,可以根据不同的应用场景和需求选择合适的持久化方案。

1. RDB 持久化 (快照持久化)

RDB 持久化,也称为快照持久化,是指 Redis 将内存中的数据集快照 (snapshot) 以二进制文件的形式保存到磁盘上。当 Redis 需要重启恢复数据时,可以直接加载 RDB 文件,快速恢复数据到快照时的状态。

1.1 RDB 工作原理

RDB 持久化是通过创建快照来实现的。Redis 可以配置在不同的时间间隔和数据变更次数条件下自动触发快照,也可以手动执行命令触发快照。

触发 RDB 快照的方式:

  • 自动触发: 通过配置 redis.conf 文件中的 save 指令,可以设置多个保存点。每个保存点由两个参数组成:secondschanges。当在 seconds 秒内,数据集发生了至少 changes 次修改,就会自动触发 BGSAVE 命令生成 RDB 文件。

  • 手动触发:

    • SAVE 命令: 这是一个同步命令,会阻塞 Redis 服务器,直到 RDB 文件创建完成。在生产环境中,不建议使用 SAVE 命令,因为它会影响 Redis 的性能。

    • BGSAVE 命令: 这是一个异步命令,Redis 会 fork 出一个子进程来执行 RDB 文件的创建,主进程仍然可以继续处理客户端请求。推荐使用 BGSAVE 命令 进行 RDB 持久化。

RDB 文件创建过程 (BGSAVE):

  1. 客户端发送 BGSAVE 命令。

  2. Redis 主进程接收到 BGSAVE 命令后,fork 出一个子进程。

  3. 子进程开始遍历内存中的数据,并将数据写入到一个临时的 RDB 文件 (例如 temp.rdb)。 子进程在遍历数据时,主进程仍然可以处理客户端请求。为了保证快照的一致性,Redis 使用了 copy-on-write (COW) 技术。当主进程需要修改数据时,会将需要修改的数据复制一份,子进程仍然可以读取旧的数据快照。

  4. 子进程完成 RDB 文件的写入后,用临时的 RDB 文件替换旧的 RDB 文件 (通常是 dump.rdb)。

  5. 子进程发送信号通知主进程 RDB 文件创建完成。

  6. 主进程更新统计信息,记录最后一次 RDB 持久化的时间等信息。

1.2 RDB 相关配置

RDB 的配置主要在 redis.conf 文件中进行。

关键配置项:

  • save <seconds> <changes>: 配置自动触发 BGSAVE 的保存点。可以配置多个 save 指令。

    • 例如:

      save 900 1 # 900 秒 (15 分钟) 内,至少 1 次 key 修改,触发 BGSAVE save 300 10 # 300 秒 (5 分钟) 内,至少 10 次 key 修改,触发 BGSAVE save 60 10000 # 60 秒 (1 分钟) 内,至少 10000 次 key 修改,触发 BGSAVE
    • 注释掉所有 save 指令可以禁用 RDB 持久化。

  • stop-writes-on-bgsave-error yes|no: 当 BGSAVE 出错时,是否停止写入操作。

    • yes: 如果 BGSAVE 出错,Redis 将停止接受新的写入操作,防止数据不一致。

    • no: 即使 BGSAVE 出错,Redis 仍然继续接受写入操作。

    • 建议设置为 yes,确保数据一致性。

  • rdbcompression yes|no: 是否对 RDB 文件进行压缩。

    • yes: 压缩 RDB 文件,可以减小文件大小,但会消耗 CPU 资源。

    • no: 不压缩 RDB 文件,文件较大,但节省 CPU 资源。

    • 通常建议设置为 yes,在磁盘空间和 CPU 之间权衡。

  • rdbchecksum yes|no: 是否在 RDB 文件中添加校验和。

    • yes: 在 RDB 文件末尾添加校验和,用于检测 RDB 文件是否损坏。

    • no: 不添加校验和。

    • 建议设置为 yes,确保数据可靠性。

  • dir ./: RDB 文件和 AOF 文件 (如果启用 AOF) 的存放目录。

    • 可以修改为其他目录,例如 /var/lib/redis/
  • dbfilename dump.rdb: RDB 文件的名称。

    • 可以自定义 RDB 文件名。

示例 redis.conf RDB 配置片段:

save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dir ./ dbfilename dump.rdb

1.3 RDB 代码实践

1. 手动触发 RDB 快照 (BGSAVE):

可以使用 Redis 客户端 (例如 redis-cli) 连接到 Redis 服务器,然后执行 BGSAVE 命令手动触发 RDB 快照。

redis-cli bgsave

执行 BGSAVE 命令后,Redis 服务器会返回 "Background saving started" 表示后台 RDB 快照任务已经启动。

2. 检查 RDB 快照是否成功:

可以使用 LASTSAVE 命令查看最后一次成功执行 RDB 快照的时间戳。

redis-cli lastsave

返回的是 Unix 时间戳,可以使用 date -d @<timestamp> 命令转换为可读的时间格式。

3. 查看 RDB 相关信息:

可以使用 INFO persistence 命令查看 RDB 和 AOF 的持久化信息。

redis-cli info persistence

返回的信息包括:

  • rdb_last_save_time: 最后一次成功 RDB 快照的时间戳。

  • rdb_bgsave_in_progress: 是否正在进行 BGSAVE 操作 (0 表示否,1 表示是)。

  • rdb_last_bgsave_status: 最后一次 BGSAVE 操作的状态 (ok 或 err)。

  • rdb_changes_since_last_save: 上次 RDB 快照后,数据集的修改次数。

4. 修改 RDB 配置并重启 Redis 服务器:

修改 redis.conf 文件中的 RDB 相关配置后,需要重启 Redis 服务器才能使配置生效。

# 停止 Redis 服务器 redis-cli shutdown # 启动 Redis 服务器 redis-server /path/to/redis.conf

5. RDB 文件恢复数据:

当 Redis 服务器启动时,如果 dir 目录下存在 dump.rdb 文件,Redis 会自动加载该文件,恢复数据到 RDB 快照时的状态。

代码实践示例 (Python + redis-py):

import redis import time # 连接 Redis 服务器 r = redis.Redis(host='localhost', port=6379, db=0) # 设置一些数据 r.set('mykey1', 'value1') r.set('mykey2', 'value2') # 手动触发 BGSAVE print("开始 BGSAVE...") r.bgsave() # 等待一段时间,确保 BGSAVE 完成 (实际应用中可以使用 redis-py 的 pubsub 监听 bgsave-done 事件) time.sleep(1) # 查看 RDB 相关信息 info = r.info('persistence') print(info) # 模拟 Redis 重启 (实际应用中需要手动重启 Redis 服务器) # 这里只是为了演示数据恢复,实际重启后 redis-py 需要重新连接 # 假设 Redis 重启后,重新连接 r_restarted = redis.Redis(host='localhost', port=6379, db=0) # 检查数据是否恢复 print("重启后 mykey1 的值:", r_restarted.get('mykey1')) print("重启后 mykey2 的值:", r_restarted.get('mykey2'))

1.4 RDB 优缺点

优点:

  • 性能高: RDB 持久化是快照方式,子进程负责写入 RDB 文件,主进程可以继续处理客户端请求,对性能影响较小。

  • 恢复速度快: RDB 文件是紧凑的二进制文件,恢复数据时直接加载 RDB 文件到内存,速度非常快。

  • 适用于备份: RDB 文件非常适合用于备份,可以定期备份 RDB 文件到其他存储介质,用于灾难恢复。

缺点:

  • 数据丢失风险: RDB 是快照方式,如果在两次快照之间 Redis 服务器宕机,会丢失这段时间内的数据。数据丢失的量取决于 save 指令配置的快照间隔。

  • fork 开销: BGSAVE 命令需要 fork 子进程,如果数据集非常大,fork 过程可能会比较耗时,并且会占用一定的内存空间 (copy-on-write)。

2. AOF 持久化 (Append-Only File 持久化)

AOF 持久化是将 Redis 服务器接收到的每个写命令 (append-only) 追加到 AOF 文件的末尾。当 Redis 需要重启恢复数据时,会重新执行 AOF 文件中的所有命令,重建数据集。

2.1 AOF 工作原理

AOF 持久化记录的是 Redis 服务器接收到的 写命令 (例如 SET, HSET, SADD, DEL 等),而不是数据本身。

AOF 文件写入过程:

  1. 客户端发送写命令。

  2. Redis 服务器执行命令,并将命令追加到 AOF 缓冲区 (aof_buf)。

  3. 根据配置的 appendfsync 策略,将 AOF 缓冲区的数据刷入到 AOF 文件 (磁盘)。

  4. Redis 服务器向客户端返回命令执行结果。

appendfsync 策略:

appendfsync 指令控制 AOF 缓冲区数据刷入磁盘的频率,影响数据安全性和性能。

  • always: 每次写命令都同步刷入磁盘。数据安全性最高,性能最差。 即使 Redis 服务器宕机,最多只会丢失最后一次写操作的数据。

  • everysec: 每秒钟刷入磁盘一次 (默认策略)。数据安全性较高,性能适中。 如果系统崩溃,可能会丢失最近一秒钟的数据。通常情况下,everysec 已经足够安全。

  • no: 由操作系统决定何时刷入磁盘。数据安全性最低,性能最好。 如果系统崩溃,可能会丢失较多的数据。不建议使用 no 策略。

AOF 重写 (Rewrite):

随着时间的推移,AOF 文件会越来越大,其中会包含很多冗余的命令 (例如多次修改同一个 key 的命令)。为了减小 AOF 文件的大小,Redis 提供了 AOF 重写机制。

AOF 重写原理:

AOF 重写并不是对旧的 AOF 文件进行重写,而是 Redis 创建一个新的 AOF 文件,只包含重建当前数据集所需的最少命令。例如,如果 AOF 文件中包含多次 SET mykey value 命令,重写后的 AOF 文件可能只会包含一条 SET mykey value 命令。

AOF 重写触发方式:

  • 自动触发: 通过配置 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 指令,可以设置自动触发 AOF 重写的条件。

    • auto-aof-rewrite-percentage: 当前 AOF 文件大小超过上次重写后 AOF 文件大小的百分比阈值时触发重写。

    • auto-aof-rewrite-min-size: AOF 文件最小大小,只有当 AOF 文件大小超过这个值时,才会尝试触发重写。

  • 手动触发: 可以使用 BGREWRITEAOF 命令手动触发 AOF 重写。这是一个异步命令,Redis 会 fork 出一个子进程来执行 AOF 重写。

AOF 重写过程 (BGREWRITEAOF):

  1. 客户端发送 BGREWRITEAOF 命令。

  2. Redis 主进程接收到 BGREWRITEAOF 命令后,fork 出一个子进程。

  3. 子进程开始遍历内存中的数据,并将重建数据集所需的命令写入到一个临时的 AOF 文件 (例如 temp.aof)。 子进程在遍历数据时,主进程仍然可以处理客户端请求。

  4. 在重写期间,主进程接收到的新的写命令,会同时写入到 AOF 缓冲区重写缓冲区 重写缓冲区用于保证在重写期间,新的写命令不会丢失。

  5. 子进程完成 AOF 重写后,将重写缓冲区中的命令追加到临时的 AOF 文件末尾,保证数据一致性。

  6. 子进程用临时的 AOF 文件替换旧的 AOF 文件 (通常是 appendonly.aof)。

  7. 子进程发送信号通知主进程 AOF 重写完成。

  8. 主进程更新统计信息,记录最后一次 AOF 重写的时间等信息。

2.2 AOF 相关配置

AOF 的配置主要在 redis.conf 文件中进行。

关键配置项:

  • appendonly yes|no: 是否启用 AOF 持久化。

    • yes: 启用 AOF 持久化。

    • no: 禁用 AOF 持久化 (默认值)。

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

    • 可以自定义 AOF 文件名。
  • appendfsync always|everysec|no: AOF 缓冲区数据刷入磁盘的策略。

    • 建议设置为 everysec,平衡数据安全性和性能。
  • no-appendfsync-on-rewrite yes|no: 在 AOF 重写期间,是否禁用 appendfsync

    • yes: 如果正在进行 AOF 重写,并且设置为 alwayseverysec,则会临时设置为 no,以减少磁盘 I/O 开销,提高重写性能。但会降低数据安全性,重写期间如果 Redis 宕机,可能会丢失更多数据。

    • no: 即使正在进行 AOF 重写,仍然按照配置的 appendfsync 策略刷入磁盘。数据安全性更高,但会影响重写性能。

    • 通常建议设置为 no,优先保证数据安全。

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

    • 例如设置为 100,表示当前 AOF 文件大小是上次重写后 AOF 文件大小的两倍 (100%) 时触发重写。

    • 设置为 0 表示禁用自动 AOF 重写。

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

    • 只有当 AOF 文件大小超过这个值时,才会尝试触发重写。

示例 redis.conf AOF 配置片段:

appendonly yes appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb

2.3 AOF 代码实践

1. 启用 AOF 持久化:

修改 redis.conf 文件,将 appendonly 设置为 yes,并重启 Redis 服务器。

2. 查看 AOF 相关信息:

可以使用 INFO persistence 命令查看 AOF 的持久化信息。

redis-cli info persistence

返回的信息包括:

  • aof_enabled: 是否启用 AOF 持久化 (0 表示否,1 表示是)。

  • aof_rewrite_in_progress: 是否正在进行 AOF 重写 (0 表示否,1 表示是)。

  • aof_last_rewrite_status: 最后一次 AOF 重写操作的状态 (ok 或 err)。

  • aof_current_size: 当前 AOF 文件的大小。

  • aof_base_size: 上次 AOF 重写后 AOF 文件的大小。

  • aof_pending_rewrite: 是否有等待执行的 AOF 重写任务。

  • aof_buffer_length: AOF 缓冲区的大小。

  • aof_rewrite_buffer_length: AOF 重写缓冲区的大小。

3. 手动触发 AOF 重写 (BGREWRITEAOF):

可以使用 BGREWRITEAOF 命令手动触发 AOF 重写。

redis-cli bgrewriteaof

执行 BGREWRITEAOF 命令后,Redis 服务器会返回 "Background append only file rewriting started" 表示后台 AOF 重写任务已经启动。

4. 修改 AOF 配置并重启 Redis 服务器:

修改 redis.conf 文件中的 AOF 相关配置后,需要重启 Redis 服务器才能使配置生效。

5. AOF 文件恢复数据:

当 Redis 服务器启动时,如果启用了 AOF 持久化,并且 dir 目录下存在 appendonly.aof 文件,Redis 会自动加载该文件,重新执行 AOF 文件中的所有命令,重建数据集。

代码实践示例 (Python + redis-py):

import redis import time # 连接 Redis 服务器 r = redis.Redis(host='localhost', port=6379, db=0) # 启用 AOF 持久化 (需要在 redis.conf 中配置 appendonly yes 并重启 Redis) # 设置一些数据 r.set('aofkey1', 'value1') r.set('aofkey2', 'value2') # 等待一段时间,让数据写入 AOF 文件 (根据 appendfsync 策略) time.sleep(2) # 手动触发 AOF 重写 print("开始 BGREWRITEAOF...") r.bgrewriteaof() # 等待一段时间,确保 AOF 重写完成 (实际应用中可以使用 redis-py 的 pubsub 监听 aof-rewrite-done 事件) time.sleep(1) # 查看 AOF 相关信息 info = r.info('persistence') print(info) # 模拟 Redis 重启 (实际应用中需要手动重启 Redis 服务器) # 这里只是为了演示数据恢复,实际重启后 redis-py 需要重新连接 # 假设 Redis 重启后,重新连接 r_restarted = redis.Redis(host='localhost', port=6379, db=0) # 检查数据是否恢复 print("重启后 aofkey1 的值:", r_restarted.get('aofkey1')) print("重启后 aofkey2 的值:", r_restarted.get('aofkey2'))

2.4 AOF 优缺点

优点:

  • 数据安全性更高: AOF 持久化可以配置不同的 appendfsync 策略,即使使用 everysec 策略,最多也只会丢失最近一秒钟的数据。使用 always 策略,数据安全性最高。

  • 数据恢复更完整: AOF 记录的是写命令,数据恢复时重新执行命令,可以保证数据恢复的完整性。

  • 文件可读性好: AOF 文件是文本文件,可以打开查看和分析,方便进行数据审计和故障排查。

缺点:

  • 性能相对较低: AOF 持久化每次写操作都需要写入 AOF 文件,性能比 RDB 快照持久化略低,尤其是在 always 策略下。

  • 文件体积较大: AOF 文件记录的是所有写命令,文件体积通常比 RDB 文件大。

  • 恢复速度较慢: AOF 恢复数据需要重新执行 AOF 文件中的所有命令,恢复速度比 RDB 加载快照文件慢。

3. RDB 和 AOF 的选择与混合使用

选择建议:

  • 对数据安全性要求不高,可以容忍一定程度的数据丢失,并且需要高性能和快速恢复: 只使用 RDB 持久化。 例如,作为缓存使用的 Redis 服务,可以考虑只使用 RDB。

  • 对数据安全性要求较高,希望尽可能减少数据丢失,并且可以接受一定的性能损失: 只使用 AOF 持久化。 例如,存储重要业务数据的 Redis 服务,建议使用 AOF。

  • 希望兼顾数据安全性和性能,并且希望快速重启恢复: 同时启用 RDB 和 AOF 持久化 (混合持久化)。 Redis 4.0 版本之后引入了混合持久化模式,结合了 RDB 和 AOF 的优点。

混合持久化 (Redis 4.0+):

混合持久化模式下,AOF 文件的前半部分是 RDB 格式的数据,后半部分是 AOF 格式的命令追加记录。

混合持久化工作原理:

  1. 触发 AOF 重写时,Redis 会生成一个 RDB 格式的文件作为 AOF 文件的前半部分。

  2. 在 RDB 文件生成期间,新的写命令仍然会写入到 AOF 缓冲区和重写缓冲区。

  3. RDB 文件生成完成后,将重写缓冲区中的命令以 AOF 格式追加到 RDB 文件末尾。

  4. 用新的混合格式的 AOF 文件替换旧的 AOF 文件。

混合持久化优点:

  • 兼顾 RDB 和 AOF 的优点: 既能像 RDB 一样快速重启恢复,又能像 AOF 一样尽可能减少数据丢失。

  • 恢复速度快: 重启时先加载 RDB 部分,然后执行 AOF 增量命令,恢复速度比纯 AOF 快。

  • 数据安全性较高: AOF 增量命令可以保证在 RDB 快照之后的数据不丢失。

启用混合持久化配置:

redis.conf 文件中,除了启用 appendonly yes 和配置 appendfsync 策略外,还需要启用 aof-use-rdb-preamble yes 指令。

appendonly yes appendfilename "appendonly.aof" appendfsync everysec aof-use-rdb-preamble yes # 启用混合持久化

总结:

RDB 和 AOF 是 Redis 提供的两种主要的持久化机制,各有优缺点。可以根据实际应用场景的需求,选择合适的持久化方案。对于大多数需要数据持久化的场景,推荐使用 AOF 持久化或混合持久化,以保证数据的安全性和可靠性。

在实际应用中,还需要结合监控和备份策略,定期检查持久化状态,并做好数据备份,以应对各种突发情况,确保 Redis 服务的稳定运行和数据安全。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U