Redis 持久化与高可用:RDB、AOF、主从复制与哨兵完整配置

一、结论先给

方案 数据安全 性能影响 恢复速度 适用
仅 RDB 丢最后一次快照之后的数据(可能几分钟) 小 快 纯缓存、可重建
仅 AOF 最多丢 1 秒(everysec) 中 慢(要重放命令) 要尽量不丢
RDB + AOF 混合(推荐) 最多丢 1 秒 中 快 绝大多数场景

结论:生产环境开 appendonly yes + aof-use-rdb-preamble yes(混合持久化,Redis 4.0+ 默认开启),这是兼顾安全与恢复速度的标准配置。

但记住:Redis 再怎么持久化也不如关系型数据库可靠,缓存丢了能重建,唯一数据源必须放数据库。

👉 排查持久化/复制故障时,把 Redis 日志粘进 日志分析工具 能快速定位错误类型和高发时段。

二、RDB:时间点快照

2.1 机制

RDB 是把某一刻的全量数据写成二进制快照(dump.rdb)。

SAVE                 -- 同步保存 ⚠️ 阻塞主线程,生产禁用
BGSAVE               -- ⭐ 后台保存,fork 子进程写
LASTSAVE             -- 上次成功保存的时间戳

自动触发配置:

# redis.conf:900 秒内至少 1 次改动则触发,300 秒内 10 次,60 秒内 10000 次
save 900 1
save 300 10
save 60 10000

dbfilename dump.rdb
dir /var/lib/redis
stop-writes-on-bgsave-error yes     # 快照失败时停止写入,提醒你磁盘有问题
rdbcompression yes                  # 压缩(LZF),CPU 换空间
rdbchecksum yes                     # 校验和

2.2 RDB 的两个要点

1. fork 的代价:BGSAVE 会 fork 子进程,采用写时复制(COW)。父进程内存越大,fork 时的页表拷贝越慢(几个 G 的实例可能阻塞几十到几百毫秒)。数据量很大时要监控 latest_fork_usec:

INFO stats | grep latest_fork_usec     # 上次 fork 耗时(微秒),超过 1 秒要警惕

2. 丢失窗口:两次快照之间的数据会丢。按 save 60 10000 算,最坏丢 1 分钟的数据。

三、AOF:命令日志

3.1 机制与刷盘策略

AOF 把每个写命令追加到日志文件,重启时重放。

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec       # ⭐ 三选一
appendfsync 行为 最多丢 性能
always 每条命令都刷盘 几乎不丢 最差(不推荐)
everysec 每秒刷一次 1 秒(默认,推荐) 好
no 交给操作系统决定 可能几十秒 最好(不推荐)

3.2 AOF 重写

AOF 会越来越大(对同一个 key 改 100 次就记 100 条),所以要重写:根据当前内存中的数据生成一份最小的命令集。

BGREWRITEAOF             -- 手动触发后台重写

自动触发:

auto-aof-rewrite-percentage 100   # 比上次重写后增长了 100%
auto-aof-rewrite-min-size 64mb    # 且文件至少 64MB
no-appendfsync-on-rewrite no      # 重写时是否暂停 fsync;yes 可减少阻塞但可能丢更多

⚠️ 重写的坑:auto-aof-rewrite-min-size 太小会导致频繁重写;重写期间需要额外内存(fork + 缓冲区),要确保机器有足够空闲内存,否则会 OOM。

3.3 混合持久化(推荐)

aof-use-rdb-preamble yes      # Redis 4.0+ 默认 yes

开启后 AOF 重写时,前半段用 RDB 二进制格式、后半段追加增量 AOF 命令。兼顾了 RDB 的加载速度和 AOF 的低丢失窗口。

文件结构长这样:

[RDB 格式的全量数据][AOF 格式的增量命令]

验证:

head -c 100 appendonly.aof | strings | head -5    # 能看到 "REDIS" 字样说明含 RDB 段

3.4 AOF 文件损坏修复

redis-check-aof --fix appendonly.aof
redis-check-rdb dump.rdb

修复会截断损坏部分(可能丢数据),执行前先备份原文件。

四、数据恢复与备份

# 备份就是拷贝文件(AOF 优先于 RDB 加载)
cp /var/lib/redis/appendonly.aof /data/backup/appendonly_$(date +%F).aof
cp /var/lib/redis/dump.rdb /data/backup/dump_$(date +%F).rdb

# 恢复:停 Redis → 放文件 → 改权限 → 启动
systemctl stop redis
cp appendonly_xxx.aof /var/lib/redis/appendonly.aof
chown redis:redis /var/lib/redis/appendonly.aof
systemctl start redis

加载优先级:AOF 开启时优先加载 AOF 文件(数据更新更完整),AOF 关闭才加载 RDB。

⚠️ RDB 和 AOF 同时存在时,不会合并两份数据,只加载 AOF。

五、主从复制

5.1 配置

从库 redis.conf(Redis 5.0+ 用 replicaof,旧版是 slaveof):

replicaof 10.0.0.10 6379        # 主库地址
masterauth '主库密码'            # 主库有密码时必须配
replica-read-only yes           # 从库只读(默认)
repl-diskless-sync yes          # 无盘复制(网络好时更快,避免写磁盘)
repl-backlog-size 64mb          # 复制积压缓冲区,决定断线后能否增量续传

也可以在运行时生效(重启失效):

