Redis集群中的Gossip协议如何实现节点状态同步
Redis集群采用去中心化的架构,没有专门的代理或中心节点来维护状态。集群要保证所有节点对拓扑结构、槽位分配和节点健康状态达成一致,全靠节点之间高频的互相通信。这种“八卦式”的通信机制被称为Gossip协议。
要掌握集群状态的同步过程,我们将其拆解为三个核心阶段:建立连接、信息交换、故障判定。
第一阶段:握手与连接
在集群中,节点之间需要先建立联系,才能开始交换信息。
-
发送
CLUSTER MEET命令。
当你需要将一个新节点加入集群时,执行cluster meet <ip> <port>命令。比如在节点A上运行cluster meet 192.168.1.2 6379。 -
握手。
节点A收到命令后,会向节点B发送一条MEET消息。节点B收到后,会将节点A加入到自己的邻居列表中,并回复一条PONG消息。 -
扩散 关系。
节点B一旦接受了节点A,它会在后续与其他节点(如节点C、D)通信时,将节点A的信息“顺带”告诉它们。这样,全网节点最终都会知道节点A的存在。
第二阶段:持续的消息交换
连接建立后,节点之间需要频繁交换状态数据。Redis集群使用 PING 和 PONG 两种消息类型来封装状态,两者的结构完全一致,PONG 通常是对 PING 的响应。
-
发送
PING消息。
每个节点每秒会随机挑选 5 个最久未通信的节点,发送PING消息。这被称为“活跃度检测”。 -
封装 消息体。
PING消息不仅仅是一句“你好”,它携带了发送者当前已知的一部分其他节点的状态信息。消息体主要包含以下字段:
| 字段名称 | 说明 |
|---|---|
sender_id |
发送消息节点的ID(40位十六进制字符串) |
offset |
发送者所知的槽位配置偏移量(用于标识配置版本) |
slaveof |
如果是从节点,记录其主节点ID |
ip & port |
节点通信地址 |
link_state |
与该节点的连接状态(连接中/已断开) |
ping_sent |
最后一次发送PING的时间 |
pong_received |
最后一次接收PONG的时间 |
-
更新 本地状态。
当节点B收到节点A的PING消息后,会解析 消息体中的节点信息。它会将这些信息与本地内存中的集群状态进行比对。- 如果消息中包含B未知的节点,B将其加入列表。
- 如果消息中某个节点的状态更新(例如槽位变了),B会更新 本地记录。
- 随后,节点B会构造 一条
PONG消息,附带自己的状态,回复 给节点A。
-
传播 变更。
当节点A收到PONG或来自其他节点的PING时,如果发现对方的配置版本(configEpoch)比自己新,就会立即触发一次更新,并尝试将自己的槽位信息同步给其他节点。
为了更直观地展示信息如何在节点间流动,请看以下流程:
在上述过程中,节点A通过一次 PING,不仅确认了节点B的存活,还间接将自己掌握的节点C的信息同步给了B,B再同步给C。信息就像病毒一样在全网扩散。
第三阶段:故障判定与状态同步
Gossip协议最关键的作用是快速发现并确认节点故障。Redis将故障分为两个层级:主观下线和客观下线。
-
检测 主观下线(PFail)。
节点A会持续记录与邻居节点B的通信时间。如果节点A在cluster-node-timeout(默认15秒)时间内没有收到节点B的PONG回复,节点A会将节点B的状态标记为PFail(Probable Fail,疑似下线)。此时这只是节点A的“个人观点”。 -
传播 疑似故障。
当节点A再次向其他节点(如C、D)发送PING时,它会在消息体中附带 “节点B疑似下线”的信息。其他节点收到后,会记录 节点B在节点A眼中是PFail状态。 -
统计 投票。
当节点C也发现节点B超时,也会将B标记为PFail。C在与其他节点通信时,会交换各自的PFail列表。
节点C如果发现集群中“持有槽位的主节点”里,有半数以上 都认为节点B是PFail,节点C就会将节点B的状态升级为Fail(客观下线)。 -
广播 下线消息。
一旦确定某个节点Fail,节点C会广播 一条FAIL消息给全网。所有收到消息的节点会立即将节点B标记为Fail,并停止向其转发请求。如果节点B是从节点且它的主节点Fail了,它将触发 故障转移逻辑。
这个过程通过Gossip协议实现了最终一致性,虽然信息传播有一定延迟,但能保证在数秒内(通常为 timeout * 2)全网达成共识。

暂无评论,快来抢沙发吧!