Redis集群Gossip协议
什么是 Gossip 协议?
Gossip 协议,中文常译为流言协议或流行病协议,是一种去中心化的、基于感染式传播的通信协议。它的灵感来源于人类社会中的流言传播或流行病扩散。
其核心思想是:
- 随机选择:集群中的每个节点都会随机地选择几个其他节点。
- 交换信息:节点之间周期性地(例如,每秒一次)交换自己所知道的信息(即元数据)。
- 最终一致性:经过一段时间后,集群中的所有节点都会获得完全一致的元数据信息,从而达到最终一致性。
这个过程就像办公室里一个人知道了一个八卦,他随机找几个人说了这个八卦,这些人又随机找其他人说,很快整个办公室的人都知道了。
为什么 Redis 集群需要 Gossip 协议?
Redis 集群是一个去中心化的架构。它没有像 ZooKeeper 或 etcd 那样的中心协调节点来统一管理所有节点的状态信息。那么,集群中的每个节点是如何知道其他节点的存在、状态(是在线还是下线)、以及负责的槽位(slot)信息呢?
这就是 Gossip 协议的用武之地。Redis 集群使用 Gossip 协议来实现:
- 节点发现:新节点加入集群后,如何让其他节点知道它。
- 元数据传播:将每个节点掌握的集群状态信息(如槽位分配情况)传播给所有其他节点。
- 故障检测:检测节点是否下线,并最终在整个集群内达成共识,从而触发故障转移(Failover)。
Gossip 协议在 Redis 集群中的具体工作方式
通信端口
每个 Redis 集群节点都需要开启两个 TCP 端口:
- 客户端通信端口(默认 6379):用于服务客户端请求。
- 集群总线端口(默认 16379):用于节点间通过 Gossip 协议进行通信。
集群总线端口 = 客户端端口 + 10000。
节点间所有的 Gossip 通信都通过集群总线进行。
消息类型
Gossip 协议承载了多种消息类型,其中最主要的是 PING 和 PONG 消息。它们本质上是相同的,PONG 是对 PING 的回复,有时也用于主动推送信息。
PING消息:是信息交换的载体。一个PING消息不仅用于探测节点是否存活,更重要的是它携带了丰富的元数据。PONG消息:用于回复PING消息,内容同样包含元数据。也可以用于在收到MEET消息后(新节点加入)立即确认。
消息内容
一个 PING/PONG 消息包主要包含两个部分:
Header(头部):包含发送节点自身的一些信息,如:
- 节点 ID
- 当前节点的纪元(配置纪元,用于故障转移和槽位信息版本控制)
- 节点角色(主节点/从节点)
- 节点 IP 和端口
- 节点状态(如是否被标记为下线)
- 负责的槽位位图(如果它是主节点)
Gossip 节(Gossip Section):这是协议的精髓。它包含了发送节点所知道的关于其他节点的一些信息(通常是随机挑选的几个节点)。对于每个被提到的节点,信息包括:
- 该节点的 ID
- 该节点的 IP 和端口
- 该节点的状态标志(如:
PFAIL、FAIL) - …
工作流程
周期性随机选择:
每个节点默认每秒会执行 10 次以下操作,但只会选择 1 个节点进行通信(cluster-node-time可配置)。它从自己已知的节点列表中(包括正常、疑似下线的节点,但不包括已确认下线的节点),随机选择 1 个节点发送PING消息。- 为什么是随机? 随机性避免了所有节点同时向同一个节点发起通信,导致网络拥塞。它是一种负载均衡。
- 为什么选择 1 个? 这是一个权衡。太频繁会增加网络负担,太慢则会导致信息收敛(最终一致)得太慢。
信息交换与更新:
- 节点 A 向随机选择的节点 B 发送一个
PING消息。这个消息里包含了 A 自己的头部信息,以及 A 所知道的关于其他随机几个节点的 Gossip 信息。 - 节点 B 收到
PING后,会回复一个PONG消息,其中同样包含 B 自己的头部信息和它知道的 Gossip 信息。 - 节点 A 收到
PONG后,会解析其中的信息,并与自己本地存储的信息进行对比和更新。例如:- 如果发现了一个自己不知道的新节点,它会把这个新节点加入到自己的节点列表中。
- 如果发现某个节点的状态(如槽位分配)比自己知道的更新(通过配置纪元判断),它会更新本地的信息。
- 如果收到关于其他节点故障的信息,也会记录下来。
- 节点 A 向随机选择的节点 B 发送一个
故障检测(Fail Detection):
这是 Gossip 协议一个非常重要的应用。- PFAIL(可能下线):如果节点 A 在
cluster-node-timeout时间内无法与节点 B 成功通信,它会在本地将节点 B 标记为PFAIL(Possible Failure,可能下线)。 - 传播 PFAIL 状态:之后,当节点 A 向其他节点发送
PING消息时,它携带的 Gossip 信息里就会包含节点B是PFAIL的状态。 - FAIL(确认下线):集群中的每个节点都会收到来自其他节点关于节点 B 的 Gossip 信息。如果大多数主节点都认为节点 B 是
PFAIL状态,那么其中一个主节点就会将节点 B 的状态升级为FAIL,并将这个FAIL状态通过 Gossip 协议广播出去。 - 触发故障转移:一旦某个主节点被确认为
FAIL状态,并且它有一个从节点,那么就会触发故障转移流程,由该从节点晋升为新的主节点。
- PFAIL(可能下线):如果节点 A 在
优点与缺点
优点:
- 去中心化与高可用:无需依赖任何中心节点,任何节点的下线都不会影响元数据的传播(只要集群大部分主节点存活)。
- 可扩展性:新节点的加入或信息的传播压力会均匀地分散到所有节点上,集群规模越大,每个节点需要通信的邻居数并不需要线性增长,因此扩展性良好。
- 容错性:由于随机选择和对等通信,它对网络抖动和节点故障具有很高的抵抗力。信息可以通过多条路径传播,最终总能到达所有节点。
- 最终一致性:虽然信息传播有延迟,但能保证所有节点最终会拥有一致的集群视图。
缺点:
- 消息延迟:信息到达所有节点需要一定的时间(通常以秒计),是最终一致而非强一致。在信息收敛期间,不同节点可能看到不同的集群状态。
- 消息冗余:由于是随机传播,同一条消息可能会被多次发送到同一个节点,造成一定的网络带宽浪费。
总结
Redis 集群的 Gossip 协议就像集群的神经系统,它通过每个节点随机地交换信息,让所有节点最终都能感知到整个集群的完整状态(节点列表、槽位映射、故障状态)。这种设计完美契合了 Redis 集群去中心化的架构思想,以其简单、可靠、高容错的特性,实现了集群的自我管理和自我修复。


