Redis 原理深度解析:持久化 × 主从复制 × Sentinel × Cluster × 性能排查全攻略

深入 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

复制流程:

  1. 从节点执行 REPLICAOF 192.168.1.10 6379
  2. 首次全量复制:Master fork 生成 RDB → 发送给 Replica → 加载 RDB → 发送期间增量写命令
  3. 后续增量复制:Master 持续把写命令发送给 Replica
  4. 断线重连:复制积压缓冲区中有缺失数据 → 部分重同步,否则全量同步

关键概念: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 / 通知客户端。

故障转移流程:

  1. 单个 Sentinel 标记主观下线(SDOWN)
  2. 多个 Sentinel 达成一致,标记客观下线(ODOWN)
  3. 选举 Leader Sentinel
  4. 从 Replica 中选择最合适节点提升为 Master(依据:优先级 / 复制偏移量 / 运行状态)
  5. 旧 Master 恢复后变成 Replica
  6. 通知客户端新的 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(异步,不阻塞主线程)。
  • 避免 HGETALLLRANGE 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道面试题

相关推荐
AI-小柒2 小时前
磅上线!DataEyes 聚合平台正式接入 GPT-Image-2,开启多模态 AI 生成全新纪元
大数据·开发语言·数据库·人工智能·gpt·php
m0_588758482 小时前
解决Navicat正向工程从模型建表报错怎么办_外键关联与语法解析
jvm·数据库·python
2501_914245932 小时前
如何修复宝塔面板由于inode耗尽导致无法创建文件_清理海量小文件缓存与会话目录
jvm·数据库·python
Gauss松鼠会2 小时前
GaussDB for DWS 数据融合:Oracle数据迁移到GaussDB(DWS)
数据库·oracle·数据库开发·gaussdb
2401_837163892 小时前
WordPress后台插件隐藏策略:仅对指定管理员显示特定插件
jvm·数据库·python
MY_TEUCK2 小时前
【Redis 高级实战】分布式缓存、 多级缓存与最佳实践一篇打通
redis·分布式·缓存
qq_189807032 小时前
C++如何验证YAML语法格式是否正确_try-catch解析校验用法【实战】
jvm·数据库·python
财经汇报2 小时前
当“多级流转“占据六成版图——供应链金融的结构性迁移与产融结合新范式
大数据·数据库
zhangchaoxies2 小时前
c++如何读取YAML格式配置文件_yaml-cpp库快速入门【详解】
jvm·数据库·python