redis的分布式设计

Redis 的分布式设计主要通过三种模式实现,每种模式解决不同的问题:


一、三种分布式模式对比

模式 解决的问题 数据关系 适用场景
主从复制 读写分离、数据备份 全量复制 读多写少、数据备份
哨兵模式 高可用、自动故障转移 全量复制 需要自动容灾
Cluster 集群 水平扩展、海量数据 分片存储 数据量大、需要扩展

二、主从复制(Replication)

核心机制

scss 复制代码
┌─────────┐         全量/增量复制          ┌─────────┐
│  Master │  ───────────────────────────►  │  Slave  │
│  (写)   │                              │  (读)   │
└─────────┘                              └─────────┘

复制流程

text 复制代码
1. Slave 发送 SYNC/PSYNC 命令
2. Master 执行 BGSAVE,生成 RDB 文件
3. Master 将 RDB 发送给 Slave
4. Slave 加载 RDB
5. 后续写命令实时同步(增量复制)

关键配置

bash 复制代码
# slave 配置
replicaof 192.168.1.10 6379
masterauth <password>

# 只读(默认)
replica-read-only yes

问题

  • 无法自动故障转移:Master 挂了需要手动切换
  • 写压力集中在 Master
  • 复制延迟:Slave 数据可能落后

三、哨兵模式(Sentinel)

在主从基础上增加自动监控和故障转移。

架构

arduino 复制代码
        ┌─────────┐
        │ Client  │
        └────┬────┘
             │
    ┌────────┼────────┐
    ▼        ▼        ▼
┌───────┐ ┌───────┐ ┌───────┐
│Sentinel│ │Sentinel│ │Sentinel│  (至少3个,投票决策)
│  1    │ │  2    │ │  3    │
└────┬───┘ └────┬───┘ └────┬───┘
     │          │          │
     └──────────┼──────────┘
                ▼
        ┌─────────────┐
        │   Master    │
        └──────┬──────┘
               │
        ┌──────┴──────┐
        ▼             ▼
    ┌───────┐     ┌───────┐
    │ Slave1│     │ Slave2│
    └───────┘     └───────┘

哨兵的核心功能

功能 说明
监控 定期检查 Master/Slave 是否存活
通知 故障时通知管理员或其他应用
自动故障转移 Master 宕机时,选举 Slave 为新 Master
配置提供者 客户端向 Sentinel 询问当前 Master 地址

故障转移流程

text 复制代码
1. 主观下线(SDOWN):某个 Sentinel 发现 Master 无响应
2. 客观下线(ODOWN):多个 Sentinel 投票确认 Master 故障
3. 选举 Leader Sentinel:Raft 算法投票
4. 选择最优 Slave(优先级高、复制偏移量大、RunID小)
5. 提升为 Master,其他 Slave 重新配置
6. 通知客户端更新 Master 地址

客户端连接方式

python 复制代码
# Python 示例:Sentinel 自动发现 Master
from redis.sentinel import Sentinel

sentinel = Sentinel([
    ('sentinel1', 26379),
    ('sentinel2', 26379),
    ('sentinel3', 26379)
])

# 自动获取当前 Master
master = sentinel.master_for('mymaster', password='xxx')
slave = sentinel.slave_for('mymaster', password='xxx')

master.set('key', 'value')
value = slave.get('key')

缺点

  • 只有一个 Master 写,无法水平扩展写性能
  • 数据量受限于单节点内存

四、Cluster 集群(最核心)

Redis 真正的分布式方案,通过数据分片实现水平扩展。

架构

css 复制代码
┌─────────────────────────────────────────────┐
│              Redis Cluster                   │
│                                              │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐     │
│   │ Node 1  │  │ Node 2  │  │ Node 3  │     │
│   │ [0-5460]│  │[5461-10922]│[10923-16383] │
│   │ Master A│  │ Master B│  │ Master C│     │
│   └───┬─────┘  └────┬────┘  └────┬────┘     │
│       │             │            │          │
│   ┌───┴───┐    ┌───┴───┐   ┌───┴───┐      │
│   │Slave A1│    │Slave B1│   │Slave C1│     │
│   └────────┘    └────────┘   └────────┘      │
│                                              │
│   16384 个哈希槽(Slot)均匀分配到各 Master    │
└─────────────────────────────────────────────┘

核心概念:哈希槽(Hash Slot)

text 复制代码
Slot = CRC16(key) % 16384

key "user:1000" → CRC16 = 12345 → 12345 % 16384 = 12345 → 属于 Node 3

