news 2026/10/6 1:49:57

CubeFS Blobstore Clustermgr 管理 API 实战指南:节点、磁盘、卷与后台任务全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CubeFS Blobstore Clustermgr 管理 API 实战指南:节点、磁盘、卷与后台任务全解析
  • 存储
  • 分布式文件系统
  • 对象存储
  • 云原生

【免费下载链接】cubefs

cloud-native distributed storage

项目地址:https://gitcode.com/gh_mirrors/cu/cubefs
点击查看免费下载

导读

Clustermgr(集群管理器)是 CubeFS Blobstore 体系中负责元数据与集群状态管理的核心服务,它基于 Raft 保证集群元数据的强一致,并对外提供一套 HTTP 管理 API,覆盖集群状态查看、Raft 节点增删与领导权切换、磁盘状态管理、卷信息查询以及后台任务开关等运维场景。本文以官方管理 API 文档(docs/source/dev-guide/admin-api/blobstore/cm.md)为主线,结合仓库源码逐接口讲解请求格式、参数含义与底层实现原理,帮助读者掌握用 curl 与 blobstore-cli 完成 Clustermgr 日常运维的核心技能。

一、Clustermgr 管理 API 概览

Clustermgr 的所有管理接口都通过 HTTP 暴露,默认监听在127.0.0.1:9998。从路由注册源码 blobstore/clustermgr/handler.go 可以看到,这些管理接口集中在文件末尾的manage分区中:

  • POST /member/add:向 Raft 集群添加成员
  • POST /member/remove:从 Raft 集群移除成员
  • POST /leadership/transfer:切换 Raft 领导者
  • GET /stat:获取集群整体状态
  • POST /config/set、GET /config/get、POST /config/delete:配置键值读写
  • 以及磁盘、卷相关的GET /disk/info、POST /disk/set、POST /disk/drop、POST /disk/access、GET /volume/get等

这些接口在 blobstore/api/clustermgr/client.go 中都有对应的 Go 客户端封装,本文统一使用 curl 演示,二者等价。

二、服务状态查询:GET /stat

/stat返回 Clustermgr 的集群整体状态,包括 Raft 状态、空间使用、卷统计等信息,是运维排障的第一入口。

curl "http://127.0.0.1:9998/stat"

响应示例

{ "leader_host": "127.0.0.1:9998", "raft_status": { "applied": 291968826, "commit": 291968826, "leader": 3, "nodeId": 2, "peers": null, "raftApplied": 291968826, "raftState": "StateFollower", "term": 24, "transferee": 0, "vote": 3 }, "read_only": false, "space_stat": { "disk_stat_infos": [ { "available": 107, "broken": 0, "dropped": 10, "dropping": 0, "expired": 0, "idc": "z0", "readonly": 22, "repaired": 17, "repairing": 0, "total": 134, "total_chunk": 55619, "total_free_chunk": 37979 }, { "available": 93, "broken": 0, "dropped": 10, "dropping": 0, "expired": 0, "idc": "z1", "readonly": 22, "repaired": 19, "repairing": 0, "total": 122, "total_chunk": 51523, "total_free_chunk": 33425 }, { "available": 96, "broken": 0, "dropped": 53, "dropping": 1, "expired": 0, "idc": "z2", "readonly": 46, "repaired": 3, "repairing": 0, "total": 152, "total_chunk": 58123, "total_free_chunk": 40173 } ], "free_space": 1774492930453504, "total_blob_node": 17, "total_disk": 408, "total_space": 2155017090891776, "used_space": 380524160438272, "writable_space": 923847465369600 }, "volume_stat": { "active_volume": 345, "can_alloc_volume": 1651, "idle_volume": 1651, "lock_volume": 0, "total_volume": 1996, "unlocking_volume": 0 } }

