news 2026/9/10 21:27:52

Dragonfly 集群节点健康状态(Node Health)机制全解析:配置、命令行为与源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dragonfly 集群节点健康状态(Node Health)机制全解析:配置、命令行为与源码实现

Dragonfly 集群节点健康状态(Node Health)机制全解析:配置、命令行为与源码实现

【免费下载链接】dragonflyA modern replacement for Redis and Memcached项目地址: https://gitcode.com/GitHub_Trending/dr/dragonfly

节点健康状态(Node Health)是 Dragonfly 集群控制面(cluster manager / orchestrator)通过DFLYCLUSTER CONFIG命令下发给各节点的被动元数据:节点本身不主动探测自身状态,而是由集群管理器负责监控,并把每个节点的健康状态写进集群配置 JSON 中。本文围绕 docs/cluster-node-health.md 展开,完整讲解online / loading / fail / hidden四种健康状态的定义、配置格式、CLUSTER SHARDS / CLUSTER SLOTS / CLUSTER NODES三个命令的过滤与展示行为,并深入到 src/server/cluster 源码层验证其实现细节,帮助你正确管理集群节点的上下线与可见性,实现 Valkey 兼容的集群客户端行为。

概述:节点健康状态是什么

Dragonfly 对集群节点健康状态的支持,是为了让集群管理器能够跟踪每个节点的健康状态,并通过各类集群命令把该状态传达给客户端。该特性在 PR #4758 与 PR #4767 中引入,用于解决 issue #4741 中提出的集群节点健康管理需求。

核心设计理念是:节点健康是被动元数据,由控制面提供。节点不会自行判定"我是否健康",而是由集群编排器监控节点状态,再通过集群配置(DFLYCLUSTER CONFIG)把健康信息同步给每个节点。这意味着:

  • 健康状态是集群配置的一部分,master 与 replica 节点都可以设置;
  • 不同集群命令会基于健康状态对节点做过滤展示处理;
  • 状态变更的判定逻辑(如节点是否失联、是否仍在同步)由集群管理器负责,Dragonfly 只负责"接收并表达"。

四种健康状态

Dragonfly 为集群节点定义了四种健康状态,定义于 src/server/cluster/cluster_defs.h:

enum class NodeHealth : std::uint8_t { FAIL, LOADING, ONLINE, HIDDEN };
状态含义在命令中的可见性
online节点完全可用,随时可以服务请求所有命令
loading节点仍在加载数据(例如初次同步或重启过程中)CLUSTER SHARDSCLUSTER NODES
fail节点已失败或不可达CLUSTER SHARDSCLUSTER NODES
hiddenreplica 存在但不应暴露给客户端(供集群管理器内部使用)master:所有命令;replica:均不可见

默认状态

当配置中未指定健康状态时,节点默认处于online状态。该默认值定义在ClusterExtendedNodeInfo结构体中(见 src/server/cluster/cluster_defs.h):

struct ClusterExtendedNodeInfo : ClusterNodeInfo { NodeHealth health = NodeHealth::ONLINE; ... };

从源码结构可以推断:ClusterExtendedNodeInfo在基础节点信息(idipport,见 src/server/cluster/cluster_defs.h)之上扩展了health字段,并内置了ONLINE默认值,因此省略health字段的节点配置天然就是online

配置:如何设置节点健康状态

节点健康状态通过DFLYCLUSTER CONFIG命令传入的集群配置 JSON 进行设置,每个节点使用health字段声明状态。

配置格式

[ { "slot_ranges": [ { "start": 0, "end": 16383 } ], "master": { "id": "node-master-1", "ip": "10.0.0.1", "port": 7000, "health": "online" }, "replicas": [ { "id": "node-replica-1", "ip": "10.0.0.2", "port": 7001, "health": "online" }, { "id": "node-replica-2", "ip": "10.0.0.3", "port": 7002, "health": "loading" }, { "id": "node-replica-3", "ip": "10.0.0.4", "port": 7003, "health": "fail" }, { "id": "node-replica-4", "ip": "10.0.0.5", "port": 7004, "health": "hidden" } ] } ]

