Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)

发布于:2025-09-12 ⋅ 阅读:(22) ⋅ 点赞:(0)

这篇是我把几套生产环境踩坑与复盘整理成的一份“从 0 到 1 + 长期可维护”的实践文。目标是:明确策略、给出默认可用的配置模板、把常见坑一次讲透
适用场景:新项目选型、老项目稳定性加固、从单机迁移到 HA/Cluster、应对数据安全与故障切换要求。


目录

  1. 核心结论先说在前面

  2. 持久化:RDB vs AOF(以及“二者结合”的推荐范式)

  3. 高可用形态:主从复制基础、Sentinel、Cluster

  4. 典型拓扑与配置模板(可直接改名上线)

  5. 备份/恢复/演练:从脚本到流程

  6. 性能与稳定性调优(内核、Redis 配置、内存与淘汰)

  7. 生产避坑清单(高频问题→定位→对策)

  8. 迁移与升级策略(Standalone→Sentinel、Sentinel→Cluster)

  9. 运维清单与值班自检表


1. 核心结论先说在前面

  • 持久化策略

    • 低延迟场景:首选 RDB + AOF(everysec) 组合。RDB 提供“冷备点”,AOF 控制丢失窗口(通常 ≤1s)。

    • 极端数据安全:AOF(appendfsync always),但写放大大、吞吐下降明显,一般不建议全站开启。

    • 只读/可丢缓存:可以 仅 RDB 或甚至关闭持久化,靠上游重建(但要清楚发生重启的业务影响)。

  • 高可用形态

    • 单实例 HA:主从 + Sentinel(入门首选,维护简单,客户端/驱动支持成熟)。

    • 水平扩展 + HA:Redis Cluster(3 主 3 备起步)。选它是因为容量/吞吐/隔离/自治,也要接受跨槽限制

  • 复制一致性:Redis 复制本质是异步。务必配合:

    • min-replicas-to-write / min-replicas-max-lag(提升写安全,避免主孤岛)

    • 按需使用 WAIT 命令等待复制到 N 个副本再返回(强一致片段,但影响时延)。

  • 默认稳妥配置(可作为起步模板):

    • appendonly yesappendfsync everysecno-appendfsync-on-rewrite yes

    • save 900 1 / save 300 10 / save 60 10000(按业务写入频率调整)

    • stop-writes-on-bgsave-error yes(防止静默数据丢失)

    • repl-backlog-size 256mb(按主写入速率与断链窗口估算)

    • maxmemory + 合理淘汰策略(缓存型业务尤为重要)


2. 持久化:RDB vs AOF(以及“二者结合”的推荐范式)

2.1 RDB(快照)

  • 原理:定期把内存快照写入 .rdb 文件(BGSAVE 子进程)。

  • 优点:文件小、恢复快、对线上写入影响较小(写时复制)。

  • 缺点:两次快照之间的新写入可能丢失

  • 关键配置

    # 触发条件按需调整(示例:90% 读多写少)
    save 900 1
    save 300 10
    save 60 10000
    
    rdbcompression yes
    rdbchecksum yes
    stop-writes-on-bgsave-error yes
    

2.2 AOF(追加日志)

  • 原理:把写命令追加到日志;重启时“重放”恢复。Redis 新版本使用 多段 AOF(BASE/INCR),并支持 RDB 作为 AOF 前导以加速恢复。

  • 优点更小的数据丢失窗口everysec 常见);可以手工编辑修复尾部。

  • 缺点:文件膨胀、重写时可能有额外 I/O 压力。

  • 关键配置

    appendonly yes
    appendfsync everysec           # 安全与性能折中(常用)
    no-appendfsync-on-rewrite yes  # 重写期间尽量少阻塞
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    aof-load-truncated yes
    # 新版:AOF 使用 RDB 作为 preamble(通常默认开启,恢复更快)
    # aof-use-rdb-preamble yes
    

2.3 推荐组合:RDB + AOF(everysec)

  • 为什么:RDB 提供“恢复基线”,AOF 提供“小丢失窗口”;重启时优先加载 AOF,若 AOF 不可用仍可回退到 RDB。

  • 通用建议先做对的,再做快的。先把 AOF + 定期 RDB 固住,再谈参数与 I/O 优化。


