上周深夜,隔壁组的老王突然在群里甩了条消息:“线上推理服务P99延迟突然飙到200ms,流量也没涨,谁碰过类似问题?” 我们几个蹲在机房,对着监控面板上那根刺眼的长尾曲线发愁。常规排查走了一圈:应用日志没异常,CPU/内存水位正常,网络带宽占用不到30%。直到我用ethtool -S扫了一眼网卡统计,发现rx_missed_errorsrx_no_buffer_count这两个计数器正在悄悄往上跳——问题出在网卡和数据包处理路径上。

这个场景让我想起五年前第一次被网卡性能支配的恐惧。那时候我们还在用传统网卡,所有数据包都得经过内核协议栈,CPU大半时间花在搬运数据、处理中断和上下文切换上。如今AI集群动辄万卡互联,网络栈那点优化早已不够用。今天我们就聊聊那些正在改变游戏规则的硬件:DPU、智能网卡和可编程交换芯片。

传统网卡的瓶颈:你的CPU正在搬砖

先看段我们早年写的驱动收包逻辑(伪代码示意):

// 传统NAPI收包循环(简化版)
while (!budget_exhausted) {
    // 从网卡DMA环取描述符
    desc = rx_ring[ring_index];
    // 分配skb(这里踩过坑:高频分配碎片化内存直接搞崩kmem)
    skb = netdev_alloc_skb(dev, len);
    // DMA同步到CPU缓存(这步开销比想象中大)
    dma_sync_single_for_cpu(dev->dma_handle);
    // 送协议栈(后面还有软中断、内存拷贝连环套)
    netif_receive_skb(skb);
}

问题在哪?CPU全程在干体力活:分配内存、同步缓存、处理中断、搬运数据。当AI训练需要100Gbps甚至更高带宽时,这套流程直接让CPU跪了——你买的是计算芯片,结果它一半时间在当搬运工。

智能网卡:让网卡自己干活

智能网卡(SmartNIC)的核心思想很直接:把网络协议栈卸载到网卡硬件上。现在的智能网卡通常集成了多核ARM处理器、硬件加速引擎和可编程流水线。比如NVIDIA的BlueField系列,一张卡上既有ConnectX网卡芯片,还有最多16个ARM核。

我们去年在视频转码集群试过用智能网卡做SSL卸载:

// 原本在CPU上做的TLS解密
ssl_ctx = SSL_new(ctx);
SSL_read(ssl_ctx, encrypted_data, len); // CPU算到冒烟

// 卸载到智能网卡后
// 配置流表规则(伪代码)
nic_flow_rule = {
    .match = {.dst_port = 443},
    .action = ACTION_CRYPTO_DECRYPT,
    .key_id = ssl_key_handle  // 密钥提前注入网卡安全区
};
// 后续443端口流量自动在网卡解密
// CPU看到的是明文数据

实测单卡能卸载30万TPS的TLS 1.3握手,CPU负载从80%降到12%。但别高兴太早——智能网卡的ARM核性能有限,复杂逻辑跑不动,而且开发得用厂商特定的SDK,调试得靠JTAG和芯片厂支持,周期以月计。

DPU:不只是智能网卡

DPU(Data Processing Unit)可以理解为智能网卡的进化版。它更像是一台“服务器中的服务器”,除了网络卸载,还能干存储虚拟化、安全策略、资源调度这些活。比如AMD的Pensando(现在归AMD了)DPU,我们在云平台用它做分布式防火墙:

// 传统方案:所有流量送到中央防火墙实例
// 东西向流量也得绕路,延迟爆炸

// DPU方案:每台宿主机本地策略执行
dpu_policy = {
    .priority = 10,
    .match = {.src_vm = "train-node-*", .dst_vm = "redis-*"},
    .action = ACTION_CHECK_ACL(redis_acl)  // 策略编译下推到DPU
};
// 策略命中后,数据包在进出VM时就被DPU拦截/放行
// 延迟从毫秒级降到微秒级

DPU的强项是能处理“有状态”的逻辑。我们做过测试,在RoCEv2(RDMA over Converged Ethernet)场景下,用DPU维护连接状态、重传和拥塞控制,比纯软件方案吞吐高40%,尾延迟降低60%。但DPU的编程模型更复杂,你得理解它的流水线架构,有时候为了适配硬件特性,算法得重写。

可编程交换芯片:网络里的FPGA

如果说DPU是“服务器边的协处理器”,可编程交换芯片就是“网络里的FPGA”。这玩意最神奇的地方在于:它能以线速(wire-speed)处理数据包,同时还能跑你自定义的逻辑。我们用的Barefoot Tofino芯片,写P4语言代码就像在定义网络协议:

// 自定义AI训练流量优先级标记(P4片段)
header custom_priority {
    bit<3> job_type;  // 0=推理,1=训练,2=参数同步
    bit<8> job_id;
}

parser中:
if (hdr.ethernet.etherType == 0x8915) {  // 自定义以太网类型
    extract(hdr.custom_priority);  // 解析我们加的头部
}

ingress流水线:
action set_queue_by_job_type() {
    if (hdr.custom_priority.job_type == 1) {
        meta.queue_id = 7;  // 训练流量进最高优先级队列
    }
}
// 后面还有调度器、拥塞控制逻辑...

我们在超算集群用这招区分参数同步流量和普通数据读取。参数同步包走低延迟队列,遇到拥塞时主动降普通数据包的速率。整套逻辑在交换芯片上跑,零CPU开销。但P4开发完全是另一个世界——没有传统意义上的“CPU”,你得用状态机思维,调试靠模拟器和芯片的带外管理接口。

选型与落地:别被厂商PPT带偏

这几年各种硬件眼花缭乱,我的经验是:

第一,先明确瓶颈在哪。 如果只是带宽不够,普通RDMA网卡可能就够了;如果需要隔离租户、加解密,看智能网卡;如果涉及复杂网络逻辑和跨节点状态同步,再考虑DPU或可编程交换。我们吃过亏,为了“技术先进性”上DPU,结果80%功能用不上,开发成本翻了三倍。

第二,开发环境评估要务实。 某厂商的DPU开发套件号称“全功能”,实际缺本地调试器,每次编译镜像得传回厂商服务器,等两小时。后来我们自己在FPGA上搭了仿真环境,才把开发效率提上来。

第三,混合架构可能是现实选择。 我们现在生产环境是分层方案:可编程交换芯片处理网络层调度,DPU做节点级安全和存储卸载,智能网卡负责基础协议卸载。没有银弹,只有合适组合。

最后留个坑位提醒: 这些硬件大多需要特定内核版本和驱动。我们去年升级内核,某个DPU驱动不兼容,回滚了三次。现在所有硬件驱动都单独维护,绝不跟系统内核绑死。

老王那个问题最后怎么解决的?我们把部分推理服务的网络队列从内核态移到用户态DPDK,结合网卡的Flow Steering功能,让关键流量绕过复杂协议栈。P99延迟从200ms降回12ms。硬件卸载不是魔法,它只是把CPU的负担转移到了更合适的地方——而知道“哪里更合适”,正是工程师的价值所在。

下次聊聊这些硬件怎么跟AI框架配合,比如TensorFlow的PluggableDevice机制怎么挂接DPU。今晚先到这儿,机房空调太冷,我得去接杯热水。

Logo

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

更多推荐