RedisCluster 集群实现原理

文章目录

  • 1. RedisCluster 的架构
      • RedisCluster 设计成 16384 个 Slot 的原因
  • 2. 集群内部节点数据一致性实现
      • 2.1 RedisCluster 节点间通信方式
      • 2.2 Gossip 协议
  • 3. 高可用性原理

1. RedisCluster 的架构

要支持集群首先要克服数据分片问题,也就是一致性哈希问题,常见方案有以下几种:

  1. 客户端分片
    使用类似于哈希取模的做法,当客户端对服务端的数量完全掌握和控制时,可以简单使用
  2. 中间层分片
    在客户端和服务器端之间增加中间层,充当管理者和调度者,客户端的请求打向中间层,由中间层实现请求的转发和响应的回收,中间层最重要的作用是对多台服务器的动态管理
  3. 服务端分片
    实现去中心化的管理模式,客户端直接向服务器中任意结点请求,如果被请求的节点没有所需数据,则向客户端回复MOVED,并告诉客户端所需数据的存储位置,这个过程实际上是客户端和服务端共同配合,进行请求重定向来完成的

Redis 3.0 版本之后,Redis 支持 RedisCluster集群作为分布式解决方案。该集群采用多主多从结构,实现了服务端的分片技术,使用多个 Master节点保存数据和整个集群状态,通过增减 Master节点就能达到增大/缩小 Redis 数据容量的目的,从而很好地支持横向扩容。 官方传送门

RedisCluster 集群实现原理_第1张图片

Redis Cluster 集群的结构特点如下:

  1. 集群内支持多个 Master 节点,每个 Master 节点也可以有多个 Slave 节点。所有节点彼此连接(基于PING-PONG机制),内部使用二进制协议通信
  2. 集群中超过半数的 Master 节点检测到某个节点失效时才判定该节点下线
  3. 客户端与集群中任意一个可用 Master 节点直连
  4. 集群内置数据自动分片机制,将集群内部所有的 key 映射到16384个Slot中,每个 Master 节点都会记录哪些 Slot 指派给了自己,哪些指派给了其他节点。这种机制让集群内节点的增加和移除很简单,增加一个 Master 节点就将其他节点的 Slot 移动部分过去,减少一个Master 就将它的 Slot 移动到其他节点即可,移动 Slot 的成本是非常低的
  5. 客户端连接集群中任意 Master 节点即可发送命令,不过在命令执行之前会根据 key 使用CRC16(key)%16384定位到一个 Slot,如果该 Slot 不在当前 Master 节点的负责范围内,则当前节点会将负责该 Slot 的节点地址返回给客户端,客户端收到后自动将原请求重新发往目标节点

RedisCluster 设计成 16384 个 Slot 的原因

可参考 作者的回答,主要有以下几个方面的考虑

  1. 心跳包的大小
    因为 redis 节点需要定时发送一定数量的 ping 消息作为心跳包,而在包的消息头中最占空间的是 myslots[CLUSTER_SLOTS/8]如果 Slot 数量太大,如 65536,则这块的大小是: 65536÷8=8kb,ping 消息的消息头太大了,浪费带宽
  2. 集群节点数量有限
    集群节点越多心跳包的消息体内携带的数据越多,如果节点数量超过一定限制,也会导致网络拥堵,从而使集群内节点达到最终一致性的时间相对变长,因此不建议集群内节点数量超过1000个,在这样的情况下,16384个 Slot 足够使用
  3. 传输效率
    Redis 主节点的配置信息中,其负责的 Slot 通过一个 bitmap 位图来保存。在网络传输过程中,bitmap 会被压缩,但是如果 bitmap 的填充率 slots/N(N表示节点数)很高的话,bitmap 的压缩率就很低。在节点数量有限的情况下,Slot 数量尽量小可以提高 bitmap 的压缩率,从而减少网络流量

2. 集群内部节点数据一致性实现

2.1 RedisCluster 节点间通信方式

RedisCluster 集群内每个 Master 节点会使用两个端口,一个是提供服务的端口,比如 6379,另外一个是该端口号加10000的端口号,比如16379,这个端口号是专门用来进行节点间通信的,也就是集群总线

RedisCluster 不是将集群元数据(节点信息,故障信息,节点的增加和移除,slot信息等)集中存储在单个节点上,而是在所有节点间采取Gossip协议不断进行通信的方式保持集群中每个节点上的元数据的一致性。具体来说,就是每个节点每隔一段时间都会往另外几个节点发送 PING 消息,其他节点接收到 PING 之后返回 PONG 消息,互相交换元数据

  • Gossip 优点
    元数据的更新比较分散,不是集中在一个节点,更新请求会陆续打到所有节点上去更新,有一定的延时,降低了压力
  • Gossip 缺点
    元数据更新有延时,可能导致集群的一些变化在各个节点上存在一段时间的同步滞后

