从一次诡异的丢包开始

上周调一个多机训练任务,发现梯度同步时间比预期长了三倍。netstat 看吞吐正常,nvidia-smi 显存占用也平稳,但 nccl 日志里总在特定节点间出现周期性的延迟尖峰。折腾半天,最后用 ethtool 看了眼网卡中断绑定——好家伙,两个 100G 网卡的 IRQ 被挤在同一个 CPU 核上,隔壁核却闲着。手动绑开之后,延迟直接掉回正常范围。

这事让我琢磨:现在 AI 集群里,计算是异构的(CPU、GPU、NPU),存储是异构的(NVMe、SSD、内存池),可网络这块,我们好像还习惯性地把它当成“一堆同质网卡+交换机”的透明管道。但现实是,网络早就不是那个“傻快”的底层了。


异构网络:不只是多几种网卡

现在稍微像样点的 AI 集群,可能同时跑着以太网、InfiniBand、甚至自家定制的互联方案。异构网络不是简单堆硬件,而是让不同的网络干它最擅长的事

比如我们最近搭的一个系统:

  • IB 用于 GPU 间梯度同步(高带宽、低延迟)
  • 以太网用于管理通信、数据加载(成本低、兼容性好)
  • 自定义的 RDMA 链路专做 checkpoint 保存(大块连续写优化)
# 以前粗暴地走默认路由
# export NCCL_SOCKET_IFNAME=eth0

# 现在得分流
export NCCL_IB_HCA=mlx5_0:1    # 指定IB卡做集合通信
export DATA_LOADER_NET=eth0     # 数据走以太网

这里踩过坑:别让不同协议的网卡在同一个子网里抢路由,内核路由表会“精神分裂”。我们后来直接上了策略路由,按进程名和端口号分流。

异构网络的管理复杂度是指数上升的,你得有个统一的视图。我们内部写了个小工具,把 ip linkibstatdcgmi 的输出揉在一起,再配上 bpftrace 抓的队列深度,才算看清数据到底在哪条道上堵着。


在网计算:把活下放到交换机

第一次听说“在网计算”(In-Network Computing)时,我心想这不就是 offload 换个名字嘛。直到亲眼见到一个 AllReduce 操作在交换机里完成,GPU 直接读结果,省掉了多跳转发和多次内存拷贝——性能提升 40%,而且 GPU 不用频繁被打断。

现在的智能网卡(DPU/IPU)和可编程交换机(P4/Tofino)能干的活越来越多:

  • 集合通信(NCCL 部分操作可以直接在交换机里做归约)
  • 负载均衡(不是简单的 ECMP,能感知 GPU 的负载状态)
  • 数据预处理(在数据到达 GPU 前完成格式转换、过滤)
// 伪代码示意:交换机里做梯度求平均
// 实际是P4或FPGA代码,这里只是逻辑
void reduce_in_switch(Packet pkt) {
    if (pkt.type == GRADIENT) {
        local_sum += pkt.data;
        counter++;
        if (counter == total_workers) {
            // 直接广播结果给所有节点
            broadcast(local_sum / counter);
        }
    }
}

别急着把所有计算都往网里塞。我们的经验是:数据移动成本超过计算成本时,才值得下放。而且调试极其痛苦——你得同时懂分布式训练、网络协议和硬件描述语言。我们团队现在备着一台退役的可编程交换机,专门用来复现问题,不然线上断一次就是几十个 GPU 闲着。


AI for Network:让网络自己调自己

以前调网络参数(TCP 窗口、缓冲大小、QoS)靠的是“老法师”经验加反复压测。现在我们可以换个思路:用 AI 来优化网络本身。

我们在两个场景里试过:

  1. 拥塞控制预测:用 LSTM 预测下一时刻的流量模式,提前调整 ECN 阈值
  2. 拓扑感知调度:GNN 模型分析集群拓扑,把通信密集的任务调度到物理距离更近的节点
# 简化版示例:用流量历史预测缓冲大小
def tune_buffer(model, history):
    # 这里原来是一堆启发式规则
    # if delay > threshold and loss_rate < 0.01:
    #     buffer *= 1.2
    # ...
    
    # 现在让模型决定
    predicted_load = model.predict(history[-10:])
    new_buffer = policy_network(predicted_load)
    
    # 执行调整(风险动作,要加回滚)
    os.system(f"sysctl -w net.core.rmem_max={new_buffer}")

这事的难点不在模型,而在数据收集和动作安全。网络参数调错了,可能直接导致集群失联。我们现在的做法是“影子模式”——AI 给出建议,但先不执行,和人工规则的结果对比,稳定跑一周才敢真上线。


个人经验:别追新,但要保持敏感

  1. 异构网络:先从物理隔离开始,别急着玩虚拟化。用不同颜色的光纤区分网络类型,物理隔离最可靠。等链路稳定了,再考虑用 VLAN 或 VRF 做逻辑隔离。

  2. 在网计算:从“监控 offload”开始入手。先把网卡的统计信息(丢包、延迟、队列深度)接入你的监控系统,感受下数据在哪流动。然后再尝试一两个最耗时的操作(比如 AllReduce)下放。

  3. AI for Network:从“辅助分析”开始,别直接控制。先把 AI 当成一个高级分析师,让它告诉你“为什么现在慢了”,而不是“现在该调哪个参数”。等它的解释和你的经验对得上 90% 以上,再考虑给它部分权限。

最后说个反直觉的体会:网络越智能,底层监控就要越扎实。我们最近把所有关键链路的原始流量镜像出来(采样 1%),存到廉价 SSD 上,出了问题能回溯到具体包的走向。这招救了不止一次——智能系统出了问题,你得有能力看到它“犯傻”的每一步。


网络正在从“连接计算单元的管道”变成“分布式系统的神经系统”。它的复杂度会越来越高,但带来的可能性也让人兴奋。保持动手,保持怀疑,好的系统是调出来的,不是设计出来的。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