下发配置

使用DFLYCLUSTER CONFIG命令下发包含健康信息的集群配置:

DFLYCLUSTER CONFIG <json_config>

health字段可选且大小写不敏感,合法取值为:onlineloadingfailhidden。从命令注册信息看(src/server/cluster/cluster_family.cc),DFLYCLUSTER属于CO::ADMIN管理类命令,需要集群管理权限(acl::kDflyCluster)才能执行。

解析逻辑的源码细节

health字段在 src/server/cluster/cluster_config.cc 的ParseClusterNode函数中被解析:

  • 依次解析idipport,任一项非法都会导致该节点解析失败并返回nullopt
  • health通过absl::EqualsIgnoreCase大小写不敏感匹配,"FAIL""LOADING""ONLINE""HIDDEN"四种写法(任意大小写组合)均可识别;
  • health存在但不是字符串、或取值不合法,会记录LOG(ERROR)错误日志,但不会使整体配置解析失败——该节点保持默认的ONLINE状态;
  • master 与 replicas 都经由同一个ParseClusterNode解析(见 src/server/cluster/cluster_config.cc 中BuildClusterConfigFromJson的调用),所以两种角色的节点都支持health字段。

单测 src/server/cluster/cluster_config_test.cc 中的TEST_F(ClusterConfigTest, NodesHealth)直接验证了该解析行为:配置中 master 为online、两个 replica 分别为loadingfail,解析后断言master.health == NodeHealth::ONLINEreplicas.front().health == NodeHealth::LOADINGreplicas.back().health == NodeHealth::FAIL

命令行为:不同命令如何对待健康状态

不同集群命令对节点健康状态的处理方式不同,核心逻辑集中在 src/server/cluster/cluster_family.cc 中。

CLUSTER SHARDS

CLUSTER SHARDS返回集群分片的详细信息,包含除hidden之外所有节点的健康状态

示例输出:

127.0.0.1:6379> CLUSTER SHARDS 1) 1) "slots" 2) 1) (integer) 0 2) (integer) 16383 3) "nodes" 4) 1) 1) "id" 2) "node-master-1" 3) "endpoint" 4) "10.0.0.1" 5) "ip" 6) "10.0.0.1" 7) "port" 8) (integer) 7000 9) "role" 10) "master" 11) "replication-offset" 12) (integer) 0 13) "health" 14) "online" 2) 1) "id" 2) "node-replica-1" 3) "endpoint" 4) "10.0.0.2" 5) "ip" 6) "10.0.0.2" 7) "port" 8) (integer) 7001 9) "role" 10) "replica" 11) "replication-offset" 12) (integer) 0 13) "health" 14) "online" 3) 1) "id" 2) "node-replica-2" 3) "endpoint" 4) "10.0.0.3" 5) "ip" 6) "10.0.0.3" 7) "port" 8) (integer) 7002 9) "role" 10) "replica" 11) "replication-offset" 12) (integer) 0 13) "health" 14) "loading" 4) 1) "id" 2) "node-replica-3" 3) "endpoint" 4) "10.0.0.4" 5) "ip" 6) "10.0.0.4" 7) "port" 8) (integer) 7003 9) "role" 10) "replica" 11) "replication-offset" 12) (integer) 0 13) "health" 14) "fail"

注意:hidden状态的节点会被过滤掉,不出现在输出中。

源码依据(src/server/cluster/cluster_family.cc):ClusterFamily::ClusterShards先通过std::erase_ifhealth == NodeHealth::HIDDEN的 replica 从分片信息中剔除,再调用ClusterShardsImpl输出。每个节点输出 14 个字段(idendpointipportrolereplication-offsethealth),其中health字段直接使用ToString(node.health)序列化(src/server/cluster/cluster_defs.cc 中的ToString将枚举映射为"fail"/"loading"/"online"/"hidden"小写字符串)。过滤只作用于 replica——即使 master 被标记为HIDDEN,它仍然会出现在输出中。

