目录
1.Redis 集群搭建有几种模式
2.Redis 主从复制的实现
全量同步
增量同步
3.Redis 的主从同步策略
1. 全量同步(Full Resynchronization)
2. 增量同步(Incremental Replication)
4.Redis一致性hash
基本原理
节点动态管理
虚拟节点
客户端支持
总结
5.Cluster 模式的原理
6.Cluster 的分片机制
7.客户端如何路由
8.Redis 为什么是16384个槽位
消息体大小上的考量
均衡数据分布
行业惯例与经验
9.集群的故障发现与迁移
故障发现(Failure Detection)
主观下线(PFail)
客观下线(Fail)
故障迁移(Failover)
从节点选举
主节点替换
通知客户端与数据迁移
原主节点恢复
1.Redis 集群搭建有几种模式
-
主从复制(Replication)模式:
- 在这种模式下,一个节点被配置为主节点(Master),负责处理所有的写操作以及部分读操作。其他节点作为从节点(Slave),通过复制主节点的数据来保持数据的副本。
- 主节点将写操作产生的数据更改同步到从节点,通常采用异步复制方式,但也支持半同步复制以提高数据安全性。
- 从节点通常是只读的,用于分摊主节点的读取压力,提供数据冗余,以及在主节点故障时提供故障恢复的基础。
-
哨兵(Sentinel)模式:
- Sentinel 是 Redis 官方提供的高可用性解决方案,它由一组独立运行的 Sentinel 进程组成,这些进程监控 Redis 主从集群的健康状态。
- Sentinel 能够自动检测主节点故障,并通过协商选举出新的主节点,同时通知从节点更新其复制关系,实现故障转移(Failover)过程。
- Sentinel 还提供了客户端通知功能,使得应用程序能够及时得知主节点的变化,从而自动调整连接到正确的节点。
-
Cluster(集群)模式:
- Redis Cluster 是官方提供的分布式数据存储方案,通过将数据分片(Sharding)分布在多个节点上,实现水平扩展和数据的高可用性。
- 在 Cluster 模式中,每个节点都可以是主节点,处理一部分数据的读写操作。节点间通过 gossip 协议自动发现和维护彼此间的连接及数据分布状态。
- 数据分片通过哈希槽(Hash Slot)的概念实现,客户端使用一致性哈希算法将键映射到特定的哈希槽,再由 Redis Cluster 负责将请求路由到对应的主节点。
- Cluster 模式还支持数据的自动 rebalancing,当添加或移除节点时,能够重新分配哈希槽以保持数据分布的均衡。
2.Redis 主从复制的实现
主从复制可以根据需要分为全量同步的增量同步两种方式。
-
全量同步
Redis 全量复制一般发生在 slave 的初始阶段,这时 slave 需要将 master 上的数据都复制一份,具体步骤如下:
- slave 连接 master,发送 SYNC 命令;
- master 接到 SYNC 命令后执行 BGSAVE 命令生产 RDB 文件,并使用缓冲区记录此后执行的所有写命令;
- master 执行完 BGSAVE 后,向所有的 slave 发送快照文件,并在发送过程中继续记录执行的写命令;
- slave 收到快照后,丢弃所有的旧数据,载入收到的数据;
- master 快照发送完成后就会开始向 slave 发送缓冲区的写命令;
- slave 完成对快照的载入,并开始接受命令请求,执行来自 master 缓冲区的写命令;
- slave 完成上面的数据初始化后就可以开始接受用户的读请求了。
-
增量同步
增量复制实际上就是在 slave 初始化完成后开始正常工作时 master 发生写操作同步到 slave 的过程。增量复制的过程主要是 master 每执行一个写命令就会向 slave 发送相同的写命令,slave 接受并执行写命令,从而保持主从一致。
3.Redis 的主从同步策略
1. 全量同步(Full Resynchronization)
当从节点初次连接主节点或断线后重新连接且无法进行部分同步时,主节点执行 BGSAVE
命令生成 RDB 快照,并将其发送给从节点。从节点加载 RDB 快照以快速恢复大部分数据。接着,主节点将断线期间积累的写命令(存储在复制积压缓冲区中)发送给从节点,从节点执行这些命令以达到与主节点的完全同步。
2. 增量同步(Incremental Replication)
-
部分同步(Partial Resynchronization):一旦从节点完成全量复制并进入正常工作状态,主从节点之间采用增量复制进行持续同步。主节点在执行完客户端的写操作后,将这些命令通过命令传播机制发送给所有从节点。从节点接收到命令后在本地执行,保持与主节点的实时同步。
-
复制偏移量(Replication Offset):主从节点各自维护一个复制偏移量,表示已复制命令的字节数。每当主节点向从节点发送一个命令时,双方都会更新自己的偏移量。通过比较偏移量,主从节点可以判断复制进度和是否存在数据差距。
-
复制积压缓冲区(Replication Backlog):主节点维护一个固定长度的先进先出(FIFO)队列,存储最近一段时间的写命令。当从节点断线重连时,如果复制积压缓冲区中仍保留了断线期间的命令,从节点可以请求这部分命令进行部分同步,避免进行耗时的全量复制。
-
4.Redis一致性hash
一致性 hash 其实是普通 hash 算法的改良版,其 hash 计算方法没有变化,但是 hash 空间发生了变化,由原来的线性的变成了环。
缓存 key 通过 hash 计算之后得到在 hash 环中的位置,然后顺时针方向找到第一个节点,这个节点就是存放 key 的节点。
基本原理
-
哈希环:将整个哈希值空间组织成一个虚拟的环状结构,通常是一个0到2^32-1的整数环。每个节点(Redis 实例)和数据键(key)都通过相同的哈希函数映射到这个环上。
-
节点映射:每个 Redis 节点通过其标识符(如 IP 地址、端口号或节点ID)计算出一个哈希值,将该值映射到哈希环上。在 Redis Cluster 中,使用的是“哈希槽(hash slot)”的概念,将整个哈希环划分为固定数量(如16384个)的槽位,每个节点负责一部分槽位。
-
数据映射:对于要存储或查询的数据键,同样通过哈希函数计算其哈希值,并定位到哈希环上的一个位置。然后沿着环顺时针方向查找第一个遇到的节点(或槽位),该节点即为该数据键应当存储或查询的目标节点。
节点动态管理
-
节点加入:当新增一个节点时,它会接管一部分哈希槽。这些槽位可能是从其他节点转移过来的,也可能是在创建集群时预先分配给新节点的。由于每个槽位对应的数据范围是确定的,因此只需要将原来映射到这些槽位上的数据迁移到新节点即可,影响范围有限。
-
节点移除或故障:当节点离开集群或发生故障时,其负责的哈希槽需要被其他节点接管。由于数据已经按照槽位均匀分布,其他节点只需接管对应的槽位,就能继续提供服务,受影响的数据同样仅限于那些槽位对应的范围。
虚拟节点
为了进一步提高数据分布的均匀性和应对节点性能差异,Redis Cluster 在实现中通常会使用虚拟节点(Virtual Node)的概念。每个物理节点对应多个虚拟节点,每个虚拟节点有自己的哈希值并映射到哈希环上。这样,即使实际节点数量较少,也能通过虚拟节点在环上形成更为均匀的分布,从而减少数据迁移时的波动。
客户端支持
Redis 客户端在连接集群时,通常会获取集群的元数据(节点列表和槽位分配信息),并内置一致性哈希逻辑。客户端在执行命令时,会根据命令涉及的键计算哈希值,确定相应的哈希槽,并直接连接到负责该槽位的节点进行操作。这样,客户端能够透明地处理节点间的路由,无需应用程序显式处理节点分配。
总结
Redis 中的一致性哈希主要体现在 Redis Cluster 架构中,通过将数据键和节点映射到同一个哈希环上,并结合哈希槽和虚拟节点技术,实现了数据在节点间的均衡分布和高效路由。这种设计使得 Redis 集群在面对节点动态增删时,能够最小化数据迁移,保持服务的高可用性和数据的高一致性。客户端通过内置一致性哈希逻辑,能够自动寻址并直接与正确节点交互,简化了应用程序的开发和维护。
5.Cluster 模式的原理
实现原理就是一致性 Hash。Redis Cluster 中有一个 16384 长度的槽的概念,他们的编号为 0、1、2、3 …… 16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster 中的每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的槽,那么这个 Master 负责为这个 key 提供服务。
至于哪个 Master 节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在 Redis Cluster 中,只有 Master 才拥有槽的所有权,如果是某个 Master 的 slave,这个slave只负责槽的使用,但是没有所有权。
6.Cluster 的分片机制
Redis Cluster 的分片机制基于哈希槽的概念,通过将键映射到特定的槽位,并将槽位分配给不同的节点,实现了数据在集群内的均匀分布和高效路由。
7.客户端如何路由
Redis 集群中的数据是分片存储的,那我们该如何知道某个 key 存在哪个节点上呢?即我们需要一个查询路由,该路由根据给定的 key,返回存储该键值的机器地址。
Redis 的每个节点中都存储着整个集群的状态,集群状态中一个重要的信息就是每个桶的负责节点。在具体的实现中,Redis 用一个大小固定为 CLUSTER_SLOTS 的 clusterNode 数组 slots 来保存每个桶的负责节点。
在集群模式下,Redis 接收任何键相关命令时首先计算键对应的桶编号,再根据桶找出所对应的节点,如果节点是自身,则处理键命令;否则回复 MOVED 重定向错误,通知客户端请求正确的节点,这个过程称为 MOVED 重定向。重定向信息包含了键所对应的桶以及负责该桶的节点地址,根据这些信息客户端就可以向正确的节点发起请求。
8.Redis 为什么是16384个槽位
消息体大小上的考量
至于这个消息体有多大?显然最占空间的就是 myslots 数组:16384÷8÷1024=2kb
。如果槽位达到 65536,则所占空间提升到 65536÷8÷1024=8kb
,极大浪费带宽。
均衡数据分布
在预期的集群规模下(通常不超过几千个节点),16384 个槽位可以确保每个节点负责的槽位数量适中,从而实现数据在节点间的相对均匀分布。即使在节点数量较小(如几十个)的情况下,每个节点也能平均分配到数百至数千个槽位,有利于保持数据分布的均衡。
行业惯例与经验
Redis Cluster 的设计者可能参考了其他分布式系统的实践经验,16384 作为常用的一致性哈希槽位数量,已经在其他系统中得到了验证,具有较好的实践效果和社区共识。
9.集群的故障发现与迁移
故障发现(Failure Detection)
主观下线(PFail)
- 节点间心跳检测:每个 Redis Cluster 节点周期性地向其他节点发送
PING
消息,以检查它们是否在线。如果一个节点在一定时间内(默认超时时间通常是几百毫秒)没有收到另一个节点的响应,它会标记该节点为 主观下线(Subjectively Down, PFail)。这只是单个节点对另一个节点状态的局部判断。
客观下线(Fail)
-
Gossip 协议传播:主观下线状态通过集群内部的 Gossip 协议迅速传播给其他节点。当半数以上的节点(包括自身)都认为某个节点 PFail 时,该节点被宣布为 客观下线(Objectively Down, Fail)。这是整个集群对节点状态达成的共识。
-
故障确认:为了防止短暂网络波动导致的误判,客观下线通常还伴随着额外的确认步骤,比如多次探测失败、等待一段时间等条件。
故障迁移(Failover)
一旦一个主节点被标记为客观下线,集群会触发故障迁移过程以恢复服务的高可用性。故障迁移通常包括以下几个步骤:
从节点选举
-
候选资格:从主节点的从节点(如果有)中选择一个作为新的主节点候选人。通常会选择复制偏移量(replication offset)最高、数据最接近最新的从节点,以减少数据丢失和不一致的风险。
-
选举触发:选举可以由集群中的其他节点(如哨兵节点,如果部署了哨兵模式)或从节点自己(某些情况下)发起。选举过程可能涉及投票或其他协调机制,以确定哪个从节点应晋升为主节点。
主节点替换
-
晋升为主节点:被选中的从节点执行
slaveof no one
命令,断开与原主节点的复制关系,将自己的角色提升为新的主节点。 -
数据接管:由于从节点一直在与原主节点保持同步,因此晋升为主节点后,它已经拥有大部分(如果不是全部)最近的数据。此时,客户端开始向新主节点发送请求。
通知客户端与数据迁移
-
通知客户端:新主节点通过发送
MOVED
响应告知客户端其新的位置。客户端收到后,更新其内部的槽位映射表,将后续对该槽位的请求直接发送到新主节点。 -
数据迁移:对于原主节点在下线前未同步给新主节点的少量新写入数据,可能需要通过异步复制或客户端重试等方式进行恢复。同时,其他从节点也会开始与新主节点建立复制关系,以保持数据一致性。
原主节点恢复
-
角色调整:当原主节点恢复在线时,它会发现自己不再是主节点,而是变成了从节点。它会自动与新主节点建立复制关系,开始同步数据。
-
槽位重分配:在某些情况下,原主节点可能需要重新获得部分或全部槽位的分配权,这通常需要手动干预或集群管理工具的支持。
总的来说,Redis Cluster 的故障发现与迁移机制旨在快速检测并响应节点故障,通过自动或半自动的方式将服务从故障节点转移至健康的节点,确保数据的高可用性和服务的连续性。在整个过程中,集群内部通过 gossip 协议、心跳检测和角色转换等手段维持数据的一致性和服务的稳定性。