3. 高可用形态:主从复制基础、Sentinel、Cluster

3.1 主从复制基础

  • 复制机制:初次全量同步 + 之后命令流增量;断联后支持部分重同步(PSYNC)

  • 常用参数

    replica-read-only yes
    repl-diskless-sync yes
    repl-diskless-sync-delay 5
    repl-backlog-size 256mb
    min-replicas-to-write 1         # 至少有1个副本在线主才写
    min-replicas-max-lag 5          # 超过5s延迟则视为不安全
    
  • 只读从库:默认只读,适合做报表与只读流量分流(避免主库压力过大)。

3.2 Sentinel(哨兵)

  • 作用:自动故障检测、投票选主、通知客户端新主地址

  • 部署:至少 3 个哨兵实例(奇数),建议与 Redis 节点分机房/可用区部署。

  • 核心配置sentinel.conf):

    port 26379
    daemonize yes
    
    # 监控一个 master:<name> <ip> <port> <quorum>
    sentinel monitor app-master 10.0.0.10 6379 2
    
    sentinel down-after-milliseconds app-master 5000
    sentinel failover-timeout app-master 60000
    sentinel parallel-syncs app-master 1
    
    # 可选:通知/脚本
    # sentinel notification-script app-master /opt/sentinel/notify.sh
    # sentinel client-reconfig-script app-master /opt/sentinel/reconfig.sh
    
  • 客户端接入

    • 方式一:连接哨兵,按 master name 查询主;

    • 方式二:用支持 Sentinel 的驱动(Java/Lettuce、Go/redis、Node/ioredis 等)自动刷新连接。

3.3 Redis Cluster(分片+高可用)

  • 特性:16384 槽位(hash slot)分布到多主节点,每个主有 ≥1 个副本;主节点故障时由副本升主。

  • 限制:多键操作需在同槽(可用 {tag} 控制);Lua 脚本/事务等有跨槽限制。

  • 常用参数redis.conf):

    cluster-enabled yes
    cluster-config-file nodes.conf
    cluster-node-timeout 15000
    cluster-announce-ip 10.0.0.10     # 跨网段/容器时要显式设置
    cluster-announce-port 6379
    cluster-announce-bus-port 16379
    
  • 集群建议规模3 主 3 备起步(6 节点),单 AZ 内至少 3 台物理/虚拟机,尽量跨 AZ。

  • 创建与检查

    # 创建集群(示例6节点,3主3从)
    redis-cli --cluster create \
      10.0.0.10:6379 10.0.0.11:6379 10.0.0.12:6379 \
      10.0.0.13:6379 10.0.0.14:6379 10.0.0.15:6379 \
      --cluster-replicas 1
    
    # 查看拓扑
    redis-cli -c -h 10.0.0.10 -p 6379 cluster nodes
    redis-cli -c -h 10.0.0.10 -p 6379 cluster info
    

4. 典型拓扑与配置模板(可直接改名上线)

4.1 单实例高可用(主从 + Sentinel)

  • 拓扑1 主 + 2 从 + 3 Sentinel

  • 适用:中小体量、强一致要求不高、运维成本友好。

  • 主库片段(redis.conf)

    port 6379
    # 持久化
    save 900 1
    save 300 10
    save 60 10000
    appendonly yes
    appendfsync everysec
    no-appendfsync-on-rewrite yes
    
    # 复制与安全
    repl-diskless-sync yes
    repl-backlog-size 256mb
    min-replicas-to-write 1
    min-replicas-max-lag 5
    
    # 内存
    maxmemory 16gb
    maxmemory-policy allkeys-lru
    
    # 安全(按需)
    # requirepass <pass>
    # aclfile /etc/redis/users.acl
    
  • 从库片段

    replicaof 10.0.0.10 6379
    replica-read-only yes
    
  • Sentinel(3 份,仅示例一份):见上 3.2 配置。