响应字段可分成三组来理解:

  • raft_status:Raft 协议运行细节,包括当前nodeId、term、leader、vote、applied/commit日志水位以及raftState(StateFollower/StateLeader)。leader_host则直接给出当前领导者地址,便于运维判断请求应发往哪个节点。
  • space_stat:按 IDC 聚合的物理空间统计(disk_stat_infos数组)与全局总量。disk_stat_infos中total是磁盘总数,available/readonly/broken/repairing/repaired/dropping/dropped/expired分别对应各种磁盘状态的数量,total_chunk与total_free_chunk是 chunk(容量单元)维度统计;全局字段中total_space为物理总空间,free_space为可写物理空间,writable_space为可写逻辑空间,total_blob_node为 BlobNode 节点数,total_disk为磁盘总数。
  • volume_stat:卷状态统计,total_volume为卷总数,active_volume为活跃(可服务读写)卷数,idle_volume为空闲卷数,can_alloc_volume为可分配卷数,lock_volume/unlocking_volume为锁定与解锁中的卷数。注意响应中的space_stat对应 blobstore 侧常说的 BlobNode(HDD)空间,而volume_stat中can_alloc_volume等字段来自卷分配器的实时统计。

从实现上看,blobstore/clustermgr/manage.go#L124-L137 中的Service.Stat依次聚合了 Raft 状态(s.raftNode.Status())、Leader 地址、BlobNode 空间统计、ShardNode 空间统计、卷统计与集群只读标志;其中卷统计由 blobstore/clustermgr/volumemgr/volumemgr.go#L545-L559 的VolumeMgr.Stat计算,直接取自各卷状态的运行时计数。响应体结构的字段定义可对照 blobstore/api/clustermgr/disk.go 中的DiskStatInfo、SpaceStatInfo类型。

三、节点管理

节点管理面向 Raft 集群本身的成员变更,包括添加节点、移除节点与切换领导者,是 Clustermgr 扩缩容的核心操作。

3.1 添加节点:POST /member/add

通过指定节点类型、地址与 ID 向 Raft 集群添加新成员:

curl -X POST --header 'Content-Type: application/json' -d '{"peer_id": 1, "host": "127.0.0.1:10110","node_host": "127.0.0.1:9998", "member_type": 2}' "http://127.0.0.1:9998/member/add"

参数列表

参数类型说明
peer_iduint64Raft 节点 ID,必须唯一
hoststringRaft 地址(节点间通信地址)
node_hoststring服务地址(对外提供服务的地址)
member_typeuint8节点类型,1 表示 leaner,2 表示 normal

其中member_type的取值在 blobstore/api/clustermgr/client.go 中定义为MemberType枚举:MemberTypeLearner(1,学习者节点,只同步日志不参与投票,适合先追平数据再提升为正式成员)与MemberTypeNormal(2,正式投票成员)。请求体 JSON 字段与AddMemberArgs结构体一一对应:

type AddMemberArgs struct { PeerID uint64 `json:"peer_id"` Host string `json:"host"` MemberType MemberType `json:"member_type"` NodeHost string `json:"node_host"` }

服务端 blobstore/clustermgr/manage.go#L40-L78 的MemberAdd处理逻辑值得注意:

  1. 首先校验member_type是否落在合法区间(必须为 1 或 2),否则返回参数非法;
  2. 遍历当前 Raftstatus.Peers,若peer_id或host与已有成员重复,直接返回ErrDuplicatedMemberInfo,保证 ID 与地址的唯一性;
  3. node_host会被序列化为MemberContext随成员信息一起持久化,供后续路由使用;
  4. 最终调用s.raftNode.AddMember,按类型分别以Learner: true/false加入。

该接口没有独立参数表之外的可选字段,一次请求完成一个节点的加入。

3.2 移除节点:POST /member/remove

按 ID 从 Raft 集群中移除节点:

curl -X POST --header 'Content-Type: application/json' -d '{"peer_id": 1}' "http://127.0.0.1:9998/member/remove"

参数列表

参数类型说明
peer_iduint64Raft 节点 ID,必须唯一

