深入 Redis 内核:RDB/AOF 持久化机制、主从复制流程、Sentinel 故障转移原理、Cluster 分片路由、大Key/热Key治理、慢查询排查与 Benchmark 压测实战。
四、进阶:理解 Redis 原理和架构
1. Redis 为什么快
核心原因:
- 基于内存访问。
- 单线程执行命令,减少锁竞争。
- I/O 多路复用。
- 数据结构设计高效。
- 命令模型简单。
- 网络协议轻量(RESP)。
说明:Redis 的"单线程"主要指命令执行主线程。现代 Redis 在网络 I/O、异步删除、持久化等方面已引入多线程能力。
2. 持久化:RDB 与 AOF
RDB
RDB 是快照持久化,会在特定条件下生成某一时刻的数据快照。
conf
save 900 1
save 300 10
save 60 10000
优点:文件紧凑、适合备份、恢复速度快。
缺点:可能丢失最近一段时间的数据、生成快照时有额外开销。
AOF
AOF 会记录写命令。
conf
appendonly yes
appendfsync everysec
刷盘策略:
| 策略 | 含义 | 特点 |
|---|---|---|
always |
每次写都刷盘 | 最安全,性能最低 |
everysec |
每秒刷盘 | 常用,最多丢约 1 秒数据 |
no |
交给操作系统 | 性能好,可靠性较弱 |
持久化深水区:fork 和 Copy-On-Write
Redis 生成 RDB 或 AOF rewrite 时会 fork 子进程:
text
父进程继续处理请求
子进程负责写持久化文件
fork 后采用 Copy-On-Write:父进程修改内存页时触发页复制
风险:
- 数据量越大,fork 耗时可能越高。
- 写入越频繁,COW 额外内存越大。
- 磁盘 I/O 抖动会影响 Redis。
关注指标:
bash
INFO persistence
# 重点关注:latest_fork_usec / rdb_last_bgsave_status / aof_delayed_fsync
AOF Rewrite
AOF 文件会随写命令变大,rewrite 后压缩:
bash
# 原始 AOF
INCR count # × 3次
# rewrite 后
SET count 3
Redis 7.0 Multi-part AOF
text
appendonlydir/
appendonly.aof.1.base.rdb ← 基础 RDB 快照
appendonly.aof.1.incr.aof ← 增量 AOF
appendonly.aof.manifest ← 清单文件
优势:rewrite 更高效,恢复时先加载 base RDB,再回放增量 AOF。
3. 内存淘汰策略
| 策略 | 含义 |
|---|---|
noeviction |
不淘汰,新写入报错 |
allkeys-lru |
从所有 key 中淘汰最近最少使用的 key |
volatile-lru |
从设置了过期时间的 key 中淘汰 LRU |
allkeys-lfu |
从所有 key 中淘汰最少使用的 key |
volatile-ttl |
从设置了过期时间的 key 中淘汰快过期的 |
缓存场景常用:
conf
maxmemory 4gb
maxmemory-policy allkeys-lru
LRU vs LFU:LRU 关注最近是否使用,LFU 关注使用频率。
4. 过期删除策略
- 惰性删除:访问 key 时发现已过期,再删除。
- 定期删除:周期性抽样检查并删除过期 key。
- 内存淘汰:内存不足时根据淘汰策略删除部分 key。
因此,一个 key 到期后不一定立刻从内存中消失。
5. 主从复制
text
Master
-> Replica 1
-> Replica 2
复制流程:
- 从节点执行
REPLICAOF 192.168.1.10 6379 - 首次全量复制:Master fork 生成 RDB → 发送给 Replica → 加载 RDB → 发送期间增量写命令
- 后续增量复制:Master 持续把写命令发送给 Replica
- 断线重连:复制积压缓冲区中有缺失数据 → 部分重同步,否则全量同步
关键概念:replication id / offset / backlog(复制积压缓冲区)
主从复制通常是异步的,可能存在短暂数据延迟。
6. 主从复制一致性与故障窗口
text
客户端写入 Master 成功
Master 还没同步给 Replica
Master 宕机
Replica 被提升为新 Master
刚才写入的数据丢失
降低风险:
bash
SET order:1001 paid
WAIT 1 100 # 等待至少 1 个副本确认,最多 100ms
conf
min-replicas-to-write 1
min-replicas-max-lag 10
业务层兜底:关键状态落 MySQL + MQ 补偿 + 写操作幂等。
7. Sentinel 哨兵
Sentinel 用于 Redis 高可用,核心功能:监控 / 判断下线 / 选举新 Master / 通知客户端。
故障转移流程:
- 单个 Sentinel 标记主观下线(SDOWN)
- 多个 Sentinel 达成一致,标记客观下线(ODOWN)
- 选举 Leader Sentinel
- 从 Replica 中选择最合适节点提升为 Master(依据:优先级 / 复制偏移量 / 运行状态)
- 旧 Master 恢复后变成 Replica
- 通知客户端新的 Master 地址
8. Redis Cluster
Redis Cluster 通过哈希槽分片,固定 16384 个 slot:
text
CRC16(key) % 16384
| 节点 | 槽范围 |
|---|---|
| Node A | 0 - 5460 |
| Node B | 5461 - 10922 |
| Node C | 10923 - 16383 |
路由重定向:
MOVED:槽已归属其他节点(永久重定向)ASK:槽正在迁移中(临时重定向)
Hash Tag:
bash
user:{1001}:profile
user:{1001}:orders
{} 内相同内容的 key 会落到同一个 slot,支持多 key 操作。
注意:hash tag 不要滥用,否则数据集中到少数 slot 造成倾斜。
Cluster 运维:
bash
redis-cli --cluster check host:port
redis-cli --cluster add-node newHost:newPort existingHost:existingPort
redis-cli --cluster reshard existingHost:existingPort
9. 大 Key 问题
示例:
text
String 存 10MB JSON
Hash 有 100 万个 field
List 有几百万个元素
危害:阻塞 Redis / 网络传输慢 / 删除慢 / 主从复制压力大 / Cluster 槽分布不均
排查:
bash
redis-cli --bigkeys
MEMORY USAGE key
解决:
- 拆分 key。
- 分页读取(HSCAN / SSCAN / ZSCAN)。
- 删除时用
UNLINK(异步,不阻塞主线程)。 - 避免
HGETALL、LRANGE 0 -1。
10. 热 Key 问题
热 Key 是被极高频访问的 key,危害:单节点 CPU/网络压力过高。
发现:
bash
redis-cli --hotkeys # 需 LFU 策略
解决:
- 本地缓存:Caffeine 缓存热点数据,减少 Redis 访问。
- 热 key 拆分 :
product:1001:stock:0/1/2/3,读时随机访问。 - 多副本读:把读请求分散到多个 Replica。
11. 底层数据结构理解
| 上层类型 | 常见底层实现 | 说明 |
|---|---|---|
| String | SDS | 动态字符串,支持二进制安全 |
| Hash | listpack / hashtable | 小对象紧凑存储,大对象哈希表 |
| List | quicklist | 双向链表 + 压缩列表思想 |
| Set | intset / hashtable | 整数小集合可用 intset |
| ZSet | listpack / skiplist + dict | 支持范围查询和快速定位 |
常见命令复杂度:
| 命令 | 复杂度 | 风险 |
|---|---|---|
GET |
O(1) | value 过大时网络慢 |
HGETALL |
O(N) | 大 Hash 会阻塞 |
SMEMBERS |
O(N) | 大 Set 风险高 |
KEYS |
O(N) | 生产禁用 |
12. 事件循环和网络模型
text
客户端连接
-> I/O 多路复用监听事件
-> 读取请求
-> 解析命令
-> 执行命令
-> 写回响应
关键点:
- 命令执行主路径通常是单线程。
- 单个慢命令会阻塞后续命令。
- Redis 6 之后支持多线程 I/O,但命令执行仍需关注阻塞问题。
Redis 真的是单线程吗?
text
核心命令执行线程主要是单线程。
RDB/AOF rewrite 会 fork 子进程。
异步删除由后台线程处理。
Redis 6+ 支持多线程 I/O 用于网络读写和协议解析。
七、性能排查与优化
1. 常用排查命令
bash
INFO # 全量信息
INFO memory # 内存详情
INFO stats # 统计信息
INFO commandstats # 各命令统计
INFO persistence # 持久化状态
INFO clients # 客户端信息
SLOWLOG GET 20 # 慢查询日志
LATENCY DOCTOR # 延迟诊断
LATENCY HISTORY event # 延迟事件历史
MEMORY STATS # 内存分配详情
MEMORY USAGE key # 单 key 内存占用
CLIENT LIST # 当前所有客户端连接
redis-cli --bigkeys # 扫描大 key
redis-cli --hotkeys # 扫描热 key(需 LFU)
2. 慢查询分析
bash
SLOWLOG GET 10
配置:
conf
slowlog-log-slower-than 10000 # 10ms,单位微秒
slowlog-max-len 128
延迟事件:
bash
CONFIG SET latency-monitor-threshold 5
LATENCY LATEST
LATENCY DOCTOR
3. 内存分析与碎片整理
核心指标:
| 指标 | 含义 |
|---|---|
used_memory |
Redis 实际使用内存 |
used_memory_rss |
操作系统分配的物理内存 |
mem_fragmentation_ratio |
碎片率 = rss / used |
碎片率判断:
text
1.0 - 1.5 正常
> 1.5 碎片偏高
> 2.0 需要处理
< 1.0 可能使用了 swap,严重影响性能
在线碎片整理(Redis 4.0+):
conf
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
手动触发:
bash
MEMORY PURGE
4. 网络延迟诊断
bash
redis-cli --latency # 持续测量延迟
redis-cli --latency-dist # 延迟分布直方图
redis-cli --intrinsic-latency 10 # 系统基础延迟(排除 Redis 本身)
5. Benchmark 压测
bash
# 只测 SET 和 GET
redis-benchmark -t set,get -c 100 -n 500000 -q
# 测试大 value
redis-benchmark -t set -d 1024 -c 50 -n 100000
# Pipeline 模式
redis-benchmark -t set,get -c 100 -n 500000 -P 16 -q
6. 常见优化清单
| 方向 | 优化措施 |
|---|---|
| 命令优化 | 避免 KEYS *、HGETALL 大 Hash |
| 大 Key | 拆分、分页扫描、UNLINK 删除 |
| 热 Key | 本地缓存、key 拆分、多副本读 |
| 网络优化 | Pipeline、MGET/MSET 批量操作 |
| 连接管理 | 连接池、合理超时、控制连接数 |
| 内存 | 设置 maxmemory、监控碎片率 |
生产禁止命令:
text
KEYS * → 用 SCAN 替代
FLUSHALL → 禁用或 rename
DEL 大 key → 用 UNLINK 替代
HGETALL 大 Hash → 用 HSCAN 替代
常见面试题:原理与架构篇
Redis 为什么快?
text
基于内存 + 单线程命令执行(无锁竞争)+ I/O 多路复用 + 高效数据结构 + 轻量协议(RESP)
RDB 和 AOF 有什么区别?
| 维度 | RDB | AOF |
|---|---|---|
| 持久化内容 | 某一时刻的数据快照 | 写命令日志 |
| 恢复速度 | 较快 | 可能较慢 |
| 数据安全性 | 可能丢失最近一段时间数据 | 通常更好(everysec 丢约 1 秒) |
Sentinel 如何实现故障转移?
text
监控 -> 主观下线 -> 客观下线 -> 选举 Leader Sentinel
-> 选择最优 Replica 提升 -> 通知客户端
Redis Cluster 如何分片?
text
CRC16(key) % 16384 → 固定 16384 个 slot → 每个节点负责一部分 slot
什么是大 Key?有什么危害?
text
大 Key = value 很大或集合元素数量非常多的 key
危害:阻塞主线程 / 网络传输慢 / 删除耗时长 / 主从复制压力大
解决:UNLINK 删除 / HSCAN 分页 / 拆分 key
Redis 主从切换会丢数据吗?
text
可能会。异步复制模式下,Master 未同步到 Replica 的数据在 Master 宕机后会丢失。
WAIT 命令和 min-replicas 配置可降低概率,但不等同强一致。
本文是《Redis 知识体系》系列第二篇,聚焦原理与架构。
第一篇:《Redis 数据结构与工程实战》→ 9大数据结构 × 11个高频场景
第三篇:《Redis 专家实战》→ 生产架构/容量规划/安全/37道面试题