2.2 Gossip 协议

Gossip协议又被称为流言协议,是 Redis 集群各个节点彼此同步状态的手段。其工作方式很简单,以加入新节点(Meet) 为例,最初只有发出邀请的节点和被邀请节点知道这件事,但是通过 Ping 消息一层一层扩散,其他节点也被通知到了,这样Gossip协议实现了最终一致性

Gossip 算法又被称为反熵(Anti-Entropy),就是在混乱中寻求一致,这也说明了Gossip 的特点:在一个有界网络中,每个节点可能知道所有其他节点,也可能仅知道几个邻居节点,只要这些节点可以通过网络连通,并且每个节点都随机地与其他节点通信,那么经过一段时间的交流,最终所有节点的状态都会达成一致

RedisCluster 的集群消息主要有以下几种类型:

  1. Meet
    通过cluster meet ip port命令,已有集群的某个节点会向新加入的节点发送邀请,使其加入现有集群
  2. Ping
    每个节点都会频繁地给其他节点发送 Ping,每次会选择5个最久没有通信的其他节点,如果发现某个节点通信延时达到了cluster_node_timeout/2,那么立即发送 Ping,避免数据长时间不一致。cluster_node_timeout可以用来调节 Ping 的频率,如果该值设置得比较大,那么会减少 Ping 次数。Ping 消息中包含了节点自己的状态及其维护的集群元数据,还会带上至少两个已知的其他节点信息一起发送出去,进行数据交换
  3. Pong
    节点收到 Ping 消息后会回复 Pong 消息,消息中同样带有自己节点的信息及已知的其他节点信息
  4. Fail
    某节点判定一个节点 Fail 后,会立即向集群所有节点广播该节点挂掉的消息,其他节点收到消息后标记指定的节点已下线
  5. Publish
    当节点接收到一个 PUBLISH 命令时,节点会执行这个命令,并向集群广播一条 Publish 消息,所有接收到消息的节点都会执行相同的 PUBLISH 命令
  6. FAILOVER_AUTH_REQUEST
    当 Master 节点进入 Fail 状态,Slave 向集群中的所有的节点发送消息,但是只有 Master 才能给 Slave 投票failover 其的 Master
  7. FAILOVER_AUTH_ACK
    当 Master 接收到 FAILOVER_AUTH_REQUEST 消息,如果 Slave 节点满足投票条件且 Master 自己在当前纪元未投票就返回 FAILOVER_AUTH_ACK 消息给 Slave 投票

3. 高可用性原理

RedisCluster 高可用的原理和哨兵机制极其相似,主要原理如下:

  1. Master 节点宕机判定
    如果一个节点 ping 了另外一个节点,这个节点在cluster-node-timeout超时时间内一直没有返回 pong,那么就被认为 PFAIL ,主观宕机
    如果一个节点认为某个节点 PFAIL 了,那么会在 ping 消息中将这个信息广播给其他节点,如果多个节点(N/2 + 1)都认为目标节点 PFAIL了,那么这个节点就会变成 FAIL,客观宕机
  2. Slave 节点切换为 Master 节点
    对宕机的 Master 节点,需要从其所有的从节点中选择一个切换成 Master 节点。这个过程中大概分为了 3 个步骤:
    1. 过滤可用的 Slave 节点
      具体做法就是检查每个 Slave 节点与 Master 节点断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那这个Slave 节点就没有资格切换成 Master
    2. 确定候选节点优先级
      过滤出可用的 Slave 节点后,所有从节点需要进行排序,排序因子为 复制偏移量 offset ,每个从节点根据优先级设置一个选举时间,选举时间靠前的 Slave 节点优先进行选举
    3. 选举出 Master 节点
      Slave 节点将自己记录的集群 currentEpoch 加1,并广播 Failover Request信息。其他节点收到该信息,只有 Master 节点会判断请求者的合法性,发送FAILOVER_AUTH_ACK 对 Slave 节点进行选举投票,每一个epoch只发送一次ack。Slave 节点收集 FAILOVER_AUTH_ACK,如果大部分Master节点(N/2 + 1)都投票给了这个 Slave 节点,那么选举通过,这个 Slave 节点将执行主备切换,切换为新的 Master 节点,并广播通知集群其它节点

你可能感兴趣的:(分布式,Redis)