# Redis 集群的实现原理是什么?

10 min read
Table of Contents

Redis 集群的实现原理是什么?

Redis 集群的实现原理

【核心定义】

Redis 集群是一种通过分片(Sharding)实现数据分布式存储、通过主从复制保证高可用、通过Gossip协议和集群总线进行节点间通信与协调的分布式解决方案。

【关键要点】

  1. 数据分片(Sharding):采用哈希槽(Hash Slot)机制,将整个数据集划分为16384个固定槽位,每个键通过CRC16算法计算后对16384取模,确定其所属槽位,集群中的每个主节点负责处理其中一部分槽位。
  2. 节点角色与通信:集群由多个节点组成,每个节点承担主节点或从节点角色;节点间通过集群总线(Cluster Bus)和Gossip协议(PING/PONG消息)进行状态通信、故障检测和配置信息传播。
  3. 高可用与故障转移:每个主节点可配置一个或多个从节点;当主节点被标记为疑似下线(PFAIL)并经过集群多数主节点确认为下线(FAIL)后,其从节点会发起选举并升级为新主节点,实现自动故障转移。
  4. 客户端重定向:客户端可连接集群任意节点;若请求的键不属于该节点负责的槽位,节点会返回MOVED错误并告知正确节点地址,客户端需更新本地槽位映射并重定向请求。
  5. 集群配置管理:集群配置信息(节点、槽位分配、状态)通过Gossip协议在节点间最终一致性地同步;新节点加入或节点下线时,通过手动或自动的槽位迁移实现数据重平衡。

【深度推导/细节】

哈希槽(Hash Slot)的设计与优势

  • 槽位数量16384的合理性:
    • 足够多(2^14)以实现灵活、细粒度的数据分布和节点间负载均衡。
    • 不宜过多:集群中每个节点需要维护一个16384位的位图(bitmap)来记录其负责的槽位,在节点间传播时,该位图占用内存为 16384/8 = 2048 字节,若槽位过多(如65536),则位图将占用8KB,在Gossip消息中会显著增加网络开销。
    • 不宜过少:过少的槽位会导致数据分布不够均匀,扩容或缩容时数据迁移的粒度太粗,影响集群灵活性。

故障检测与故障转移的详细流程

Step 1: 故障检测(PFAIL -> FAIL)

  • 每个节点定期(默认每秒10次)向其他随机节点发送PING消息,并期待在cluster-node-timeout(默认15秒)内收到PONG回复。
  • 若某主节点A在超时时间内未收到主节点B的PONG回复,则节点A将节点B标记为疑似下线(PFAIL),并将该信息通过Gossip消息传播给其他节点。
  • 当集群中多数主节点(超过N/2,N为主节点总数)在各自的角度都将节点B标记为PFAIL时,节点B被升级标记为已下线(FAIL)。

Step 2: 故障转移(Failover)

  • 当主节点被标记为FAIL后,其下属的从节点会发起选举。
  • 从节点等待一个随机的延迟(与复制偏移量有关,复制越新的从节点延迟越短),然后向集群所有主节点广播FAILOVER_AUTH_REQUEST消息请求投票。
  • 每个主节点只能投一票,收到多数主节点(超过N/2)投票的从节点赢得选举,升级为新主节点。
  • 新主节点接管原主节点的所有哈希槽,并广播PONG消息通知集群更新配置。

槽位迁移与集群重平衡

  • 使用CLUSTER SETSLOT <slot> IMPORTING <source-node-id> 和 CLUSTER SETSLOT <slot> MIGRATING <target-node-id> 命令在源节点和目标节点上分别设置槽位的“迁出”和“迁入”状态。
  • 迁移过程中,对于属于该槽位的键:
    • 若客户端向源节点请求,且键存在,则正常处理。
    • 若键不存在于源节点(可能已迁移),源节点返回ASK重定向错误,引导客户端向目标节点临时请求一次。
  • 迁移完成后,通过CLUSTER SETSLOT <slot> NODE <target-node-id>命令将槽位所有权正式分配给目标节点,并广播通知全集群。

【关联/对比】

  • Redis Cluster vs. Redis Sentinel(哨兵):

    • 目标不同:哨兵专注于主从模式下的高可用(HA),实现主节点故障时的自动切换;集群则同时解决了数据分片(分布式存储)和高可用问题。
    • 数据模型:哨兵模式下,所有数据存在于单个主节点(和其从节点),存在单点容量和性能瓶颈;集群模式下,数据分散在多个主节点,支持横向扩展。
    • 复杂度:集群的部署、配置和客户端逻辑(需处理重定向)比哨兵模式更复杂。
  • Redis Cluster vs. 客户端分片(Sharded Jedis等):

    • 服务端管理 vs. 客户端管理:客户端分片由应用层代码维护分片逻辑和节点映射,扩容时需要修改客户端配置并手动进行数据迁移;Redis Cluster的分片逻辑和节点管理由服务端集群自身维护,支持动态扩缩容和自动故障转移。
    • 高可用性:客户端分片通常需要结合哨兵或其他HA方案来实现每个分片的高可用;Redis Cluster内置了主从复制和故障转移。

『面试官追问』

  1. 为什么Redis Cluster的最大主节点数量推荐不超过1000个?

    • 主要受限于Gossip协议通信的开销。每个节点需要与其他节点定期交换元数据(PING/PONG),节点数N的增长会使消息总量以O(N²)趋势增长,网络带宽和CPU消耗会急剧增加,影响集群的稳定性和性能。
  2. 集群模式下,如何保证多个键的操作(如MSET)的原子性?

    • Redis Cluster不支持跨多个节点的多键操作。所有命令涉及的键必须位于同一个节点(即属于同一个哈希槽)。可以使用“哈希标签”(Hash Tag)功能,通过对键中{}包围的部分进行哈希计算,强制将多个键映射到同一个槽位,从而在单个节点上执行原子操作。
  3. 集群扩容时,数据迁移是如何进行的?会影响线上服务吗?

    • 数据迁移以槽位为单位进行。迁移过程是渐进式的,在迁移未完成时,对于正在迁移的槽位,客户端请求可能会收到ASK重定向,但集群仍可正常服务其他槽位。因此,影响是局部的和可控的。建议在业务低峰期进行扩容操作。
  4. 如果集群发生网络分区(脑裂),会怎样?

    • Redis Cluster通过要求主节点必须能与多数主节点通信才能提供服务的机制来应对网络分区。如果一个主节点所在的分区无法连接到大多数主节点,它会停止处理写命令(但仍可处理读命令),从而防止出现数据不一致的“脑裂”情况。这被称为“集群可用性”原则。
  5. Redis Cluster支持事务(MULTI/EXEC)吗?

    • 仅支持所有键都在同一个节点上的事务。跨节点的事务无法支持,因为Redis Cluster不提供跨节点的分布式事务协调机制。同样,Lua脚本的执行也要求所有键必须在同一个节点。
My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

# Redis 集群会出现脑裂问题吗?

10 min read

【核心定义】 Redis 集群(Cluster模式)通过内置的分布式协议和多数派(majority)原则来选举主节点和管理故障转移,其设计本身旨在避免脑裂问题,但在极端网络分区(network partition)场景下,仍可能出现类似脑裂的“双主”或数据不一致风险。

Read

# Redis 的 Pipeline 功能是什么?

8 min read

Redis Pipeline 是一种客户端技术,通过将多个命令一次性打包发送给 Redis 服务器,并批量接收所有响应,从而显著减少网络往返时间(RTT)开销,提升批量操作的吞吐量。

Read

Comments