Redis 学习笔记(四):持久化与高可用

写在前面

本文是 Redis 学习笔记系列的最后一篇,介绍 Redis 的持久化机制、主从复制、哨兵、Cluster 集群和运维排查。前置知识:分布式锁(第三篇)。


一、持久化

1.1 为什么需要持久化

1
2
3
4
5
6
Redis 是内存数据库,重启后数据全部丢失。
持久化将内存数据保存到磁盘,重启后可以恢复。

两种持久化方式:
  RDB(Redis Database)   — 定时快照
  AOF(Append Only File) — 追加写日志

1.2 RDB 快照

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
原理:在某个时间点,把内存中的所有数据生成一份快照文件(dump.rdb)

触发方式:
  1. 自动触发(配置规则)
  2. 手动触发(SAVE / BGSAVE)
  3. 关闭时触发(shutdown)

自动触发配置:
  save 900 1        — 900秒内有1次修改就触发
  save 300 10       — 300秒内有10次修改
  save 60 10000     — 60秒内有10000次修改

BGSAVE 工作方式:
  1. 主进程 fork 子进程
  2. 子进程将内存数据写入临时 RDB 文件
  3. 写完后替换旧的 RDB 文件
  4. 主进程继续处理请求(不影响服务)

优点:
  - 文件紧凑,恢复速度快
  - fork 子进程不影响主进程
  - 适合备份和容灾

缺点:
  - 不是实时的,两次快照之间的数据可能丢失
  - fork 子进程时如果数据量大,可能短暂影响性能

1.3 AOF 日志

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
原理:将每个写命令追加到 AOF 文件(appendonly.aof)

工作流程:
  1. 客户端发送写命令
  2. Redis 执行命令
  3. 将命令追加到 AOF 缓冲区
  4. 根据策略将缓冲区写入文件

刷盘策略(appendfsync):
  always     — 每个写命令都刷盘(最安全,最慢)
  everysec   — 每秒刷盘一次(推荐,最多丢1秒数据)
  no         — 由操作系统决定(最快,可能丢较多数据)

优点:
  - 数据更安全(最多丢1秒)
  - AOF 文件可读(可以手动修改恢复数据)

缺点:
  - 文件比 RDB 大
  - 恢复速度比 RDB 慢

1.4 AOF 重写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
问题:AOF 文件越来越大(SET a 1, SET a 2, SET a 3 → 只需要 SET a 3)

AOF 重写:压缩 AOF 文件,只保留最终状态的数据

触发方式:
  auto-aof-rewrite-min-size 64mb      — AOF 文件超过 64MB 触发
  auto-aof-rewrite-percentage 100     — 文件大小比上次重写后增长 100%

手动触发:
  BGREWRITEAOF

1.5 RDB + AOF 混合持久化(Redis 4.0+)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
配置:aof-use-rdb-preamble yes(默认开启)

工作方式:
  - AOF 重写时,前半部分用 RDB 格式写入(快速加载)
  - 后半部分用 AOF 格式写入增量命令
  - 结合了两者的优点

推荐配置:
  开启 AOF(appendonly yes)
  开启混合持久化(aof-use-rdoc-preamble yes)
  刷盘策略 everysec

1.6 持久化选择

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
纯缓存(丢了无所谓):
  关闭持久化,性能最好
  save ""
  appendonly no

缓存 + 允许少量丢失:
  只用 RDB
  适合:Session、验证码

数据不能丢:
  AOF + everysec
  适合:业务数据、计数器

生产环境推荐:
  RDB + AOF 混合持久化
  RDB 用于快速恢复和备份
  AOF 保证数据安全

二、主从复制

2.1 作用

1
2
3
1. 数据备份   — 从节点是主节点的完整副本
2. 读写分离   — 写请求到主节点,读请求到从节点
3. 高可用基础  — 主节点故障时从节点可以提升为主

2.2 配置

1
2
3
4
5
6
7
8
# 从节点配置(redis.conf 或命令)
REPLICAOF master-ip 6379

# 或运行时设置
REPLICAOF 192.168.1.100 6379

# 查看主从关系
INFO replication

2.3 复制过程

1
2
3
4
5
6
7
8
1. 从节点连接主节点
2. 主节点执行 BGSAVE 生成 RDB 快照
3. 主节点将 RDB 发送给从节点
4. 从节点加载 RDB(全量同步)
5. 之后主节点将新的写命令持续发送给从节点(增量同步)

全量同步:初次连接或断开较久时触发
增量同步:正常情况下的持续同步

2.4 注意事项

1
2
3
4
5
6
7
8
1. 主从复制是异步的(主节点写入后立即返回,不等从节点确认)
   → 主节点宕机时可能丢失少量数据

