
简介智算网络横向扩展Scale-out与纵向扩展Scale-up技术解析代码包是一份面向人工智能基础设施研发者和网络工程师的源码资料用于辅助理解智算集群中前端与后端网络的设计差异。压缩包共三个文件包含网页展示页面、在线运行配置和版本管理忽略文件整体体积约六KB非常轻量便于快速查阅。已有二百一十九人学习下载。代码内容围绕横向扩展网络基于以太网或无限带宽实现图形处理器之间的远程直接内存访问应用于前端扩展纵向扩展网络在计算单元内实现跨图形处理器内存读写以纳秒级超低时延支撑后端高性能互连。同时分析了两种网络在带宽、时延、大模型训练场景中的不同作用并探讨了成本优化与未来融合方向适合有一定分布式训练基础、希望系统构建智算网络知识体系的读者。 智算网络Scale-out与Scale-up技术解析是这两年搞大模型基础设施的人绕不开的一道坎。本来嘛GPU服务器堆在一起网络怎么连、连完带宽够不够、训练任务跑起来卡不卡这些事以前做传统云网络的人并不太在意因为业务模型不一样。可到了大模型训练这个场景分布式集合通信变成了常态网络就不再是“能通就行”的基础设施而是直接决定训练效率和成本上限的关键环节。我最近整理一个智算集群项目的代码和文档正好把Scale-out和Scale-up这两条技术路线的选型逻辑、落地方案、配套工程化手段重新梳理了一遍写成这篇博文给准备上智算网络或者正在被组网方案折磨的朋友一个参考。这个内容适合谁看第一类是数据中心网络工程师想搞清楚智算场景下RoCE、拥塞控制、无损网络这些概念怎么落地第二类是AI基础设施平台开发者需要理解网络拓扑对训练框架比如NCCL的影响好给自己平台做资源调度第三类是项目负责人或者架构师要在Scale-out和Scale-up之间做技术选型得先搞清楚两种方案的成本模型和性能边界。我会把整个思路拆开揉碎从原理讲到实操再讲我整理项目代码时踩过的坑尽量让不同背景的人都能从中拿到自己能用的东西。1. 智算网络的两个方向到底在争什么1.1 Scale-out的经典思路Scale-out翻译成大白话就是“横向扩展”一个GPU服务器网卡带宽不够用那我就多接几台服务器通过交换机把它们连成一个大规模的网络集群。计算节点之间的通信走的是以太网或者InfiniBand数据从一个节点出发经过TOR交换机再往上走Spine交换机一层一层转发最终到达目的节点。这种架构是过去十年数据中心的主流大家熟知的CLOS拓扑、Spine-Leaf架构就是Scale-out的典型代表。它的核心优势是规模上限高只要交换机端口够多、光模块够用几千张GPU卡可以随便组。而且故障域相对独立一台交换机挂了受影响的范围可以被控制住。在传统云业务里这种横向扩展的方式够用很久因为业务流量模式是“南北向”加少量“东西向”对时延和带宽的要求远没有大模型训练那么苛刻。但Scale-out有一个天然的结构性瓶颈远端内存访问的时延和带宽受限于网络链路层的能力永远不可能比本地内存或者机内互联更快。哪怕你用再好的400G网卡数据出网卡、过线缆、进交换机、查路由表、再出门这个链路本身就决定了时延的下限。大模型训练恰好是一个对通信极其敏感的场景AllReduce、AllGather这些集合通信操作动不动就同步几千张卡的梯度数据通信时间稍微拉长GPU就只能在那边空转等数据算力利用率直线下降。1.2 Scale-up为什么重新翻红Scale-up的思路刚好反过来我不追求把集群铺得很大而是在一个尽可能小的物理空间里把GPU之间的互联带宽做到极致。GPU之间不通过网络交换机而是通过高速互联总线把几十张卡像一个整体一样连起来。这个方向的代表就是NVLink、NVSwitch还有各种新兴的Scale-up互联协议比如英伟达的NVLink Domain或者UALink这种开放标准。为什么Scale-up这两年重新变得这么重要因为大模型的单集群规模越来越大而集合通信的时间占比在同步训练中一直在涨。打个比方你让一百个人协作搬砖Scale-out是每个人站在自己的工位上靠中间的传送带传递砖块传送带再快也有上限Scale-up是直接把一百个人围成一个圈旁边的人直接递给你中间省掉了很多倒手环节。放在GPU训练里省掉的就是PCIe总线、网卡、交换机这些“倒手”环节。Scale-up的价值不只是时延低更重要的是它改变了通信的软件模型。当GPU之间的互联带宽接近内存带宽量级通信库就不再需要做大量的数据切分和打包优化数据可以更细粒度地传输训练框架可以把通信和计算重叠得更好。当然这种方案的劣势也很明显互联距离短、规模上限受限于物理机框或者机柜扩展性远不如Scale-out。比如说单个NVLink Domain一般也就几十张卡再往上走还得靠Scale-out网络把多个Domain连起来。所以现实情况不是二选一而是两层架构叠加Scale-up管域内Scale-out管域间。这也是现在主流智算集群的标准做法。2. 项目视角下的Scale-out与Scale-up选型2.1 时延、带宽、利用率三个维度算一笔账我在实际做项目的时候最喜欢用一个很简单的模型来判断该侧重哪个方向。大模型训练中一次典型的同步操作通信时间大致可以拆成三部分数据从GPU显存取出来、数据经过互联链路传输、数据到达目的GPU写入显存。Scale-out方案优化的是第二部分但它能做的优化最多只是让链路不丢包、不排队减小排队时延而Scale-up方案能把第二部分的物理距离缩短到极致同时把第一部分和第三部分里PCIe带来的额外开销也省掉。举个例子同样做一次跨节点AllReduce如果用400G RoCE网络单次通信的往返时延大概在1.5到3微秒的量级还要考虑拥塞导致的抖动如果走NVLink时延可以压到几百纳秒而且几乎没有抖动。这个差距在单次操作里你看不太出来但当集合通信次数达到几万次、几十万次累计的时间差距就会演变成训练吞吐量的显著差异。带宽账就更好算了。NVLink 5.0单条链路的双向带宽是1.8TB/s一张GPU卡通常有多条链路总带宽可以到7.2TB/s甚至更高。而400G网卡的理论带宽也就是50GB/s左右哪怕是800G网卡也就100GB/s。一个数量级以上的差距直接导致同等数据量下Scale-up方案传输时间要短得多。所以从单纯的性能账来看Scale-up占绝对优势。但性能只是指标之一利用率才是最终决定训练成本的关键。模型并行度越高通信频率越高对Scale-up的需求就越迫切。如果一个集群的GPU利用率只有40%和另一个集群的80%对比哪怕前者硬件单价便宜30%总成本反而是更高的。我拆过很多失败的项目不少就是栽在这个地方光看网卡速率和交换机端口数没算通信占比和实际利用率最后训练跑起来才发现瓶颈在网络。2.2 组网设计与硬件落地的取舍确定了Scale-up和Scale-out结合的原则之后工程上还要具体回答几个问题一个Scale-up域放多少张卡、跨域怎么连、网络收敛比怎么设计。这里没有一个放之四海而皆准的答案但有一条经验可以分享Scale-up域的规模尽量和模型并行策略匹配。比如你要训练一个需要8路张量并行的模型那么一个Scale-up域至少应该能容纳8张卡最好能容纳16张甚至32张这样张量并行所需的通信全部发生在域内域间的网络只承担数据并行和流水线并行的通信量。这一条决定了网络不会成为主瓶颈。域间网络的设计一般走的是Spine-Leaf加RoCE收敛比建议做成1:1不要贪图省钱做成1:2或者1:4。大模型训练的流量模型是典型的“多打一”模式很容易出现多个节点同时往一个节点灌数据的情况如果收敛比不够拥塞几乎是必然的。RoCE网络对丢包极其敏感一丢包就触发重传重传会放大拥塞最后就是雪崩式性能下降。我在实践中见过太多项目为了省几个交换机端口把收敛比降到1:2结果性能直接腰斩省的钱还不够补GPU空闲的损失。存储网络和计算网络建议物理隔离。很多人觉得现在存储也走RDMA和计算网络共用一套设备可以省成本实际上混跑的时候存储流量很容易干扰训练流量的拥塞控制。我自己踩过这个坑之后就坚持一个原则智算集群里训练网络、存储网络、管理网络各走各的哪怕规模小一点也要物理隔离。这个经验在多个项目里验证过省事且稳定。3. 配套代码工程网络拓扑配置与项目结构管理3.1 配置管理的代码化组织智算网络的复杂度一旦上来如果再靠手工登录交换机敲命令来维护配置早晚要出事。我在项目里坚持把网络配置全部代码化用Git做版本管理。这个决定帮我避免了好几次“配置漂移”引发的故障。什么叫配置漂移就是你有一台交换机的手动配置和别的机器不一致排查起来极其痛苦。做法其实不复杂把交换机的配置、拓扑关系、IP规划、路由策略全部组织成一个独立的配置仓库。拓扑相关的配置用YAML描述例如topology: spine: - name: spine-01 model: CE8861 peers: [leaf-01, leaf-02, leaf-03, leaf-04] leaf: - name: leaf-01 model: CE8851 servers: [gpu-server-01, gpu-server-02] uplinks: [spine-01, spine-02]然后通过自动化脚本把这些YAML渲染成各厂商的CLI配置片段或者直接通过NetConf/gRPC推送到设备上。这个方案的优点很明显配置有历史记录回滚只需一条命令新增一台设备改YAML就行不用再复制粘贴整段配置。我见过太多团队还在拿Excel表格管理IP和拓扑换一个人维护就成了灾难。3.2 模块边界拆分与依赖方向配置代码化只是第一步真正让项目长期好维护的是代码结构的模块化。我这次重新整理项目的时候把整个系统按边界拆成了三层底层是网络设备适配层负责对接不同厂商的设备接口中间是网络服务层包含拓扑管理、配置下发、状态采集上层是业务接入层给训练平台提供API。这里有个特别重要的工程原则依赖方向必须从上往下不允许底层反向依赖上层。比如设备适配层只能对外暴露统一接口不能感知上层业务逻辑。我在整理代码时发现原项目里有些包之间互相引用改一个接口导致七八个文件联动修改就是因为当初没有控制依赖方向。拆模块的意义并不是单纯让代码好看而是让多人协作时可以并行开发不至于天天冲突。这让我联想到网上经常有人问“如何在Go项目里引入其他目录的代码”。其实答案很简单只要你项目的模块边界清晰不同目录对应不同包import路径引入就行。真正让人头疼的从来不是技术细节而是模块之间职责不清导致你不敢随意import怕引入循环依赖。我在重构的时候最常用的一招是画一张依赖关系图找出双向依赖的模块然后通过接口抽取或者中间层隔离来打破循环。做完这一步项目复杂度肉眼可见地降了下来。4. 常见故障与排查经验4.1 交换机哈希不均导致带宽打不满先讲一个很经典的问题明明链路带宽够但训练速度就是上不去。排查到最后发现是交换机的ECMP哈希不均。ECMP等价多路径是为了让流量在多条链路上均匀分布但传统哈希算法基于五元组而RDMA流量很多都是大流量流几条大流如果哈希到同一条链路上就会出现一条链路跑满、其他链路空闲的尴尬局面。解决方向有两个。一是换用更高级的哈希算法比如基于流的熵哈希让哈希结果更均匀二是故意对网络流量做打散比如在RoCE场景下调整哈希因子把更多的报文头字段纳入计算。实际操作中我用过最有效的手段是逐条流打标签并查看设备侧哈希结果找出大流在硬件层面的分布规律再针对性地调整哈希种子。这个问题的排查过程比较磨人但定位到之后解决不难难的是很多人一开始根本不会往这个方向想。4.2 RoCE拥塞控制参数调优RoCE网络对PFC优先级流控和ECN显式拥塞通知的依赖非常高。参数配得不合适要么出现PFC风暴要么出现ECN标记过晚导致队列堆积。我常用的调优策略是先弄清业务流量模型再配置缓冲区和阈值。ECN的配置核心是水线阈值设太低了正常流量就被频繁标记导致发送端降速吞吐反而上不去阈值设太高了拥塞已经发生才标记等于没做。我一般是把ECN阈值设在端口缓冲区深度的40%到60%之间再根据实际流量模型做微调。PFC那边要特别注意不要全局开启只给RoCE优先级队列开并设置好死锁检测机制。这个经验是拿几次事故换来的有一次就因为PFC配置波及了普通TCP流量结果存储和业务网络一起卡死复盘的时候发现是优先级队列划分的锅跟拥塞本身没什么关系。4.3 代码版本回退与依赖混乱的坑网络配置和代码版本管理表面上看起来是两件事实际上在故障场景里是绑在一起的。我遇到过不止一次某个网络策略被推到生产环境之后发现有问题想回退结果因为配置没有纳入版本管理根本不知道上一个稳定版本长什么样只能靠回忆这是最恐怖的情况。所以我强烈建议把网络配置和项目代码放在同一套CI体系里管理。每次变更走MR合并请求流程有评审、有记录回退时直接恢复到上一个tag。这套流程在普通软件开发里司空见惯但在网络工程领域能做到的团队真的不多。另外关于“框架层代码放到私库其他模块依赖Jar包”这类问题我的体会是框架层代码确实应该独立成库通过版本号控制发布而不是让各个业务模块直接把框架代码拷贝一份进自己的工程。因为一旦有安全漏洞或者bug要修复只有一份代码源才能保证所有依赖方同步更新。如果每个模块都自己维护一份拷贝那就是一场灾难你根本不知道谁用的哪个版本、哪个有漏洞。5. 运维监控别等训练挂了才去查网络智能网络运维的核心是把网络的实时状态变成训练平台可以感知的数据。我们在项目里给每个GPU服务器部署了RDMA状态采集器定期抓取网卡状态、丢包计数、ECN标记数、PFC暂停帧计数上报到Prometheus。这里有一个特别实用的技巧不要只监控平均值要监控最大值和分位数。RDMA流量是典型的脉冲型流量平均带宽看着不高但某个瞬间可能猛冲到线速如果只看平均值阈值得不到反映。我用99分位数来配置告警配合Grafana看板实时观察拥塞信号效果比原先好用太多。另外端口错误计数也不能忽视。CRC错误、链路震荡计数这些指标往往在真正丢包之前就有了征兆。我在项目里总结了几个关键告警指标做成了一张速查表适合初次搭建监控体系的团队做参考告警指标阈值建议说明网卡丢包率 0.001%超过这个值基本就是网络问题需立刻排查PFC暂停帧计数持续上涨说明PFC频繁触发存在拥塞或配置不合理ECN标记率 1%标记过多说明网络水线设置过深或业务流量异常端口CRC错误 0物理链路问题考虑光模块或线缆故障交换机CPU利用率 60%控制面异常可能遭遇特殊流量攻击或协议震荡这套指标跑下来我们提前发现了两个隐患都是还没影响到训练就已经在监控里露出苗头比如某个端口CRC错误持续增长换掉一条光模块就好了。这种“把故障消灭在发生前”的体验比事后救火舒服太多。6. 把项目代码变成团队资产代码整理到这个程度接下来还要做一件事就是把代码和文档一起发布成一个内部工具集。我之前在重构过程中犯过一个错误只顾着把代码整理得清清楚楚却没有处理好模块与模块之间的版本依赖关系。结果同事拉下来代码一编译报错一堆就是因为每个模块的版本依赖没有写明大家各用各的简直是在拼运气。后来我统一用Go Module和Maven依赖管理工具锁定了所有依赖版本并写了一个自动化的版本一致性检查脚本。每次提交代码CI都会运行一次检查确保模块之间的版本匹配。这个流程帮我摆脱了“每次编译都像赌博”的困境。关于git push上传代码这种基础操作我通常建议团队用“主干开发 短期分支”的模式避免长期分支导致的大规模合并冲突。我在重构项目结构的时候就是先把所有调整放在一个临时分支里验证通过后再合回主干整个过程靠代码审查兜底确保不会把网络配置的变更和代码结构的变更混在一次提交里。此外把框架层代码放到私库还有另一个好处其他模块依赖的Jar包或者Module都从私库里统一拉取。这样写代码的时候大家都在同一个版本的框架上开发不会被底层更新打断。虽然这个做法的前期投入是搭一个私库和配套CI流程但后期省下的维护成本真的很高。回到智算网络这个大话题上我的体会是Scale-out和Scale-up不是对立关系它们是同一个目标——让GPU集群跑得更快、更稳——的两个手段。真正决定项目成败的不只是在纸面上选了哪个方案而是选完之后配套的工程化管理是否跟得上。在我见过的大大小小的项目里硬件和拓扑本身很少拉开决定性差距拉开差距的恰恰是配置管理、代码组织、监控运维这些看起来不太性感的工作。希望这篇分享能让准备入坑智算网络的朋友从一开始就把这些地基打好。本文还有配套的精品资源点击获取