Redis持久化的两种方式怎么选择

文章导读
选 RDB 还是 AOF,取决于两件事:你能接受重启后丢多少数据,以及重启时能不能等得起加载时间。先别急着改配置,第一步是把当前实例的真实状态查出来——CONFIG GET save、CONFIG GET appendonly、INFO persistence 这三处输出,基本能说明你现在到底在用什么、有没有在生效。很多人以为自己开了 AOF,实际是配置文件改了但没 CONFIG REWRITE,
📋 目录
  1. Ⅰ Redis持久化的两种方式:先把能核对的事实摆清楚
  2. Ⅱ Redis持久化的两种方式最容易搞错的一点
  3. Ⅲ Redis持久化的两种方式:一个照着就能做完的做法
  4. Ⅳ Redis持久化的两种方式:怎么验证结果对不对
A A

选 RDB 还是 AOF,取决于两件事:你能接受重启后丢多少数据,以及重启时能不能等得起加载时间。先别急着改配置,第一步是把当前实例的真实状态查出来——CONFIG GET save、CONFIG GET appendonly、INFO persistence 这三处输出,基本能说明你现在到底在用什么、有没有在生效。很多人以为自己开了 AOF,实际是配置文件改了但没 CONFIG REWRITE,或者容器里挂载的配置根本不是正在跑的那份。

如果业务不能接受丢失几分钟的数据,先确认 appendonly 实际为 yes 且 appendfsync 的值,再考虑是否需要调整;如果能接受按时间点回档、更在意重启加载速度和文件体积,保留 RDB 就够。两种都开(AOF 加 RDB 前导)在多数版本里是保守做法,代价是磁盘占用和 fork 开销。任何改动先在从库或测试实例上做,确认 INFO persistence 各项状态为 ok 再推到主库。

Redis持久化的两种方式:先把能核对的事实摆清楚

先把版本和路径确认掉,后面的判断都建立在这两项上。版本用 redis-server --version 或 redis-cli INFO server | grep redis_version 查;配置文件和持久化目录用 CONFIG GET dir、CONFIG GET dbfilename、CONFIG GET appendfilename 查。如果实例跑在容器里,还要确认 dir 指向的目录是不是挂载出来的卷,否则重建容器就什么都没了。

能直接核对的字段集中在 INFO persistence:rdb_changes_since_last_save、rdb_last_bgsave_status、aof_enabled、aof_last_bgrewrite_status、aof_last_write_status、aof_current_size、loading。这些是运行时事实,不看配置文件的注释也能判断当前行为。日志位置则取决于 CONFIG GET logfile:为空时输出到标准输出,用 systemd 起的实例通常进 journalctl -u redis。这一节先只摆事实,不下结论。

Redis持久化的两种方式最容易搞错的一点

最常见的误解是“开了 AOF 就等于不丢数据”。实际丢多少由 appendfsync 决定:always 每条命令都落盘,代价是写性能;everysec 每秒刷一次,掉电时可能丢掉这一秒内的写入;no 交给操作系统,丢多少不可控。同理,RDB 的 save 规则只决定什么时候触发一次快照,触发点之间的写入在崩溃时直接消失。

Redis持久化的两种方式怎么选择

能把两种情况区分开的检查动作是:同时执行 redis-cli CONFIG GET appendonly 和 redis-cli INFO persistence | egrep 'aof_enabled|aof_last_write_status|rdb_changes_since_last_save'。如果 appendonly 返回 no、aof_enabled 为 0,那这个实例完全靠 RDB,重启后回到最近一次快照;如果 aof_enabled 为 1,但 aof_last_write_status 不是 ok,说明 AOF 在报错但你可能没注意,这时写命令可能已经被拒绝。

Redis持久化的两种方式:一个照着就能做完的做法

下面这条路径适合“现在只有 RDB、希望把 AOF 打开并保留 RDB 快照”的情况。先把现状导出来留底,出问题能对照:

redis-cli CONFIG GET 'append*' > /tmp/redis-append-before.txt
redis-cli CONFIG GET 'save' >> /tmp/redis-append-before.txt
redis-cli INFO memory | egrep 'used_memory_human|maxmemory_human'
redis-cli INFO persistence

INFO memory 那一步不是凑数:启用 AOF 会触发一次重写,需要 fork,内存余量不足会失败。接着按当前版本 redis.conf 里的注释项对照着改,不要直接照抄别人博客里的数值:

Redis持久化的两种方式怎么选择
appendonly yes
appendfsync everysec
appendfilename "appendonly.aof"
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
save 900 1
save 300 10

不想重启实例的话,可以先在线打开再落盘:

redis-cli CONFIG SET appendonly yes
redis-cli INFO persistence | egrep 'aof_rewrite_in_progress|aof_last_bgrewrite_status|aof_enabled'
redis-cli CONFIG REWRITE

第二步应该看到 aof_rewrite_in_progress:0、aof_last_bgrewrite_status:ok、aof_enabled:1;如果重写还在进行,等一会儿再查一次。CONFIG REWRITE 之后去 dir 目录下确认 appendonly.aof 文件已经生成。

这里最容易踩的坑:CONFIG SET appendonly yes 只改运行时,不写回配置文件,实例一重启就退回原样。必须跟一条 CONFIG REWRITE,或者直接改配置文件后重启。另一个连带坑是 dir 目录权限或磁盘满导致重写失败,此时 aof_last_bgrewrite_status 会变成 err,日志里出现 MISCONF 一类报错。

Redis持久化的两种方式怎么选择

Redis持久化的两种方式:怎么验证结果对不对

分两步验证,先验文件,再验加载。文件层面:

redis-cli SET persist_check 1
redis-cli INFO persistence | egrep 'aof_current_size|aof_last_write_status|rdb_changes_since_last_save'
redis-cli BGSAVE
redis-cli INFO persistence | egrep 'rdb_last_bgsave_status|rdb_changes_since_last_save'

写入后 aof_current_size 应该有增长,aof_last_write_status 为 ok;BGSAVE 之后 rdb_last_bgsave_status 为 ok,rdb_changes_since_last_save 回到 0。如果开头那条 SET 就返回错误,先看 aof_last_write_status 和日志,别继续往下走。

加载层面,在测试实例上做,别在主库上试:重启后在日志里找 DB loaded from appendonly file 或 DB loaded from disk,再 GET persist_check 看值是否还在。也可以用 redis-check-aof appendonly.aof 和 redis-check-rdb dump.rdb 单独检查文件是否完整。正常结果是:命令返回 ok,INFO persistence 里 loading:0、各项 status 为 ok,日志没有反复出现保存失败或重写失败的记录。看到 err 就先停手,回到 dir 的磁盘余量和权限上查,而不是继续调参数。