写在前面
本文是 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 过期时间相同
Licensed under CC BY-NC-SA 4.0