2. 从节点默认只读(read-only)
   → 不应该往从节点写数据

3. 一个主节点可以有多个从节点
   → 从节点也可以作为其他从节点的主节点(链式复制)

三、哨兵(Sentinel)

3.1 问题:主节点宕机了怎么办

1
2
3
4
5
6
主从复制中:
  主节点宕机 → 需要人工把从节点提升为主节点
  → 需要通知所有客户端新的主节点地址
  → 整个过程需要人工干预

哨兵:自动完成这个过程

3.2 哨兵功能

1
2
3
4
1. 监控    — 持续检查主节点和从节点是否正常
2. 通知    — 节点故障时通知管理员或应用
3. 自动故障转移 — 主节点故障时自动将从节点提升为主节点
4. 配置提供者 — 客户端从哨兵获取当前主节点地址

3.3 哨兵部署

1
2
3
4
5
6
7
8
9
至少 3 个哨兵节点(保证选举的多数派)

部署结构:
  Redis Master        — 192.168.1.100:6379
  Redis Slave 1       — 192.168.1.101:6379
  Redis Slave 2       — 192.168.1.102:6379
  Sentinel 1          — 192.168.1.100:26379
  Sentinel 2          — 192.168.1.101:26379
  Sentinel 3          — 192.168.1.102:26379
1
2
3
4
5
6
# sentinel.conf
port 26379
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
1
2
3
4
monitor          — 监控的主节点名称、IP、端口、法定人数
down-after       — 多久无响应判定为主观下线
failover-timeout  — 故障转移超时
parallel-syncs   — 故障转移后多少个从节点同时同步新主节点

3.4 故障转移流程

1
2
3
4
5
6
7
1. 哨兵每秒向主节点发送 PING
2. 超过 down-after 时间无响应 → 主观下线
3. 多数哨兵(≥ 2 个)认为主节点下线 → 客观下线
4. 哨兵选举一个从节点提升为新主节点
5. 其他从节点改为复制新主节点
6. 哨兵更新配置,通知客户端新主节点地址
7. 旧主节点恢复后变为新主节点的从节点

3.5 .NET 连接哨兵

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// StackExchange.Redis 支持哨兵
var config = new ConfigurationOptions
{
    ServiceName = "mymaster",    // 哨兵监控的 master 名称
    AbortOnConnectFail = false
};
config.EndPoints.Add("192.168.1.100:26379");
config.EndPoints.Add("192.168.1.101:26379");
config.EndPoints.Add("192.168.1.102:26379");

var connection = ConnectionMultiplexer.Connect(config);
// 自动从哨兵获取当前主节点地址
// 主节点切换后自动重连新主节点

四、Cluster 集群

4.1 为什么需要 Cluster

1
2
3
4
5
6
7
8
9
主从 + 哨兵的问题:
  - 主节点只有一个,写入压力集中在主节点
  - 主节点内存有限,单机无法存储更多数据
  - 水平扩展困难

Cluster 解决:
  - 数据分片(Sharding)— 数据分散到多个主节点
  - 水平扩展 — 加节点即可扩容
  - 高可用 — 每个主节点有从节点,自动故障转移

4.2 Cluster 架构

1
2
3
4
5
6
7
8
9
最小集群:6 个节点(3 主 3 从)

  Master-1 (slot 0-5460)    ←→ Slave-1
  Master-2 (slot 5461-10922) ←→ Slave-2
  Master-3 (slot 10923-16383) ←→ Slave-3

  共 16384 个 Hash Slot
  每个主节点负责一部分 Slot
  key 的 slot = CRC16(key) % 16384

4.3 创建 Cluster

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 每个节点的 redis.conf
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

# 启动 6 个节点(7001-7006)
redis-server redis.conf

# 创建集群
redis-cli --cluster create \
  127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \
  127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 \
  --cluster-replicas 1

4.4 Cluster 操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看集群信息
redis-cli -c -p 7001 cluster info
redis-cli -c -p 7001 cluster nodes

# 查看某个 key 在哪个 slot
redis-cli -c -p 7001 cluster keyslot "user:1"

# 加减节点
redis-cli --cluster add-node new_host:port existing_host:port
redis-cli --cluster reshard host:port

4.5 Cluster 限制

1
2
3
4
5
6
7
8
1. 不支持跨 slot 的多 key 操作(MSET、SUNION 等涉及多个 key 的命令)
   → 可以用 Hash Tag 强制同一 slot:{user}:1, {user}:2

2. 不支持 SELECT 切换数据库(只用 db0)

3. 批量操作需要确保 key 在同一个 slot

