bigywater.tech
Redis · 74

Redis Cluster 节点握手

新节点是怎么加入集群的?你只对一个节点说了一句 CLUSTER MEET,其它节点怎么知道它?这篇把三个空节点从「互不认识」到「集群 ok」的全过程,按毫秒采样打印出来:握手的几个状态、gossip 的传播延迟、cluster_state 什么时候变 ok,以及握手一个不存在的节点会发生什么。

约 111 ms
CLUSTER MEET 后两个节点互相认识(master/connected)
1800 ms
第三个节点只 MEET 中间人,靠 gossip 三方互相认识
0.0 s
MEET 一个不存在地址时 handshake 记录的存活时间

起点:三个互不认识的节点

实测 · 本机执行输出
  7380: 已知节点 1 个,cluster_state = fail,current_epoch = 0
  7381: 已知节点 1 个,cluster_state = fail,current_epoch = 0
  7382: 已知节点 1 个,cluster_state = fail,current_epoch = 0

启动后各自只认识自己:known_nodes = 1,没有槽位所以 cluster_state = fail,current_epoch = 0。

CLUSTER MEET:直接握手

每 10 ms 采样两端的 CLUSTER NODES,只打印变化
实测 · 本机执行输出
> CLUSTER MEET 127.0.0.1 7381
"OK"
  +     0 ms  7380 眼中的其它节点: {7381: 'handshake/disconnected'}
  +     1 ms  7381 眼中的其它节点: {}
  +    44 ms  7380 眼中的其它节点: {7381: 'handshake/connected'}
  +    45 ms  7381 眼中的其它节点: {7380: 'handshake/disconnected'}
  +    61 ms  7380 眼中的其它节点: {7381: 'master/connected'}
  +   111 ms  7381 眼中的其它节点: {7380: 'master/connected'}

0 ms 时 7380 的节点表里出现 handshake/disconnected——还不知道对方的 ID,用一个临时的随机 ID 占位;连上之后是 handshake/connected(44 ms);对方回应后拿到真实 ID 与角色,变成 master/connected(61 ms)。另一端(7381)比 7380 晚一点才认出 7380(111 ms)。整个过程约 111 ms。

gossip:不需要两两 MEET

实测 · 本机执行输出
> CLUSTER MEET 127.0.0.1 7382
"OK"
  +     1 ms  7380 认识的节点端口: [7381]
  +     2 ms  7381 认识的节点端口: [7380, 7382]
  +     2 ms  7382 认识的节点端口: []
  +    18 ms  7382 认识的节点端口: [7381]
  +   911 ms  7382 认识的节点端口: [7380, 7381]
  +  1799 ms  7380 认识的节点端口: [7381, 7382]
三个节点互相认识(每个都知道另外两个)用了 1800 ms

只让 7381 去 MEET 7382:7381 立刻认识了两个邻居,7382 认识了 7381(+18 ms);而 7380 与 7382 互相不知道对方。它们通过 gossip(节点之间的心跳消息里附带的「我认识的其它节点」)传播:7382 在 +911 ms 学到了 7380,7380 在 +1799 ms 才学到 7382——比直接握手慢一个数量级(约每秒一轮心跳)。所以新节点只要 MEET 集群里任何一个节点,不需要逐个 MEET;但完全互相认识需要 1–2 秒。这个延迟是这台实验机上的一次测量,不同规模的集群会不同。

握手之后与分配槽位

实测 · 本机执行输出
  7380: known_nodes = 3,cluster_state = fail(还没分槽位),current_epoch = 2
  7381: known_nodes = 3,cluster_state = fail(还没分槽位),current_epoch = 2
  7382: known_nodes = 3,cluster_state = fail(还没分槽位),current_epoch = 2
  7380 的 CLUSTER NODES:
    39f34c33 127.0.0.1:7380   myself,master  link=connected
    cf302e20 127.0.0.1:7382   master         link=connected
    d0c21949 127.0.0.1:7381   master         link=connected
实测 · 本机执行输出
  ADDSLOTS 后 3031 ms,三个节点 cluster_state 都是 ok;current_epoch = ['2', '2', '2']

三个节点都知道另外两个之后 known_nodes = 3,但 cluster_state 仍是 fail——因为 16384 个槽都没有主库负责。分配槽位后大约 3.0 秒三个节点才都变成 ok(状态更新不是立即的,我没有拆开这 3.0 秒各是什么等待)。

握手一个不存在的节点

实测 · 本机执行输出
> CLUSTER MEET 127.0.0.1 9 10009
"OK"
  +     0 ms  出现 handshake 节点:127.0.0.1:9 flags=['handshake']
  +  3038 ms  handshake 节点消失(被丢弃)
  已知节点数: 3

CLUSTER MEET 127.0.0.1 9 10009 之后,节点表里立刻出现一个 handshake 节点,0.0 秒后被丢弃,known_nodes 仍是 3。握手不会永远挂着;这里的时长与 cluster-node-timeout(3000 ms)吻合,我没有改这个配置验证它们的关系。

持久化:nodes.conf

实测 · 本机执行输出
39f34c330165b63e499c55814be36723f8501706 127.0.0.1:7380@17380,,tls-port=0,shard-id=d52dba1e4e882f599bff8f4a4c556ddd382467dd myself,master - 0 0 1 connected 0-5460
  cf302e202014f28a97259c60b48c68c44d78e177 127.0.0.1:7382@17382,,tls-port=0,shard-id=b19ec5df512c0bcc591ba292bb5858cd0044b544 master - 0 1790696844241 2 connected 10923-16383
  d0c21949948fdcab4196c6c33845aaa24ff8d60e 127.0.0.1:7381@17381,,tls-port=0,shard-id=6794455ca22c5ba0f936d16e1c1001d5e8de4c6b master - 0 1790696843628 0 connected 5461-10922
  vars currentEpoch 2 lastVoteEpoch 0

节点关系写在 nodes.conf:每行 ID 地址@总线端口 角色 主ID ping 时间 pong 时间 configEpoch 链路状态 槽位,最后一行 vars currentEpoch … lastVoteEpoch …。按端口排序三个主库的 configEpoch 是 1、0、2——互不相同(第 77 篇讨论它们怎么分开)。

分步演示:从互不认识到 cluster ok

Redis Cluster 节点握手
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。三个新启动的集群节点,cluster-node-timeout 3000;每 10 ms 采样 CLUSTER NODES 的变化
    • 没有验证:更多节点时 gossip 的收敛时间、跨机器网络下的握手耗时、MEET 时指定不同总线端口以外的参数(如 cluster-announce-*)、cluster_state 从 fail 变 ok 的 3 秒里的具体等待项
    京ICP备2026067502号-1京公网安备11010502063487号