4.2 Redis Cluster(3 主 3 从)

  • 每个节点的 redis.conf(变化项:cluster-announce-ip、端口):

    port 6379
    cluster-enabled yes
    cluster-config-file nodes.conf
    cluster-node-timeout 15000
    
    # 持久化
    appendonly yes
    appendfsync everysec
    save 900 1
    save 300 10
    
    # 内存淘汰(缓存型很关键)
    maxmemory 16gb
    maxmemory-policy allkeys-lru
    
  • 创建集群:参考 3.3 脚本。

  • 扩容/缩容:使用 redis-cli --cluster reshardadd-nodedel-node,务必在低峰期进行。


5. 备份/恢复/演练:从脚本到流程

5.1 备份策略

  • RDB 冷备:定期复制 .rdb 到异地/对象存储(带版本与校验);

  • AOF:先 BGREWRITEAOF 生成紧凑版,再打包上传(避免巨大日志)。

  • 频率:日常建议 日备 + 周全量,重要业务增加关键时点手动快照。

  • 校验

    redis-check-rdb dump-2025-09-01.rdb
    redis-check-aof appendonly.aof
    

5.2 恢复流程(单实例)

  1. 下线流量、停止 Redis;

  2. 备份当前数据文件到临时目录(防误操作);

  3. 放入目标 dump.rdb(或 appendonly.aof),确保权限与 owner 一致;

  4. 启动 Redis,观察日志与 INFO

  5. 业务侧灰度放量。

5.3 恢复流程(Cluster)

  • 同槽迁移:尽量在集群内重建节点而非整体“外部恢复”;

  • 节点级恢复:按节点维度恢复 RDB/AOF,重入集群(CLUSTER MEET),再做 slot 迁移;

  • 强演练:每季度做一次“节点级数据损坏恢复演练”,记录耗时与回放步骤。


6. 性能与稳定性调优(内核、Redis 配置、内存与淘汰)

6.1 系统内核与文件系统

# 软中断/网络 backlog
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=8192

# TIME_WAIT 回收(按需,谨慎)
sysctl -w net.ipv4.tcp_tw_reuse=1

# 关闭透明大页(THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled

# 关闭 swap 或保证 swapiness 很低
sysctl -w vm.swappiness=1

# 允许内存 overcommit(防止 fork 失败)
sysctl -w vm.overcommit_memory=1

重点vm.overcommit_memory=1,否则 BGSAVE/BGREWRITEAOF 可能因内存不足失败。