CLUSTER SLOTS

CLUSTER SLOTS返回槽位分布信息,会过滤掉尚未就绪、无法服务请求的 replica

过滤行为:

  • 包含online状态的 replica;
  • 排除loadingfailhidden状态的 replica。

示例输出:

127.0.0.1:6379> CLUSTER SLOTS 1) 1) (integer) 0 2) (integer) 16383 3) 1) "10.0.0.1" 2) (integer) 7000 3) "node-master-1" 4) 1) "10.0.0.2" 2) (integer) 7001 3) "node-replica-1"

本例中,只有 master 和online的 replica(node-replica-1)被展示;loadingfailhidden状态的 replica 均不包含在内。

源码依据(src/server/cluster/cluster_family.cc):ClusterSlotsImplstd::erase_if一次剔除三种非就绪状态的 replica——HIDDENFAILLOADING(源码注释为 "we need to remove hidden and fail replicas")。剔除逻辑同样只作用于 replica 列表,master 始终被包含。注意该命令的响应中每个节点只输出ipportid三个字段,不包含health字段。

CLUSTER NODES

CLUSTER NODES以空格分隔的文本格式返回全部集群节点列表,展示大多数健康状态的节点,但排除hidden节点

连接状态映射:

  • onlineloading节点:显示为connected
  • fail节点:显示为disconnected
  • hidden节点:不显示在输出中

示例输出:

127.0.0.1:6379> CLUSTER NODES node-master-1 10.0.0.1:7000@7000 master - 0 0 0 connected 0-16383 node-replica-1 10.0.0.2:7001@7001 slave node-master-1 0 0 0 connected node-replica-2 10.0.0.3:7002@7002 slave node-master-1 0 0 0 connected node-replica-3 10.0.0.4:7003@7003 slave node-master-1 0 0 0 disconnected

对照说明:

  • node-replica-1(online):显示为connected
  • node-replica-2(loading):显示为connected
  • node-replica-3(fail):显示为disconnected
  • node-replica-4(hidden):不显示在输出中

源码依据(src/server/cluster/cluster_family.cc):ClusterNodesImplWriteNode用三元表达式完成连接状态映射:

node.health != NodeHealth::FAIL ? "0 0 0 connected" : "0 0 0 disconnected"

即只有FAIL状态显示为disconnected,其余(含LOADING)均为connected。列出 replica 时同样用if (replica.health != NodeHealth::HIDDEN)跳过hiddenreplica,而 master 无条件写入(即便被标记为HIDDEN)。输出行之间仅用\n分隔(不使用\r\n),这是 issue #2726 中确定的行为。

典型使用场景

1. 渐进式节点加入(Gradual Node Addition)

当向集群添加新 replica 时,可在其同步数据期间将健康状态设置为loading。这样集群管理器可以跟踪到该节点的存在,但客户端无法通过CLUSTER SLOTS把读请求重定向到它——因为CLUSTER SLOTS只返回online的 replica。同步完成后,集群管理器再把状态更新为online,节点即可对外服务。

2. 故障节点处理(Failed Node Handling)

当节点失败或不可达时,集群管理器可将其标记为fail。这样该节点在CLUSTER SHARDSCLUSTER NODES中仍然可见(便于运维排查),但会被排除在CLUSTER SLOTS响应之外,客户端不会把请求路由到故障节点。

3. 内部 replica(Internal Replicas)

hidden状态适用于由集群编排器内部管理、但不应暴露给外部客户端的 replica。被标记为hidden的 replica 会从所有集群命令(CLUSTER SHARDSCLUSTER SLOTSCLUSTER NODES)中过滤掉。注意:被标记为hidden的 master 在所有命令中仍然可见——过滤只作用于 replica。

4. Valkey 兼容性

该特性提供了 Valkey 兼容的集群客户端 API 行为:

  • CLUSTER SHARDS返回 replica 节点的健康状态(health字段);
  • CLUSTER SLOTS不返回尚未完成加载(loading等非online)的 replica。

实现细节:从数据模型到命令处理

