Redis 总结
大型互联网系统如何将 Redis 从单机内存数据库,逐步演进为高性能、高可用、可水平扩展的分布式存储系统。
一、核心主线
演进路径可以概括为:
1 | 单机 Redis |
二、Redis 概述
1. Redis 的定位与特点
Redis 是一种支持网络访问、基于内存、可选持久化的开源键值型 NoSQL 数据库。
主要特点:
- 性能高:数据主要存储在内存中;
- 数据结构丰富:支持 String、List、Hash、Set、Sorted Set 等;
- 支持分布式:提供主从、哨兵和集群模式;
- 操作具有原子性:基于单线程事件驱动模式处理数据操作;
- 应用范围广:可用于缓存、计数器、限流、排行榜和社交关系等场景。
大型互联网系统使用 Redis 时,重点是同时满足:
- 高性能;
- 高可用;
- 可扩展。
三、Redis 高可用与分布式架构
1. 主从模式
1.1 基本结构
一个 Master 与若干 Slave 组成主从关系:
1 | ┌── Slave 1 |
- Master 负责处理数据写入;
- Slave 从 Master 复制数据;
- Slave 保存数据副本,也可以承担部分读取请求。
1.2 Redis 主从复制流程
Slave 首次连接 Master 时,先进行全量复制,再持续进行增量复制。
1 | Slave 发送 PSYNC |
详细步骤:
- Slave 连接 Master,并发送
PSYNC命令; - Master 执行
BGSAVE,生成当前数据的 RDB 快照; - 生成和发送快照期间,Master 使用缓冲区记录新的数据变更;
- Slave 收到 RDB 后先保存到磁盘,再将数据加载到内存;
- Master 把缓冲区内的增量命令发送给 Slave;
- Slave 执行这些命令,使数据逐渐与 Master 保持一致。
1.3 通用复制规律
Redis 与 MySQL 等存储系统的主从复制具有相似思路:
1 | 全量复制 + 增量复制 |
如果一个 Master 向过多 Slave 复制数据,同样会产生复制风暴,增加 Master 的网络和处理压力。
2. 哨兵模式
2.1 主从模式的问题
单纯的主从模式存在一个明显缺点:
Master 宕机后,需要人工选择一个 Slave 并将其切换为新 Master。
人工切换费时费力,还会造成 Redis 在一段时间内无法写入。
2.2 Sentinel 的作用
Redis Sentinel(哨兵)负责:
- 监控 Master 和 Slave 的健康状态;
- 判断 Master 是否宕机;
- 在多个 Slave 中选举新的 Master;
- 通知其他 Slave 改为复制新 Master;
- 向客户端提供新的 Master 地址。
典型结构:
1 | Sentinel 集群 |
2.3 自动故障转移流程
1 | 多个 Sentinel 持续监控 Master |
哨兵模式的本质是:
在主从复制基础上,增加自动监控、选主和故障转移能力。
3. Redis Cluster
3.1 为什么需要集群模式
主从模式和哨兵模式都只有一个 Master 处理主要读写请求,因此存在两个瓶颈:
- 单个 Master 的内存有限,无法保存海量数据;
- 单个 Master 的处理能力有限,无法承受海量请求。
解决方式是数据分片:
1 | 全量数据 |
多个 Master 分别保存部分数据,并共同提供服务。
3.2 Redis Cluster 基本结构
Redis Cluster 从 Redis 3.0 开始提供分布式存储能力。
- 集群至少需要 3 个 Master;
- 每个 Master 管理一个数据分片;
- 每个 Master 最好至少配置一个 Slave;
- 同一分片通过主从复制保证高可用;
- 集群节点之间可以相互通信。
3.3 哈希槽与数据路由
Redis Cluster 将整个数据库划分为 16384 个哈希槽。
每个 Master 负责其中一部分槽位。例如:
1 | Master 1:0~5461 |
数据所属槽位的计算方式:
1 | slot = CRC16(Key) mod 16384 |
客户端访问流程
- 客户端连接集群中的任意节点;
- 获取并缓存“槽位—Master”的映射关系;
- 访问数据时,根据 Key 计算槽位;
- 根据槽位找到对应 Master;
- 将请求发送给正确的数据分片。
哈希槽的价值是:
- 将数据分片抽象为槽位;
- 数据与具体机器解耦;
- 扩容、缩容时可以迁移槽位,而不是重新设计整体路由规则。
3.4 Gossip 协议
Redis Cluster 使用 Gossip 协议在节点之间传播集群元信息。
需要传播的信息包括:
- 新节点加入;
- 节点地址和状态;
- 槽位归属;
- 槽位迁移;
- Master 宕机;
- Slave 提升为新 Master。
Gossip 的传播方式
Gossip 类似“流言传播”:
- 每个节点周期性选择部分节点通信;
- 收到信息的节点再将信息传播给其他节点;
- 经过多轮传播,最终所有节点的信息趋于一致。
它不是一次广播给所有节点,而是通过多轮局部通信扩散。
主要消息类型
| 消息 | 作用 |
|---|---|
meet |
邀请新节点加入集群 |
ping |
发送自身状态、槽位信息并探测其他节点 |
pong |
响应 ping 或 meet,返回自身信息 |
fail |
通知集群某节点已经宕机 |
Gossip 的优点是去中心化,没有单独的元信息管理中心;缺点是信息需要多轮传播,因此只能保证最终一致性。
3.5 新节点加入
新节点加入集群时,可以向集群内任意节点发送 CLUSTER MEET 命令。
简化流程:
1 | 客户端通知节点 A:节点 B 要加入 |
因此,新节点只需要先认识集群中的一个节点,之后便可通过 Gossip 逐渐被整个集群发现。
3.6 节点故障检测与转移
Redis Cluster 区分两种下线状态。
主观下线
节点 A 向节点 B 发送 ping,但在指定时间内没有收到 pong,于是 A 主观认为 B 已下线。
单个节点的判断可能受到局部网络异常影响,因此不能直接触发故障转移。
客观下线
如果集群中超过半数的节点都认为 B 主观下线,那么 B 被认定为客观下线。
1 | 单节点判断失败 → 主观下线 |
故障转移
如果被客观判定下线的是 Master:
- 集群广播
fail消息; - 该 Master 的 Slave 停止复制;
- 一个 Slave 接管原 Master 的槽位;
- Slave 提升为新 Master;
- 新 Master 广播
pong,通知整个集群更新状态。
3.7 Redis Cluster 的优势
- 去中心化:各节点地位对等;
- 数据分片清晰:通过槽位管理数据;
- 扩展性较强:可以增加节点并迁移槽位;
- 高可用:支持自动故障发现与主从切换;
- 人工干预少:集群可以自动恢复;
- 官方支持:对 Redis 命令的兼容和支持较全面。
3.8 Redis Cluster 的局限:Gossip 风暴
Gossip 依赖节点间扩散式通信。
当集群只有数百个节点时,一般可以正常运行;但如果扩展到成千上万个节点,节点之间的通信量会急剧增加,形成 Gossip 风暴。
可能带来的问题:
- 占用大量网络带宽;
- 集群内部通信成本过高;
- 元信息传播链路过大;
- 集群规模继续扩大时受到限制。
对于需要数千甚至上万个 Redis 节点的亿级用户系统,更推荐放弃完全去中心化的元信息传播方式,转向中心化 Proxy 架构。
4. 中心化集群
中心化架构的核心思想是:
使用中间代理统一维护数据路由和集群元信息,客户端不直接参与 Redis 分片寻址。
基本结构:
1 | Redis 客户端 |
优点:
- 避免大规模节点间的 Gossip 通信;
- 客户端无须了解槽位和节点拓扑;
- 可以代理到成千上万台 Redis 服务器;
- 更适合超大规模 Redis 集群。
4.1 Twemproxy
Twemproxy 是 Twitter 开源的 Redis 中间代理。
访问流程:
1 | 客户端 → Twemproxy → 根据路由规则选择 Redis 节点 |
优势
- 客户端像连接普通 Redis 一样连接 Twemproxy,改造成本低;
- Twemproxy 与 Redis 保持长连接,减少 Redis 节点的连接数;
- 数据路由由代理完成,客户端和 Redis 节点无须参与。
不足
- 缺少友好的管理后台;
- 运维和监控不够方便;
- 不支持 Redis 集群平滑扩缩容;
- 增加节点时的数据迁移成本较高。
Twemproxy 提供了中心化代理的基本思路,但不是完善的超大规模集群管理方案。
4.2 Codis 架构
Codis 是借鉴 Twemproxy 思路发展出的中心化 Redis 集群方案。
Codis 默认把数据划分为 1024 个槽位:
1 | slot = CRC32(Key) mod N |
其中 N 默认是 1024。
Codis 核心组件
| 组件 | 作用 |
|---|---|
| Codis Server | 二次开发的 Redis 服务器,负责数据读写并支持数据迁移 |
| Codis Proxy | 接收客户端请求并路由到正确的 Codis Server |
| ZooKeeper | 保存槽位、分片、节点和 Proxy 等集群元信息 |
| Codis Dashboard | 执行扩缩容、槽位迁移和 Proxy 管理 |
| Codis Fe | 为 Dashboard 提供 Web 管理页面 |
Redis Server Group
Codis 将一个数据分片称为 Redis Server Group:
1 | Redis Server Group |
每个 Group 通过主从复制保证分片高可用,新版本可为每个 Group 配置 Sentinel 完成自动主从切换。
4.3 Codis 数据访问流程
1 | 客户端从 ZooKeeper 获取 Codis Proxy 地址 |
其中:
- Master 可以处理读写请求;
- Slave 可以承担读取请求;
- Proxy 负责屏蔽底层分片与节点变化。
4.4 Codis 平滑扩容与槽位迁移
Codis 以槽位为单位迁移数据。
假设要把节点 A 的槽位 S 迁移到新节点 B:
- A 将槽位 S 的关联数据复制到 B;
- 迁移过程中 A 继续提供服务;
- 如果请求的数据不属于 S,A 正常处理;
- 如果请求的数据属于正在迁移的 S,为确保数据已经位于 B,会先将该数据强制迁移到 B;
- 数据迁移完成后,请求被转发到 B 处理。
这种方式保证:
- 扩容期间集群仍可提供服务;
- 数据可以逐步迁移;
- 避免一次性停机搬迁全部数据。
四、Redis 架构对比
| 架构 | 解决的问题 | 优点 | 局限 |
|---|---|---|---|
| 主从模式 | 数据副本 | 简单,具备基础容灾能力 | Master 故障需人工切换,单主容量有限 |
| 哨兵模式 | 自动故障转移 | 自动监控、选主和切换 | 仍然只有一个 Master,不能解决分片和容量问题 |
| Redis Cluster | 分布式存储与自动恢复 | 多主分片、去中心化、官方支持 | 超大规模下可能产生 Gossip 风暴 |
| 中心化 Proxy | 超大规模分片管理 | 客户端简单,可代理大量 Redis 节点 | Proxy 和元信息系统的设计、运维更复杂 |
五、核心架构思想
- Redis 的价值不只是快,还包括丰富数据结构、原子操作和分布式能力。
- 主从复制采用全量复制加增量复制,是高可用的基础。
- 哨兵模式解决的是单个 Master 故障后的自动选主和切换问题。
- 哨兵不能解决单 Master 的容量和吞吐瓶颈,数据分片必须依靠集群模式。
- Redis Cluster 通过 16384 个哈希槽实现数据分片和路由。
- Gossip 让 Redis Cluster 去中心化,但只能保证元信息最终一致。
- 主观下线不能直接代表节点故障,需要多数节点确认后才形成客观下线。
- Redis Cluster 适合一般规模的分布式 Redis,但节点过多时可能出现 Gossip 风暴。
- 中心化 Proxy 架构牺牲部分去中心化特性,换取更强的超大规模扩展能力。
- Codis 通过 Proxy、ZooKeeper、槽位和 Server Group 实现集中路由、集群管理和平滑扩缩容。
- Redis 架构选型需要综合考虑数据量、请求量、节点规模、故障恢复和运维复杂度。
六、一句话总结
Redis 从主从复制、Sentinel 自动切主,演进到 Redis Cluster 多主分片,再到 Codis 等中心化 Proxy 架构,逐步解决数据副本、故障恢复、容量扩展和超大规模节点管理问题;中小规模集群可优先使用官方 Redis Cluster,而节点达到数千甚至上万时,中心化代理架构更有利于避免 Gossip 风暴并实现可控的平滑扩缩容。