REPLICAOF 10.0.0.10 6379
REPLICAOF NO ONE        -- ⭐ 提升为主库(故障切换时用)

5.2 复制状态

INFO replication
-- 主库视角:
-- role:master
-- connected_slaves:2
-- slave0:ip=10.0.0.11,port=6379,state=online,offset=123456,lag=0

-- 从库视角:
-- role:slave
-- master_link_status:up        ⭐ 必须 up
-- master_last_io_seconds_ago:1
-- slave_repl_offset:123456

关键字段:master_link_status:up、lag(延迟秒数),offset 差值是真实延迟。

5.3 全量同步 vs 增量同步

类型 触发 代价
全量 从库首次连、offset 不在积压缓冲区内 主库 BGSAVE + 传整个 RDB + 从库加载,大实例很重
增量 短暂断连且 offset 还在 repl-backlog 里 只传缺失的命令,很轻

避免全量同步的关键:把 repl-backlog-size 调大(默认 1MB 太小,建议 64-256MB),让短暂断网能走增量。

repl-backlog-size 128mb
repl-backlog-ttl 3600
client-output-buffer-limit slave 512mb 128mb 300   # 放宽从库输出缓冲,防同步被中断

全量同步反复发生的排查:

INFO stats | grep sync_full        -- 全量同步次数
INFO stats | grep sync_partial_ok  -- 增量成功次数

六、哨兵(Sentinel):自动故障转移

6.1 配置

# /etc/redis/sentinel.conf(每个哨兵节点都配)
port 26379
sentinel monitor mymaster 10.0.0.10 6379 2       # 2 = 几个哨兵认为挂了才判定客观下线
sentinel auth-pass mymaster '主库密码'
sentinel down-after-milliseconds mymaster 5000   # 5 秒无响应判主观下线
sentinel parallel-syncs mymaster 1               # 故障转移后同时同步的从库数
sentinel failover-timeout mymaster 60000

启动:

redis-sentinel /etc/redis/sentinel.conf
# 或 redis-server /etc/redis/sentinel.conf --sentinel

⚠️ 哨兵至少要 3 个节点(且部署在不同机器),quorum 设 2。两个节点无法形成有效多数派。

6.2 选举流程

1. 某个哨兵发现主库 5 秒无响应 → 主观下线(sdown)
2. 它询问其他哨兵,达到 quorum 数量同意 → 客观下线(odown)
3. 哨兵之间选出一个 leader(Raft 式)
4. leader 挑一个从库:优先级高 → offset 大(数据新)→ runid 小
5. 对该从库执行 REPLICAOF NO ONE,再让其他从库指向新主库
6. 旧主库恢复后被降级为从库

从库优先级配置(想指定某台优先被提升):

replica-priority 100     # 数字越小优先级越高;设为 0 表示永不提升

6.3 客户端接入

客户端不能直连主库 IP,要连哨兵拿地址:

// Jedis
Set<String> sentinels = new HashSet<>(Arrays.asList(
    "10.0.0.10:26379", "10.0.0.11:26379", "10.0.0.12:26379"));
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels, config);

// Spring Boot
spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 10.0.0.10:26379,10.0.0.11:26379,10.0.0.12:26379
    password: xxx
# 查询当前主库
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL slaves mymaster
redis-cli -p 26379 SENTINEL ckquorum mymaster     -- 检查哨兵数是否够

6.4 哨兵解决不了的问题

问题 说明 方案
主库写压力 只有一个主,写无法扩展 Redis Cluster 分片
单机容量上限 数据超过单机内存 Redis Cluster
跨机房 网络分区可能双主 至少三机房部署,或接受脑裂风险

七、方案选型

规模/需求 方案
纯缓存、丢了能重建 单机 + RDB,甚至不开持久化
要尽量不丢、单实例够用 主从 + 哨兵 + 混合持久化
数据量大、写压力大 Redis Cluster(3 主 3 从起)
云上 云厂商托管版(自动主备、备份、扩缩容)

八、常见误区

  1. 以为开了 AOF 就万无一失:everysec 仍可能丢 1 秒;Redis 持久化不等同于数据库的事务保证。
  2. auto-aof-rewrite-min-size 不调:默认 64MB 在大写入场景下频繁重写,IO 抖动。
  3. 生产执行 SAVE:同步阻塞,几百万 key 能卡住几秒。
  4. repl-backlog-size 用默认 1MB:网络抖一下就触发全量同步,主库 IO 打满。
  5. 哨兵只部署 2 个:无法形成多数派,等于没高可用。
  6. 客户端写死主库 IP:故障转移后应用连的还是旧主(已变从库),写入直接报错。
  7. masterauth 忘了配:从库同步一直失败,master_link_status:down。

九、几条纪律

  1. 生产开混合持久化(appendonly yes + aof-use-rdb-preamble yes),appendfsync everysec。
  2. repl-backlog-size 调到 64-256MB,避免网络抖动触发全量同步。
  3. 哨兵至少 3 节点、跨机器部署,quorum = 节点数/2 + 1。
  4. 客户端通过哨兵/集群方式连接,绝不写死主库 IP。
  5. 定期备份 RDB/AOF 到异地,且验证过能恢复。
  6. 监控 master_link_status、latest_fork_usec、used_memory、sync_full 四个指标。
  7. Redis 里不存唯一数据源,任何时刻都要能从数据库重建。

十、延伸阅读

👉 相关在线工具:Linux 命令速查 · 日志分析,免登录、浏览器内处理。

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具