对于关注实现的开发者,可沿以下链路阅读源码:

  1. 数据模型NodeHealth枚举定义于 src/server/cluster/cluster_defs.h,包含FAILLOADINGONLINEHIDDEN四个值;枚举到字符串的映射ToString位于 src/server/cluster/cluster_defs.cc。值得注意:HIDDENToString中带有DCHECK(false)断言("shouldn't be used"),因为hidden节点在输出前已被过滤,正常流程中不应被序列化到任何命令响应。

  2. 配置解析:健康状态在 src/server/cluster/cluster_config.cc 的ParseClusterNode函数中从 JSON 解析,master 与 replica 共用该函数;非法health值只记录错误日志、不中断整体解析。

  3. 命令处理器:src/server/cluster/cluster_family.cc 中三个命令各自实现基于健康状态的过滤逻辑:

    • ClusterShards(L232-L243):调用ClusterShardsImpl前先剔除HIDDENreplica(master 即使为HIDDEN也保留);
    • ClusterSlotsImpl(L246-L286):剔除HIDDENFAILLOADING的 replica(master 始终包含);
    • ClusterNodesImpl(L298-L343):列出 replica 时剔除HIDDEN(master 为HIDDEN仍包含),并把健康状态映射为connected/disconnected
  4. 默认值:未指定时节点默认ONLINE,定义于 src/server/cluster/cluster_defs.h 的ClusterExtendedNodeInfo

  5. 测试佐证:src/server/cluster/cluster_family_test.cc 中构造了包含online/loading/fail/hidden四种 replica 的完整集群配置,并断言CLUSTER SHARDS输出中health字段的取值与hiddenreplica 的缺席;src/server/cluster/cluster_config_test.cc 的NodesHealth用例则验证了 JSON 到枚举的解析结果。

延伸阅读

  • Dragonfly 集群模式完整文档
  • 集群拓扑相关设计图
  • 槽位迁移机制
  • 集群节点健康状态原始文档
  • 集群配置解析与测试:src/server/cluster/cluster_config.cc、src/server/cluster/cluster_config_test.cc
  • 集群命令实现与测试:src/server/cluster/cluster_family.cc、src/server/cluster/cluster_family_test.cc

【免费下载链接】dragonflyA modern replacement for Redis and Memcached项目地址: https://gitcode.com/GitHub_Trending/dr/dragonfly

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 21:27:23

WSABuilds:把C/C++编译成WebAssembly的Bazel构建工具

WSABuilds&#xff1a;把C/C编译成WebAssembly的Bazel构建工具 【免费下载链接】WSABuilds Run Windows Subsystem For Android on your Windows 10 and Windows 11 PC using prebuilt binaries with Google Play Store (MindTheGapps) and/or Magisk or KernelSU (root soluti…

作者头像 李华
网站建设 2026/9/10 21:27:09

User Service

User Service 【免费下载链接】agents Multi-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity 项目地址: https://gitcode.com/GitHub_Trending/agents24/agents Purpose: Manages user account…

作者头像 李华
网站建设 2026/9/10 21:27:00

MarkItDown 完整指南:一条命令免费转换文档到 Markdown 的教程

MarkItDown 完整指南&#xff1a;一条命令免费转换文档到 Markdown 的教程 【免费下载链接】markitdown Python tool for converting files and office documents to Markdown. 项目地址: https://gitcode.com/GitHub_Trending/ma/markitdown MarkItDown 是一个免费开源…

作者头像 李华
网站建设 2026/9/10 21:26:10

3条命令跑通实时服务编排系统:iii 完整教程(免费开源)

3条命令跑通实时服务编排系统&#xff1a;iii 完整教程&#xff08;免费开源&#xff09; 【免费下载链接】iii Effortlessly compose, extend, and observe every service in real-time for the first time ever. 项目地址: https://gitcode.com/GitHub_Trending/mo/iii …

作者头像 李华
网站建设 2026/9/10 21:24:43

CANN/ge推理上下文概述

简介 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好…

作者头像 李华