实现上(blobstore/clustermgr/manage.go#L80-L104)有两个关键约束:

  • 先通过checkPeerIDExist校验节点确实存在,不存在则返回参数非法;
  • 不允许直接移除当前 Leader,若peer_id等于当前raftNode.Status().Leader,接口返回ErrRequestNotAllow。正确的扩缩容流程是先用/leadership/transfer把领导权转移给其他节点,再执行移除。

3.3 切换领导者:POST /leadership/transfer

按 ID 将 Raft 领导权转移到指定节点:

curl -X POST --header 'Content-Type: application/json' -d '{"peer_id": 1}' "http://127.0.0.1:9998/leadership/transfer"

参数列表

参数类型说明
peer_iduint64Raft 节点 ID,必须唯一

对应实现 blobstore/clustermgr/manage.go#L106-L122 同样先校验节点存在,再调用s.raftNode.TransferLeadership(ctx, s.raftNode.Status().Id, args.PeerID)完成领导权转移。注意该接口的peer_id是目标节点(接收领导权的一方),常用于 Leader 节点需要下线维护或触发重新选举的场景。

四、磁盘管理

磁盘管理围绕 BlobNode 上报的物理磁盘元数据展开,支持查询、状态变更、读写属性切换与离线迁移。

4.1 查询磁盘信息:GET /disk/info

curl "http://127.0.0.1:9998/disk/info?disk_id=1"

参数列表

参数类型说明
disk_iduint32磁盘 ID

响应示例

{ "cluster_id": 10001, "create_time": "2022-05-07T15:22:01.627271402+08:00", "disk_id": 1, "free": 1910475022336, "free_chunk_cnt": 106, "host": "http://127.0.0.1:8889", "idc": "bjht", "last_update_time": "2022-05-07T15:22:01.627271402+08:00", "max_chunk_cnt": 1037, "path": "/home/service/var/data21", "rack": "HT02-B11-F4-402-0203", "readonly": false, "size": 17828005326848, "status": 1, "used": 15917530304512, "used_chunk_cnt": 931 }

响应字段覆盖磁盘的归属信息(cluster_id、idc、rack、host、path)、容量信息(size总容量、used/free已用与可用、max_chunk_cnt/used_chunk_cnt/free_chunk_cnt的 chunk 维度计数)以及运行状态(status磁盘状态、readonly是否只读、create_time/last_update_time)。这些字段对应 blobstore/api/clustermgr/disk.go 中的BlobNodeDiskInfo结构体,其中status的取值枚举定义在 blobstore/common/proto/const.go#L46-L51。

4.2 设置磁盘状态:POST /disk/set

curl -X POST --header 'Content-Type: application/json' -d '{"disk_id":2,"status":2}' "http://127.0.0.1:9998/disk/set"
参数类型说明
disk_iduint32磁盘 ID
statusuint8磁盘状态只能递增,数值含义见下表
磁盘状态值说明
1normal
2broken
3repairing
4repaired
5dropped

状态枚举在 blobstore/common/proto/const.go#L46-L51 中定义:

DiskStatusNormal = DiskStatus(iota + 1) // 1 DiskStatusBroken // 2 DiskStatusRepairing // 3 DiskStatusRepaired // 4 DiskStatusDropped // 5 DiskStatusMax // 6

服务端实现 blobstore/clustermgr/blobnode_disk.go#L152-L189 有几个细节需要运维人员注意:

  • 该接口不允许设置 dropped(5)状态:代码限定args.Status必须满足normal <= status < dropped,即只能设置 1~4,磁盘离线(dropped)必须走专门的/disk/drop接口,以保证数据迁移流程可控;
  • 状态相同则直接返回,不做重复写入;
  • 当状态被设置为broken时,会联动调用s.VolumeMgr.DiskWritableChange调整受影响卷的健康度,让上层及时感知容量变化;
  • 文档强调"磁盘状态只能递增",即运维应遵循 normal → broken → repairing → repaired 的推进顺序,避免状态回退造成管理混乱。

4.3 设置磁盘读写:POST /disk/access

将磁盘切换为只读或读写:

curl -X POST --header 'Content-Type: application/json' -d '{"disk_id":2,"readonly":false}' "http://127.0.0.1:9998/disk/access"

参数列表

参数类型说明
disk_iduint32磁盘 ID
readonlybool是否只读,true 表示只读,false 表示读写

该接口与/disk/set互补:/disk/set管理生命周期状态,/disk/access管理读写权限。将磁盘置为只读常用于容量保护、异常排查或准备下线前的过渡,只读状态下新数据不再写入该盘,但存量数据仍可读取。

4.4 设置磁盘下线:POST /disk/drop

针对机器或磁盘过保等场景,可对磁盘执行下线以触发数据迁移。迁移过程中会先尝试直接读取离线磁盘上的数据,若读取失败则走"修复后读取"流程,保证数据尽量完整搬迁:

curl -X POST --header 'Content-Type: application/json' -d '{"disk_id":2}' "http://127.0.0.1:9998/disk/drop"

服务端 blobstore/clustermgr/blobnode_disk.go#L191-L206 的DiskDrop仅接收disk_id,随后交给s.BlobNodeMgr.DropDisk执行下线逻辑——它会将磁盘标记为 dropping,由后台调度器接管数据迁移任务(迁移期间可通过GET /disk/droppinglist查询进行中的下线列表,相关路由见 blobstore/clustermgr/handler.go)。注意/disk/drop是异步触发的:接口返回只代表下线任务已受理,实际迁移进度由后台任务系统持续推进。

五、卷管理:GET /volume/get

查询单个卷的详细信息,包括卷的编码模式、容量使用与构成该卷的所有存储单元:

curl "http://127.0.0.1:9998/volume/get?vid=1"

参数列表

参数类型说明
viduint32卷 ID

响应示例

{ "code_mode": 12, "create_by_node_id": 1, "free": 1061027840, "health_score": 0, "status": 1, "total": 171798691840, "units": [ { "disk_id": 112, "host": "http://127.0.0.1:8889", "vuid": 4294967654 }, ... { "disk_id": 401, "host": "http://127.0.0.1:8889", "vuid": 4513071462 } ], "used": 170737664000, "vid": 1 }

字段含义:

  • code_mode:卷的纠删码编码模式编号(如 12 对应某种 EC 冗余策略,编码模式定义见 blobstore/common/codemode 目录),它决定了units中存储单元的数量与冗余配比;
  • vid/status:卷 ID 与卷状态;
  • total/used/free:卷的逻辑容量、已用与可用空间;
  • units:构成该卷的底层存储单元列表,每个单元由vuid(Volume Unit ID)、disk_id和所在 BlobNode 的host唯一标识,这也是卷路由(Volume Route)的基础数据;
  • health_score:卷健康分,反映底层单元异常情况,数值越大通常意味着可用性越差。

对应的请求与响应结构定义在 blobstore/api/clustermgr/volume.go:GetVolumeArgs只含vid,响应VolumeInfo由Units []Unit与VolumeInfoBase组合而成,其中Unit结构体为{Vuid, DiskID, Host}三元组。

六、后台任务开关管理

Clustermgr 会把磁盘修复、数据均衡、磁盘离线、数据删除、数据修复、数据巡检等后台任务的启停状态保存在自身的 KV 配置中,运维可随时查询与切换。支持的六类任务如下:

任务类型(type)任务名称(key)开关(value)
Disk Repairdisk_repairtrue/false
Data Balancingbalancetrue/false
Disk Offlinedisk_droptrue/false
Data Deletionblob_deletetrue/false
Data Repairshard_repairtrue/false
Data Inspectionvolume_inspecttrue/false

这些任务名与 blobstore/common/proto/scheduler.go#L40-L46 中定义的TaskType常量一一对应(disk_repair、balance、disk_drop、volume_inspect、shard_repair、blob_delete),调度器与 CLI 工具均以这些字符串作为开关的 key。

6.1 查看任务状态

curl http://127.0.0.1:9998/config/get?key=balance # 或使用 blobstore-cli blobstore-cli cm background status balance

6.2 开启任务

curl -X POST http://127.0.0.1:9998/config/set -d '{"key":"balance","value":"true"}' --header 'Content-Type: application/json' # 或使用 blobstore-cli blobstore-cli cm background enable balance

6.3 关闭任务

curl -X POST http://127.0.0.1:9998/config/set -d '{"key":"balance","value":"false"}' --header 'Content-Type: application/json' # 或使用 blobstore-cli blobstore-cli cm background disable balance

背后的实现机制在 blobstore/clustermgr/config.go 中非常清晰:

  • ConfigGet(L32-L59)属于线性一致读:先调用s.raftNode.ReadIndex(ctx)确认当前节点状态已追平 Leader 的提交水位,再从ConfigMgr读取配置,保证读到的一定是最新值;
  • ConfigSet(L61-L90)走Raft Propose 持久化:将{key, value}序列化后封装为OperTypeSetConfig提案提交给 Raft,经多数派确认后才生效,因此任何节点发起的配置变更都会在集群内保持一致;同时,若 key 属于proto.IsUnmodifiableSysConfigKey保护的系统配置,接口会直接拒绝,防止误改核心配置。

6.4 blobstore-cli 用法补充

blobstore-cli cm background子命令定义在 blobstore/cli/clustermgr/background.go,支持status、enable、disable三个动作,交互式确认后执行,适合人工操作;其底层仍是通过上述config/get与config/set接口完成读写,并在enable/disable时校验任务名合法性。除后台任务外,blobstore-cli cm还提供磁盘管理、卷管理等更多子命令(见 blobstore/cli/clustermgr 目录),例如blobstore-cli cm disk set、blobstore-cli cm volume get等,可作为 curl 之外的另一条运维路径。

七、运维要点小结

结合文档与源码,使用 Clustermgr 管理 API 时有几个值得牢记的实践要点:

  1. 写操作务必发往 Leader:/member/add、/disk/set、/config/set等写接口依赖 Raft Propose,若请求落在 Follower 上会因无法提交而失败。日常可通过GET /stat的leader_host字段定位当前 Leader,将管理请求定向发送。
  2. 移除节点前先转移领导权:/member/remove明确禁止移除 Leader,标准流程是/leadership/transfer转移后再执行移除,避免集群在无主状态下操作。
  3. 磁盘状态单向推进:/disk/set只能设置 normal→broken→repairing→repaired 序列,且不能直接置为 dropped;真正的下线操作必须走/disk/drop,由后台调度器完成数据迁移。
  4. 后台任务开关全局生效且持久化:任务开关以true/false字符串存储在 Raft 共识的配置中,任意节点写入、全集群一致,适合在维护窗口统一关闭均衡、巡检等任务以减少干扰。

以上接口的路由、参数解析与实现均可对照仓库源码进一步学习:路由全表见 blobstore/clustermgr/handler.go,节点管理实现在 blobstore/clustermgr/manage.go,磁盘管理实现在 blobstore/clustermgr/blobnode_disk.go,配置管理实现在 blobstore/clustermgr/config.go,Go 客户端封装见 blobstore/api/clustermgr/client.go 及同目录下的disk.go、volume.go、config.go。

  • 存储
  • 分布式文件系统
  • 对象存储
  • 云原生

【免费下载链接】cubefs

cloud-native distributed storage

项目地址:https://gitcode.com/gh_mirrors/cu/cubefs
点击查看免费下载

相关推荐

上一篇:ICR - 交互式Crystal编程语言控制台
下一篇:TSDF-Fusion 项目推荐

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

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

DLSS Swapper 完整指南:3 步替换游戏内 DLSS 版本,随时可回退

DLSS Swapper 完整指南&#xff1a;3 步替换游戏内 DLSS 版本&#xff0c;随时可回退 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 游戏还卡在旧版 DLSS&#xff0c;新 DLL 早已释出&#xff0c;厂商却迟迟不出补丁。…

作者头像 李华
网站建设 2026/10/6 1:48:51

JavaScript 中比较两个 Date 对象的相等性与大小

文档教程知识库 【免费下载链接】til :memo: Today I Learned 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ti/til 点击查看 免费下载 在 JavaScript 里判断两个 Date 对象是否相等并不是一个直观的操作——即使两个对象在概念上&#xff08;甚至打印出来&#xff0…

作者头像 李华
网站建设 2026/10/6 1:45:15

Packet Tracer校园网实战:VLAN间路由与NAT出网全配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:45:01

I2C远距离通信实战:TCA9517缓冲器与双绞线布局详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:45:01

PCIe硬件设计实战:从差分信号到链路训练全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 1:43:41

嵌入式Linux功耗管理:PM QoS约束聚合机制与CPUIdle调优实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华