6.2 Redis 配置热点

  • 延迟敏感

    • appendfsync everysec + no-appendfsync-on-rewrite yes

    • latency-monitor-threshold 100(打开延迟监控,单位毫秒)

  • 内存与碎片

    • maxmemory <size> + 合理 maxmemory-policy(缓存型推荐 allkeys-lruallkeys-lfu

    • activedefrag yes(生产常开,降低碎片)

  • 数据结构优化

    • 小对象压缩阈值(具体名称随版本有变化,如 listpack 相关阈值);

    • 尽量使用紧凑结构(如 Hash 存多字段,避免大量小 Key)。

6.3 慢查询与可观测性

# 记录慢查询(单位微秒)
CONFIG SET slowlog-log-slower-than 10000   # >10ms
CONFIG SET slowlog-max-len 2048

# 查看慢日志
SLOWLOG GET 10

# 延迟事件
LATENCY DOCTOR
LATENCY LATEST
  • 打通 Exporter → Prometheus → Grafana,关注内存碎片率、AOF 重写耗时、复制延迟、拒绝写入次数等核心指标。


7. 生产避坑清单(高频问题→定位→对策)

  1. BGSAVE/BGREWRITEAOF 失败

    • 现象:日志提示 fork 失败或 OOM;

    • 排查:vm.overcommit_memory、内存碎片、容器内存限制;

    • 对策:开启 activedefrag、扩内存、调整触发频率。

  2. 主从复制频繁全量

    • 现象:网络抖动后总是从头同步;

    • 排查:repl-backlog-size 太小;

    • 对策:增大到能覆盖网络波动期的写入量(按 QPS 与命令平均大小估)。

  3. 写入被拒(OOM 或不安全写)

    • 现象:OOM command not allowed / 触发 min-replicas-to-write 保护;

    • 对策:设置 maxmemory 与合理淘汰策略,或检查从库延迟/下线。

  4. AOF 膨胀/恢复慢

    • 现象:AOF 文件超大,重放耗时长;

    • 对策:定期 BGREWRITEAOF,启用“RDB 作为 AOF 前导”,老版本升级。

  5. Cluster 跨槽操作失败

    • 现象:CROSSSLOT Keys in request don't hash to the same slot

    • 对策:使用 hash tag(如 user:{42}:profileorder:{42}:list)让相关 Key 落同槽。

  6. Sentinel 频繁误判

    • 现象:网络抖动导致频繁 failover;

    • 对策:增大 down-after-milliseconds、合理 quorum、跨 AZ 部署 Sentinel。

  7. 容器/云环境 IP 上报错误

    • 现象:Cluster 节点互相连不上;

    • 对策:显式设置 cluster-announce-ipcluster-announce-portprotected-mode no(仅在安全网络下)。


8. 迁移与升级策略(Standalone→Sentinel、Sentinel→Cluster)

8.1 单机→Sentinel(无停机/短暂停)

  • 新建两个从库(全量同步完成后),部署 3 哨兵;

  • 切流量前压测读从(确认只读链路 OK);

  • 客户端切到 Sentinel 模式;

  • 小流量灰度 → 全量切换。

8.2 单机/Sentinel→Cluster(平滑迁移)

  • 新建 Cluster(3 主 3 从),业务新写双写(或通过数据管道/订阅复制);

  • 扫描旧库 Key,分批迁移到 Cluster(redis-shake/自研脚本/SCAN + MIGRATE);

  • 验证一致性(抽样校验、核心集合完整性校验);

  • 写流量切换到 Cluster → 读流量切换 → 观测一段时间 → 下线旧库。

若业务允许短暂停机,关闭写入口,做全量迁移 + 增量补偿,会简单很多。

8.3 版本升级

  • 同大版本小修:rolling 重启(从→主),使用 REPLICAOF 切换,缩短中断;

  • 跨大版本:先读 release notes 看持久化格式/配置项兼容性,影子集群演练,再灰度。


9. 运维清单与值班自检表

日常巡检(每日/每班次):

  • INFO replication:复制延迟、master_link_status

  • INFO persistence:AOF 重写状态、最近持久化失败次数;

  • INFO memory:使用量、碎片率(>1.5 长期需关注);

  • SLOWLOG LEN / SLOWLOG GET:慢查询堆积;

  • Cluster:cluster infocluster nodes 异常标记。

周度/关键变更前:

  • 触发 RDB 快照与 AOF 重写,校验备份;

  • Sentinel/Cluster 拓扑一致性检查;

  • 压测核心读写路径,记录基线。

季度演练:

  • 单节点宕机 → 恢复;

  • 主从切换演练(Sentinel/Cluster);

  • 备份恢复全链路复盘(计时 + 步骤卡点)。


附:一键化示例(可改名投入使用)

systemd 单实例服务(/etc/systemd/system/redis-6379.service

[Unit]
Description=Redis 6379
After=network.target

[Service]
ExecStart=/usr/bin/redis-server /etc/redis/6379.conf --supervised systemd
ExecStop=/usr/bin/redis-cli -p 6379 shutdown
Type=notify
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

Sentinel systemd(/etc/systemd/system/redis-sentinel.service

[Unit]
Description=Redis Sentinel
After=network.target

[Service]
ExecStart=/usr/bin/redis-sentinel /etc/redis/sentinel.conf --supervised systemd
ExecStop=/usr/bin/redis-cli -p 26379 shutdown
Type=notify
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

结语

Redis 的“正确打开方式”不是单点性能跑多快,而是在“可预期的失败”里依然稳定工作

  • RDB + AOF(everysec) 做好数据兜底;

  • 主从 + Sentinel 扛住单点;

  • 需要水平扩展就上 Cluster,在建模时用 {} 控制跨槽;

  • 结合 操作系统与 Redis 参数 做到“高性能但不冒险”;

  • 备份/恢复/演练 变成固定流程,而不是事故现场临时发挥。

如果你愿意,我可以把上述模板整理成 可下载的配置包(包含 redis.conf/sentinel.conf/systemd/备份脚本/演练脚本),你直接改 IP 和口令就能落地。


网站公告

今日签到

点亮在社区的每一天
去签到