为什么用 16384 个槽?

  • CRC16 输出范围 0~65535
  • 16384 = 2^14,平衡了元数据大小和分片粒度
  • 集群节点配置中传播的是槽位映射,不是具体 key

节点通信:Gossip 协议

text 复制代码
每个节点每秒随机向几个其他节点发送 PING
携带:自身状态 + 已知其他节点的状态

通过"谣言传播"方式,最终整个集群状态一致

客户端路由

text 复制代码
┌─────────┐
│ Client  │
└────┬────┘
     │  SET key value
     ▼
┌─────────┐  计算 key 的 Slot
│ Node 1  │  发现 Slot 不在本地
└────┬────┘
     │ 返回 MOVED 错误,告知正确节点
     ▼
┌─────────┐
│ Client  │  重定向到正确节点
└────┬────┘
     ▼
┌─────────┐
│ Node 3  │  执行命令
└─────────┘

Smart Client(如 redis-py-cluster)会缓存槽位映射,减少重定向。

数据迁移(扩容/缩容)

text 复制代码
1. 新节点加入集群
2. 分配部分 Slot 给新节点(如从 Node1 迁 1000 个 Slot)
3. 迁移过程中:
   - 源节点:迁出的 Slot 标记为 IMPORTING
   - 目标节点:标记为 MIGRATING
   - 迁移中的 key:先查源节点,没有则查目标节点
4. 迁移完成后更新槽位映射

Cluster 配置示例

bash 复制代码
# redis.conf
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
cluster-require-full-coverage no  # 部分槽不可用时不拒绝所有请求
bash 复制代码
# 创建集群(6 节点,3 主 3 从)
redis-cli --cluster create \
  192.168.1.11:6379 192.168.1.12:6379 192.168.1.13:6379 \
  192.168.1.14:6379 192.168.1.15:6379 192.168.1.16:6379 \
  --cluster-replicas 1

五、三种模式对比总结

维度 主从复制 哨兵模式 Cluster 集群
数据容量 单机内存 单机内存 多机总和
写性能 单机 单机 水平扩展
读性能 扩展 扩展 扩展
高可用 手动切换 自动切换 自动切换
数据分片
复杂度

六、生产环境建议

场景 推荐方案
数据 < 10GB,读多写少 主从 + 哨兵
数据 > 10GB 或需要扩展写 Cluster 集群
需要跨机房容灾 Cluster + 主从交叉部署
超大规模(TB 级) 业务分片 + 多 Cluster

七、常见问题

1. Cluster 的 key 限制

bash 复制代码
# 默认不支持跨 Slot 的多 key 操作
MGET key1 key2  # 如果 key1 和 key2 在不同 Slot,报错

# 解决方案:Hash Tag
MGET {user:1000}:name {user:1000}:age  
# {} 内内容用于计算 Slot,确保同一用户数据在同一节点

2. 脑裂问题

text 复制代码
网络分区时,原 Master 和 Sentinel 隔离
Sentinel 选举新 Master → 出现两个 Master
解决方案:min-slaves-to-write 配置,确保有足够 Slave 才接受写

3. 数据倾斜

text 复制代码
Big Key 或 Hash Tag 使用不当导致某些 Slot 数据量过大
解决方案:监控 Slot 大小,避免 Big Key,合理设计 key

相关推荐
uzong8 分钟前
面试官:如何做好架构设计
后端·架构
哆来A梦没有口袋11 分钟前
干货精讲 | 初级CSS面试高频考题
前端·css·面试
plainGeekDev20 分钟前
Android运行时面试题:ART和JVM的区别都搞不清,别写精通了
jvm·面试·kotlin
Cosolar24 分钟前
QwenPaw Agent 实现原理深度剖析
后端·面试·架构
Sincerelyplz1 小时前
【AI会议纪要实践】mapReduce、RAG 与结构化输出
java·后端·agent
贺国亚1 小时前
Agent 框架 · LangChain / LangGraph / AutoGen / CrewAI
面试
zavoryn1 小时前
后端接入 AI Agent:Tool Calling 网关、幂等与审计日志实战
后端·架构
青山师1 小时前
动态规划算法深度解析:从状态转移方程到工业级优化
数据结构·算法·面试·动态规划·代理模式·java面试
zhangjw341 小时前
第15篇:Java多线程零基础入门,进程线程、线程创建方式、线程生命周期、线程安全彻底吃透
java·开发语言·面试
Raink老师1 小时前
【AI面试临阵磨枪-086】什么是 AI Agent Skill?与传统 Function Calling、Tool 的区别?
人工智能·面试·职场和发展