【HCCL学习笔记】拓扑图核心概念:Node、Fabric、Edge
2026/4/24 7:03:27 网站建设 项目流程

HCCL 拓扑图核心概念:Node、Fabric、Edge

一、概述

在 HCCL 虚拟拓扑(NetInstance)中,数据结构采用**图(Graph)**的组织方式,核心概念包括:

概念说明
Node(节点)Graph::nodes图中的顶点,代表 Peer(计算节点)或 Fabric(交换机)
Fabric(交换机)NetInstance::Fabric网络交换设备的抽象,表示交换机/路由器
Edge / Link(边)Graph::edges+NetInstance::Link图中的边,描述两个节点之间的连接关系
ConnInterface(接口)NetInstance::ConnInterface节点的连接接口,包含地址和端口信息
Path(路径)NetInstance::Path由一条或多条 Link 组成的通信路径

二、Graph 类模板

2.1 数据结构

template<typenameNodeType,typenameEdgeType>classGraph{private:// 三层嵌套 Map:srcNodeId → dstNodeId → edges[]std::unordered_map<NodeId,std::unordered_map<NodeId,std::vector<std::shared_ptr<EdgeType>>>>edges;std::unordered_map<NodeId,std::shared_ptr<NodeType>>nodes;};

2.2 edges 的三层结构

edges 的数据结构: ┌─────────────────────────────────────────────────────────────────────────┐ │ edges (三层嵌套 Map) │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 第一层 Key: srcNodeId (源节点ID) │ │ │ │ │ ▼ │ │ 第二层 Key: dstNodeId (目标节点ID) │ │ │ │ │ ▼ │ │ 第三层 Value: vector<shared_ptr<EdgeType>> (边数组) │ │ │ │ │ ├── edge1 (Link) │ │ ├── edge2 (Link) │ │ └── edge3 (Link) │ │ │ └─────────────────────────────────────────────────────────────────────────┘ 为什么是 vector 而不是单个 Edge? → 两个节点之间可能存在多条边(不同端口、不同协议、冗余路径)

2.3 核心方法

// 添加节点voidAddNode(constNodeId nodeId,std::shared_ptr<NodeType>node){nodes[nodeId]=node;}// 添加边voidAddEdge(constNodeId srcNodeId,constNodeId dstNodeId,std::shared_ptr<EdgeType>edge){edges[srcNodeId][dstNodeId].push_back(edge);}// 遍历某节点的所有出边voidTraverseEdge(constNodeId srcNodeId,std::function<void(std::shared_ptr<EdgeType>)>func)const;// 遍历两个节点之间的所有边voidTraverseEdge(constNodeId srcNodeId,constNodeId dstNodeId,std::function<void(std::shared_ptr<EdgeType>)>func)const;

三、NodeId 生成规则

3.1 NodeId 的二进制结构

┌─────────────────────────────────────────────────────────────┐ │ NodeId (64 bit) │ ├─────────────────────────────────────────────────────────────┤ │ bit[63:32] │ bit[31:0] │ │ 类型标识位 │ ID 值 │ │ ───────────────────┼───────────────────── │ │ Peer: 0b0000...0 │ rankId (如 0, 1, 2, ...) │ │ Fabric: 0b0000...1 │ fabricId (如 0, 1, 2, ...) │ └─────────────────────────────────────────────────────────────┘ 示例: Peer NodeId(rankId=5) = 0x00000000_00000005 Fabric NodeId(fabricId=2) = 0x00000001_00000002

3.2 NodeId 的生成代码

// Peer 节点 ID 生成NodeId NetInstance::Peer::GenerateNodeId(RankId rankId){// 第 32 位为 0 + rankIdreturn(static_cast<u64>(rankId)|static_cast<u64>(0)<<32);}// Fabric 节点 ID 生成NodeId NetInstance::Fabric::GenerateNodeId(FabricId fabricId)const{// 第 32 位为 1 + fabricIdreturn(static_cast<u64>(fabricId)|static_cast<u64>(1)<<32);}

四、Fabric(交换机)详解

4.1 什么是 Fabric

Fabric 是**网络交换设备(交换机/路由器)**的抽象,表示集群中用于跨节点通信的网络设备。

物理拓扑示例: ┌──────────────────────────────────────────────┐ │ Fabric (交换机) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Switch1 │ │ Switch2 │ │ Switch3 │ │ │ └───┬─────┘ └───┬─────┘ └───┬─────┘ │ └───────┼───────────┼───────────┼──────────────┘ │ │ │ ┌────────────┼───────────┼───────────┼────────────┐ │ │ │ │ │ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐ │ Peer0 │ │ Peer1 │ │ Peer2 │ │ Peer3 │ │ Peer4 │ │ (Rank0)│ │ (Rank1)│ │ (Rank2)│ │ (Rank3)│ │ (Rank4)│ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘

4.2 Fabric 类的定义

// net_instance.hclassFabric:publicNode{public:explicitFabric(FabricId fabricId,PlaneId planeId):Node(NodeType::FABRIC),fabricId_(fabricId),planeId_(planeId){nodeId_=GenerateNodeId(fabricId);// bit[32] = 1}PlaneIdGetPlaneId()const{returnplaneId_;}private:FabricId fabricId_;// Fabric 节点 IDPlaneId planeId_;// Plane ID(网络平面)};

4.3 Fabric 的创建过程

// rank_graph_builder.cc: AddFabricInfo()// 1. 从 ranktable 的地址信息中获取 planeId → fabricId 映射std::map<PlaneId,FabricId>planeId2Node=GetFabricsFromAddrInfo(myLevelInfo.rankAddrs);// 2. 遍历每个 Rank,创建 Fabric 节点for(RankId srcRankId:inRanks){for(AddressInfo addrInfo:addrs){FabricId fabId=planeId2Node[addrInfo.planeId];// 3. 如果 Fabric 不存在则创建shared_ptr<NetInstance::Fabric>fabNode;if(fabNodes[fabId]==nullptr){fabNode=make_shared<NetInstance::Fabric>(fabId,addrInfo.planeId);tempNetInsts_[netLayer][netInstId]->AddNode(fabNode);fabNodes[fabId]=fabNode;}// 4. 创建 Peer ↔ Fabric 之间的链路AddPeer2NetLink(netLayer,netInstId,srcRankId,addrInfo,fabNode,links);}}

4.4 Fabric vs Peer

类型说明NodeId bit[32]
Peer计算节点0
Fabric交换设备(交换机/路由器)1

五、Link(边)详解

5.1 Link 的结构

classLink{std::shared_ptr<NetInstance::Node>source_;// 源节点std::shared_ptr<NetInstance::Node>target_;// 目标节点std::shared_ptr<NetInstance::ConnInterface>sourceIface_;// 源端接口std::shared_ptr<NetInstance::ConnInterface>targetIface_;// 目标端接口LinkType type_;// 链路类型std::set<LinkProtocol>linkProtocols_;// 链路协议LinkDirection direction_;// 方向u32 hop_;// 跳数};

5.2 Link 的创建

// rank_graph_builder.cc: AddPeer2NetLink()// 1. 获取 Peer 和 Fabric 节点shared_ptr<NetInstance::Peer>peerNode=peers_.at(rankId);// 2. 创建 Peer → Fabric 的 Linkshared_ptr<NetInstance::Link>peer2netLink=make_shared<NetInstance::Link>(peerNode,// source: PeerfabNode,// target: FabricpeerIface,// sourceIface: Peer 的接口nullptr,// targetIface: Fabric 侧为空LinkType::PEER2NET,link->GetLinkProtocols(),LinkDirection::BOTH,// 双向2// hop 数);// 3. 创建 Fabric → Peer 的 Link(反向)shared_ptr<NetInstance::Link>net2peerLink=make_shared<NetInstance::Link>(fabNode,// source: FabricpeerNode,// target: Peernullptr,// sourceIfacepeerIface,// targetIface: Peer 的接口LinkType::PEER2NET,link->GetLinkProtocols(),LinkDirection::BOTH,2);// 4. 添加到 NetInstancetempNetInsts_[netLayer][netInstId]->AddLink(peer2netLink);tempNetInsts_[netLayer][netInstId]->AddLink(net2peerLink);

5.3 AddLink 的实现

voidNetInstance::AddLink(constshared_ptr<NetInstance::Link>&link){NodeId srcNodeId=link->GetSourceNode()->GetNodeId();NodeId dstNodeId=link->GetTargetNode()->GetNodeId();// 检查是否已存在boolhasLink=false;vGraph.TraverseEdge(srcNodeId,dstNodeId,[&](shared_ptr<NetInstance::Link>edge){if(*edge==*link){hasLink=true;return;}});if(hasLink){HCCL_WARNING("[NetInstance::AddLink] the fabric group already has the same link.");return;}// 添加到 vGraphvGraph.AddEdge(srcNodeId,dstNodeId,link);}

六、Path(路径)详解

6.1 Path 的结构

structPath{std::vector<Link>links;// 组成路径的 Link 列表LinkDirection direction;// 方向};

6.2 InnerNetInstance::GetPaths

vector<NetInstance::Path>InnerNetInstance::GetPaths(constRankId srcRankId,constRankId dstRankId)const{vector<NetInstance::Path>paths;// 1. 获取 NodeIdNodeId srcPeerId=peers.at(srcRankId)->GetNodeId();NodeId dstPeerId=peers.at(dstRankId)->GetNodeId();// 2. 获取直连路径:src ↔ dstvGraph.TraverseEdge(srcPeerId,dstPeerId,[&](shared_ptr<NetInstance::Link>edge){NetInstance::Path path;path.links={*edge};path.direction=edge->GetLinkDirection();paths.emplace_back(path);});// 3. 获取通过 Fabric 的路径:src → fabric → dstfor(auto&fabric:fabrics){NodeId fabricId=fabric->GetNodeId();// src → fabric 的链路vector<NetInstance::Link>srcToFabricLinks;vGraph.TraverseEdge(srcPeerId,fabricId,[&](shared_ptr<NetInstance::Link>edge){srcToFabricLinks.push_back(*edge);});// fabric → dst 的链路vector<NetInstance::Link>fabricToDstLinks;vGraph.TraverseEdge(fabricId,dstPeerId,[&](shared_ptr<NetInstance::Link>edge){fabricToDstLinks.push_back(*edge);});if(!srcToFabricLinks.empty()&&!fabricToDstLinks.empty()){for(auto&srcLink:srcToFabricLinks){for(auto&dstLink:fabricToDstLinks){CheckPortGroupSize(netLayer,srcLink,dstLink);NetInstance::Path path;path.links={srcLink,dstLink};paths.emplace_back(path);}}}}returnpaths;}

七、拓扑图可视化

7.1 图的节点和边

vGraph 中的节点和边: ┌──────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ Peer0 │ NodeId = 0x00000000_00000000 │ │ │ (rankId=0) │ bit[32]=0, rankId=0 │ │ └──────┬──────┘ │ │ │ │ │ ├──▶ Link(Peer0→Fabric0, eth0) │ │ │ │ │ ├──▶ Link(Peer0→Fabric0, eth1) │ │ │ │ │ └──▶ Link(Peer0→Peer1) │ │ │ │ ┌─────────────┐ │ │ │ Fabric0 │ NodeId = 0x00000001_00000000 │ │ │ (fabricId=0)│ bit[32]=1, fabricId=0 │ │ └──────┬──────┘ │ │ │ │ │ ├──▶ Link(Fabric0→Peer0, eth0) │ │ │ │ │ └──▶ Link(Fabric0→Peer1, eth0) │ │ │ └──────────────────────────────────────────────────────────────┘

7.2 edges 的实际数据示例

edges={// Peer0 → Fabric0 (2 条边,对应 2 个端口)NodeId(Peer0):{NodeId(Fabric0):[Link(src=Peer0,dst=Fabric0,iface=eth0),Link(src=Peer0,dst=Fabric0,iface=eth1)]},// Peer1 → Fabric0 (1 条边)NodeId(Peer1):{NodeId(Fabric0):[Link(src=Peer1,dst=Fabric0,iface=eth0)]},// Fabric0 → Peer0 (2 条边)NodeId(Fabric0):{NodeId(Peer0):[Link(src=Fabric0,dst=Peer0,iface=eth0),Link(src=Fabric0,dst=Peer0,iface=eth1)]},// Fabric0 → Peer1 (1 条边)NodeId(Fabric0):{NodeId(Peer1):[Link(src=Fabric0,dst=Peer1,iface=eth0)]}};

八、CheckPortGroupSize 校验

在构建通过 Fabric 的路径时,会校验源 Peer 和目标 Peer 的端口数量:

voidCheckPortGroupSize(u32 netLayer,NetInstance::Link&srcLink,NetInstance::Link&dstLink){autosrcConnIface=srcLink.GetSourceIface();// src → fabric 链路的源接口autotargetConnIface=dstLink.GetTargetIface();// fabric → dst 链路的目标接口autosrcPortGroupSize=srcConnIface->GetPorts().size();// Peer 的端口数autotgtPortGroupSize=targetConnIface->GetPorts().size();// Peer 的端口数if(srcPortGroupSize!=tgtPortGroupSize){THROW<InvalidParamsException>(StringFormat("[GetPaths][CheckPortGroupSize] portGroupSize is not equal => src[%u], target[%u].""LocatedInfo: NetLayer[%u], localRank[%u], rmtRank[%u], localAddr[%s], rmtAddr[%s]",srcPortGroupSize,tgtPortGroupSize,netLayer,localRankId,remoteRankId,localAddr.Describe().c_str(),remoteAddr.Describe().c_str()));}}

检查含义

  • srcLink:srcPeer → Fabric 的链路,源接口是 srcPeer 的接口
  • dstLink:Fabric → dstPeer 的链路,目标接口是 dstPeer 的接口
  • 检查两个 Peer 节点的端口数量是否一致(用于 CLOS 拓扑中 src→Fabric→dst 路径的端口绑定校验)

九、总结

概念类/结构说明
NodeIduint64_t图中节点的唯一标识,Peer 的 bit[32]=0,Fabric 的 bit[32]=1
Node(节点)Graph::nodes图中的顶点,Peer 或 Fabric
Peer(计算节点)NetInstance::Peer计算节点,NodeId bit[32]=0
Fabric(交换机)NetInstance::Fabric网络交换设备,NodeId bit[32]=1
Edge / Link(边)Graph::edges+NetInstance::Link描述两个节点之间的连接关系
ConnInterface(接口)NetInstance::ConnInterface节点的连接接口,包含地址和端口
Path(路径)vector<Link>一条通信路径,由一条或多条 Link 组成
vGraphGraph<Node, Link>拓扑图,存储所有节点和边

关键关系

Peer/Rank ───▶ GetNodeId() ───▶ NodeId (bit[32] 区分类型) │ ▼ vGraph 中的顶点 NodeId ───▶ TraverseEdge() ───▶ edge (Link) │ ├── GetSourceNode() → 源 Peer/Fabric ├── GetTargetNode() → 目标 Peer/Fabric ├── GetSourceIface() → 源端接口(端口信息) └── GetTargetIface() → 目标端接口(端口信息) Edge ───▶ 组成 Path ───▶ 用于 GetPaths 查找通信路径

一句话总结

vGraph是一个有向图,nodes存储 Peer 和 Fabric 两种节点,edges存储节点之间的 Link。topo.json决定"哪些节点之间有边",ranktable.json提供边所需的端口和地址信息,两者通过端口交集生成最终的ConnInterface,进而创建Link加入图中。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询