4. 集群至少 3 主 3 从

五、运维常用操作

5.1 信息查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 服务器信息
INFO server

# 内存使用
INFO memory
# 关注:used_memory_human(已用内存)
#       maxmemory(最大内存限制)
#       mem_fragmentation_ratio(内存碎片率,>1.5 需要关注)

# 客户端连接
INFO clients
# 关注:connected_clients(当前连接数)

# 命令统计
INFO stats
# 关注:total_commands_processed(总命令数)
#       instantaneous_ops_per_sec(每秒操作数)

# 持久化状态
INFO persistence
# 关注:rdb_last_save_time(上次 RDB 保存时间)
#       aof_current_size(AOF 当前大小)

# 复制状态
INFO replication

5.2 性能分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 慢查询日志
CONFIG SET slowlog-log-slower-than 10000    # 超过 10ms 记录
CONFIG SET slowlog-max-len 128              # 最多记录 128 条
SLOWLOG GET 10                              # 查看最近 10 条慢查询
SLOWLOG LEN                                # 慢查询数量

# 客户端列表
CLIENT LIST                                # 所有连接

# 监控命令(调试用,不要在生产长时间开)
MONITOR                                    # 实时显示所有命令

5.3 内存优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看内存使用
MEMORY USAGE key                    # 单个 key 的内存占用
MEMORY DOCTOR                       # 内存诊断建议

# 大 key 排查
redis-cli --bigkeys                 # 扫描大 key
redis-cli --memkeys                 # 按内存排序的 key

# 清理过期 key
SCAN 0 MATCH session:* COUNT 1000  # 安全扫描

5.4 常用运维命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看配置
CONFIG GET maxmemory
CONFIG GET maxmemory-policy

# 在线修改配置
CONFIG SET maxmemory 2gb
CONFIG SET maxmemory-policy allkeys-lru

# 查看连接数
CLIENT LIST | wc -l

# 断开客户端
CLIENT KILL ADDR:PORT

# 数据库大小
DBSIZE

# 清空当前数据库
FLUSHDB ASYNC                      # 异步清空(不阻塞)

# 查看所有数据库的 key 数量
INFO keyspace

六、常见问题排查

6.1 内存满了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
现象:OOM,写入返回错误

排查:
  1. INFO memory → 看 used_memory 和 maxmemory
  2. redis-cli --bigkeys → 找大 key
  3. 检查是否有过期策略

解决:
  - 设置 maxmemory-policy(推荐 allkeys-lru)
  - 清理无用 key
  - 扩容(增加内存或用 Cluster)
  - 检查是否有大 value(拆分为多个小 key)

6.2 响应变慢

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
排查:
  1. SLOWLOG GET 10 → 慢查询
  2. INFO memory → 看碎片率(mem_fragmentation_ratio)
  3. INFO clients → 连接数是否过多
  4. INFO persistence → 是否在频繁 BGSAVE

常见原因:
  - 大 key 操作(DEL 一个很大的 key 会阻塞)
  - 持久化阻塞(fork 耗时)
  - 内存碎片太多(重启可以解决)
  - 连接数过多
  - 使用了 KEYS * 等危险命令

6.3 主从延迟

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
排查:
  INFO replication
  → master_repl_offset 和 slave_repl_offset 差距大

原因:
  - 网络延迟
  - 从节点性能不足
  - 主节点写入量太大
  - 大 key 同步耗时

解决:
  - 检查网络
  - 提升从节点配置
  - 避免写入大 value

七、系列总结

7.1 知识体系回顾

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
第一篇:基础与数据类型
  - 核心概念、5种数据类型、通用命令、.NET 客户端

第二篇:缓存实战
  - 缓存模式、过期策略、淘汰策略、穿透/击穿/雪崩

第三篇:分布式锁
  - 锁原理、Lua 解锁、看门狗、可重入、RedLock、.NET 封装

第四篇:持久化与高可用
  - RDB、AOF、主从复制、哨兵、Cluster、运维排查

7.2 核心要点

1
2
3
4
5
6
7
8
1. Redis 单线程 + IO 多路复用 = 高性能
2. 5 种数据类型各有适用场景,选对了事半功倍
3. 缓存用 Cache Aside 模式,更新时删缓存不是更新缓存
4. 缓存三大问题必须能答:穿透(布隆过滤器)、击穿(互斥锁)、雪崩(随机过期)
5. 分布式锁三要素:SET NX EX、唯一值、Lua 解锁
6. 生产环境开启 AOF + everysec,推荐混合持久化
7. 高可用至少 3 节点:主从 + 哨兵,或 Cluster
8. 避免 KEYS *、大 value、热点 key 过期时间相同