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