news 2026/9/8 16:32:18

小消息拖慢大模型推理?分布式通信延迟的排查与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
小消息拖慢大模型推理?分布式通信延迟的排查与优化

一次只有几百字节的数据传输,平时在谁眼里都是“洒洒水”。但在做大模型推理服务压测时,我经常看到这样的情况:GPU 利用率看着不低,网络带宽也远没跑满,可端到端的 token 延迟就是压不下去,翻遍 codebase 最后发现,罪魁祸首居然是那些不起眼的小消息。

这不是段子。在做过多机多卡的大模型推理后,你会越来越确认一个反直觉的事实:分布式推理的瓶颈往往不在带宽,而在那些几百字节级别的通信上。这类通信恰恰藏在 pipeline parallel 的 decode 阶段、MoE 模型的 all-to-all 路由里,消息小,次数多,延迟高,谁也躲不掉。今天这篇就重点拆一下:这些小消息为什么能拖慢大模型推理,以及怎么把它揪出来、压下去。适合正在跑分布式推理、对 token 延迟敏感的工程师参考。

1. 一张图看清大模型推理里的通信到底长啥样

1.1 推理服务不只是“显卡算力”的事

很多人对分布式推理的第一印象是“把模型拆开,塞进多张显卡,然后算”。这句话没错,但真正动手之后你会发现,推理服务的性能有两个维度:一个是纯计算时间,也就是 GPU kernel 的耗时;另一个是数据在卡与卡、机与机之间搬运的时间。后者往往被低估,尤其是消息很小时。

大模型推理里常见的并行拆法就那几种:

  • Tensor Parallel(TP,张量并行):把一层里的矩阵按行或按列切开,多张卡各算一部分,最后再做 AllReduce 或 AllGather。TP 的通信量通常很大,因为它发生在每一个 Transformer 层的内部,计算一次就要通信一次。好消息是 TP 一般部署在同一台机器里,走 NVLink,固定延迟很低。
  • Pipeline Parallel(PP,流水线并行):按层来切,GPU 0 负责前几层,GPU 1 负责后几层。前一个 stage 的输出激活值(activation)要作为后一个 stage 的输入,所以两个 stage 之间要不停地 send/recv。推理场景下,如果每个请求的 batch 很小,那这条消息可能就只有几百字节到几 KB。
  • Expert Parallel(EP,专家并行):主要出现在 MoE(Mixture of Experts)架构里。不同的 expert 放在不同卡上,每个 token 要路由到目标 expert 所在的卡,这时需要做 all-to-all 通信。消息内容是这个 token 的 hidden state,单条不大,但次数极其频繁。
  • Data Parallel(DP,数据并行):每张卡都有一份完整模型,各自处理不同请求,一般只在需要时做梯度同步(训练)或 KV cache 管理(推理),这里不展开。

你会发现,真正会制造“几百字节小消息”的主要是 PP 的 stage 间传输,以及 EP 的 token 路由。这些消息的特点是:单条尺寸特别小,但每条都卡在关键路径上。

1.2 为什么推理和训练对小消息的态度完全不同

同样是分布式通信,训练和推理对“小消息”的容忍度是天差地别的。

训练阶段,我们通常用比较大的 batch size,一次迭代就攒了成百上千个样本。PP 在训练时传输的也是多个 micro-batch 拼接起来的激活值,消息动辄几 MB 甚至几十 MB;即使单条带不了多少数据,也可以靠大块传输把带宽打满,固定延迟被摊薄了。而且训练对吞吐的敏感度远高于对延迟的敏感度,一个 step 慢了几十微秒,大家并不在意。

推理阶段恰恰相反。在线推理服务里,用户一次请求往往只有一个 prompt,生成时 batch size 可能只有几个 token 或者几十个 token。此时 PP stage 之间传输的就是这一个 batch 的中间激活值,你看一下模型维度就能算出来:如果 hidden size 是 4096,精度是 FP16,一个 token 的 hidden state 也就 8KB;batch size 为 1 时,500B 的数据再正常不过。如果是更窄的模型,几百字节也完全可能。

更麻烦的是,推理 decode 阶段是逐 token 生成的。打个比方:你问模型“今天天气怎么样”,真正回答的时候,模型每吐一个 token,就要把新的向量从第一层一直传到最后一层;每一层之间如果跨卡,就会触发一次通信。吐 100 个 token,就是 100 次小消息。训练可以靠流水线把通信和计算重叠起来,推理的 token-by-token 依赖却很难做到完全隐藏,延迟必须实打实地算进端到端体验里。

所以我一直觉得,看推理性能光是盯着 GPU 利用率是远远不够的。通信延迟哪怕每次只多 0.1ms,100 个 token 下来就是 10ms,足以让一个“看起来没问题”的推理服务在延迟上翻车。

2. 几百字节的消息,时间到底花在哪了

2.1 延迟模型:消息再小,固定开销一分不少

通信延迟有个很经典的模型,做分布式系统的人应该都熟:T = α + β × size。

其中 α 是固定开销,包括发起通信、同步、中断处理、协议栈处理等等,只要这条通信发起,不管传 1 字节还是 1MB,这笔钱都必须花;β 是每字节的传输成本,通常由带宽决定;size 就是消息大小。当 size 只有几百字节时,β × size 几乎可以忽略,T ≈ α。也就是说,几百字节的消息,延迟基本等于“通信一次”的固定开销。

这个模型解释了很多看起来很诡异的现场。比如你用 iperf 测网卡,带宽跑到 100Gbps 很轻松,于是你理所当然地认为“跨机通信很快”;但等推理服务一上线,发现一次跨机 send/recv 要 100 多微秒,你立刻懵了。原因就是:iperf 测的是大块数据流的稳态带宽,而你的推理服务发的是几百字节的小包,根本填不满 100Gbps 的“水管”。

还有一个概念叫带宽延迟积(BDP,Bandwidth Delay Product)。简单说就是:链路上能同时“在飞”的数据量 = 带宽 × 往返延迟。假设网卡带宽 100Gbps,跨机往返延迟 100μs,BDP 大约是 1.25MB。也就是说,要在这种链路上跑满带宽,你每次至少要发出 1MB 级别的数据。几百字节的小消息,哪怕发得再快,也只占了链路容量的极小一部分。

所以“明明带宽那么大,为什么还是慢”的答案很简单:你遇到的问题根本不是带宽问题,而是延迟问题。

2.2 链路全景:从 GPU kernel 到对端 kernel,中间有六层坎

一次跨卡的小消息通信,真正走过的路径远比“网卡发出去、对方收回来”复杂。我把它拆成六个环节,每段都有固定开销:

  1. GPU kernel 内部的数据准备。通信之前,数据通常要从计算 kernel 的输出 buffer 里拷贝到通信 buffer。如果是跨 GPU 通信,还需要通过 CUDA 的 event/stream 做同步,让通信操作排在计算完成之后。这个同步本身有开销,通常在微秒级。
  2. 通信原语的启动开销。无论是 NCCL 还是自定义的 send/recv,都有一个“发起”的过程。NCCL 在 NVIDIA 驱动里有一个常驻的控制线程,kernel 启动后要发指令给它,驱动调度也要花时间。不同的通信库实现差别很大,有的快有的慢,但启动开销怎么都省不了。
  3. CPU 与内核态处理。跨机通信时,如果没有走 RDMA,数据要从 GPU 显存拷贝到 CPU 内存,再交给内核协议栈处理;即使走了 RDMA,也需要建立 QP(Queue Pair)、注册内存区域(MR,Memory Region),这些都有固定成本。
  4. 网络传输与交换。网卡把数据包发出去之后,要经过交换机、路由器等网络设备。每个设备都有处理时延。跨机场景下,这部分至少是几微秒到几十微秒。
  5. 对端接收与中断处理。对端网卡收到数据后,要触发中断或者忙轮询(busy polling),通知 CPU,再把数据搬到目标位置。如果用的是 GPU Direct RDMA,可以直接进显存;否则还得经过 CPU 中转。
  6. 同步等待。通信是双向的。send/recv 模型的接收方必须等数据到齐才能继续计算;AllReduce 等集合通信则要等所有参与节点都到齐才能完成。任何一张慢卡都会拖慢整条链路。

把这几段耗时加起来,你就能理解为什么一次几百字节的小通信要花几十甚至上百微秒:不是数据本身“跑得慢”,而是每一层“过闸”的固定开销都不小,消息越小,固定开销占比越高。

2.3 被忽略的“同步等待”:谁说小消息快就要立刻交付

还有一个特别容易被忽略的问题:小消息本身传输快,但它在系统里未必是“优先通道”。

举个例子。假设你的推理部署用的是单机 8 卡,PP 4 段、TP 2 路。TP 的 AllReduce 在卡之间频繁发生,通信量特别大,往往会把 NVLink 的通道占得比较满。PP 的 stage 间小消息如果排在同一个时间片里,就得等 TP 的大量通信清空通道后才轮到。这种“通信排队”的现象,在小消息和大消息混跑时尤其明显。

跨机场景更严重。如果集群的调度没有做流量隔离,一个节点的推理服务和另一个节点的训练任务共享同一张网卡或同一个交换机,那么小消息的延迟会受到旁观流量的干扰,出现明显抖动。这也是为什么我们在压测时会看到同一个请求,第一次延迟 50ms,第二次 80ms,第三次又回到 55ms,大概率不是模型算力波动,而是底层网络排队不稳定。

另外要注意一点:分布式推理中的 PP 相邻 stage 之间是严格的串行依赖。Stage A 的 output 必须到达 Stage B,Stage B 才能开始计算。通信这一步根本藏不住,即使你在代码里把 send 写成了异步,下一层 stage 该等还是得等。同步等待的开销,最终折算到了端到端延迟里。

3. 动手测量:一次真实的小消息通信耗时拆解

3.1 先做对照实验:NCCL sendrecv 与 allreduce 小消息基准

讲再多理论,不如直接上数据。实际排查时,我第一步永远是跑通信基准测试,把“理论延迟”先测出来,再跟推理服务的实际现象做对照。

NCCL 官方提供了nccl-tests,里面有两个工具特别有用:sendrecv测点对点通信延迟,all_reduce测集合通信延迟。跑的时候要特意指定小消息尺寸,命令大致是这样:

# 测 512B 消息的 send/recv 延迟,跑 100 轮取均值 ./sendrecv_perf -b 512 -e 512 -f 2 -g 1 -n 100 # 测 512B 消息的 allreduce 延迟,4 卡参与 ./all_reduce_perf -b 512 -e 512 -f 2 -g 1 -n 100 # 如果想要直观对比大消息,把 size 拉大到 8MB ./sendrecv_perf -b 8388608 -e 8388608 -f 2 -g 1 -n 100

我自己在一套常见配置下测过一组数据,做一个参考:

通信方式消息大小延迟(约)备注
单机内 NVLink,send/recv512B5-8 μs通过 P2P 直接访问显存,固定开销极小
单机内 NVLink,AllReduce(8卡)512B5-10 μs卡数越多,同步开销越大
跨机 InfiniBand(RDMA),send/recv512B10-20 μs延迟比 NVLink 高一个量级
跨机 100Gbps TCP,send/recv512B50-150 μsCPU 协议栈、中断处理占大头

注意,这些是纯通信延迟,不包含任何计算。你的推理服务实际耗时只会比这个表更差,不会更好。如果压测下来一次 PP stage 间通信耗时超过 200μs,而基准测试只有 15μs,说明一定有什么东西在排队或者处理不当,值得继续挖。

3.2 用 Nsight Systems 抓推理时间线,定位卡在哪一跳

基准测试只能告诉你“通信本身有多快”,没法告诉你“推理服务里的通信为什么慢”。这时候需要上 profiler。NVIDIA 的 Nsight Systems(nsys)是我最常用的工具,它能把 GPU kernel 的时间线、CUDA API 调用、NCCL 通信操作全部打点打出来。

基本用法很简单:

# 抓取推理进程的完整时间线 nsys profile -o trace_output -t cuda,nvtx,osrt --cuda-memory-usage=true --show-output=true python run_inference.py

跑完后用 Nsight Systems GUI 打开trace_output.nsys-rep,重点看这几个东西:

  • NCCL 操作条目:时间线里会有一行一行的NCCL标记,比如ncclKernel_SendncclKernel_RecvncclDevKernel_AllReduce。每个标记的宽度代表了这次通信从发起、执行到完成的时间。
  • GPU kernel 之间的空隙:如果某个 GPU 计算 kernel 结束之后,下一个 kernel 迟迟没有开始,中间正好夹着一个跨机通信,那就是通信延迟在作怪。
  • CPU 侧的等待:切换到一个按 CPU timeline 排序的视图,看 CPU 是否在等待某个cudaStreamSynchronize或 NCCL 的完成事件。如果 CPU 侧长时间阻塞,说明同步策略可能有问题。

我见过一个非常典型的现场:PP stage 0 的 compute kernel 只用了 3ms,但下一次 compute kernel 开始前,时间线上有 230μs 的空窗。对照基准测试,那个空窗就是一次跨机 send/recv 的耗时,其中 data transfer 本身只占很小一部分,剩余的大部分都是通信栈处理、同步、网络排队。

拿到这张时间线,我一般还会配合网卡监控确认排队情况。如果发现通信操作集中在某几个时间点爆发,基本可以判断是网络侧或 NCCL 内部发生了排队。

3.3 一个典型案例:两层 PP 推理如何被 500B 激活拖慢

为了把问题讲具体,我模拟一个真实场景。假设你部署了一个 13B 模型做在线推理,hidden size 4096,不是 MoE,纯 PP 切成 2 个 stage,分别在两台机器上。请求进来后,模型做 decode,每生成一个 token 都要把 hidden state(batch size 为 1,4096 × FP16 = 8KB)从 stage 0 传到 stage 1。

看起来 8KB 也不大,对吧?我们代入延迟模型算一笔账。

假设跨机通信基准延迟是 120μs(走 TCP,100Gbps),那么每生成一个 token,仅这次 stage 间通信就固定增加 120μs,而且增加的是端到端延迟。如果平均生成 200 个 token,总延迟里就有 200 × 120μs = 24ms 消耗在“等通信”上。注意这是纯额外开销,和模型计算完全串行。

如果没加 Continuous Batching,还是每个请求独占一个 batch,那这个 24ms 就是用户白白等掉的。即使批处理可以摊薄,单 token 的响应速度也受影响。

优化思路也很直接:把多个 token 的 hidden state 拼在一起发。假设把 batch size 提到 32,那么一次消息变成 256KB,延迟依然是 120μs 左右(因为还没到带宽瓶颈),但平摊到每个 token 上就只有 3.75μs——相当于单 token 通信成本降了 30 多倍。这就是消息聚合的价值。

如果进一步换 RDMA 网卡,把固定延迟从 120μs 压到 15μs,哪怕不聚合 batch,单 token 的通信成本也只剩 15μs,200 个 token 总共也就 3ms,体验立刻不一样。所以发现小消息是瓶颈之后,方案基本就是两条路:要么让消息变大,要么让单次变快。

4. 踩坑实录:排查“小通信拖慢推理”的实战清单

4.1 五个高频问题与快速定位方法

实际排查中,大家遇到的问题往往大同小异。我把这几年踩过的坑整理成一张速查表,方便你直接对照定位:

症状可能原因排查手段常用对策
单机多卡快,跨机明显变慢NVLink 与 InfiniBand/TCP 延迟差异被低估跑 send/recv 基准对比尽量把 PP 相邻 stage 放在同机;跨机只放 EP 或 DP
网络带宽利用率很低,但延迟超标消息太小,进入“延迟受限区”用 perf/iperf 抓包看报文大小合并小消息,增大单次传输体积
同一请求延迟忽高忽低网络排队、共享网卡或交换受限监控网卡丢包、重传、排队深度做流量隔离,推理业务单独部署
GPU 总有一个 kernel 等待很久才开始通信与计算未重叠,同步等待严重nsys 看 NCCL 标记与 kernel 空窗调整 stream 优先级,提前发起通信
增加并发请求后性能反而更差同步 AllReduce 或静态 batch 导致锁步检查通信原语和调度策略改为异步通信或动态 batching

表格只是帮快速定位。真到了现场,我建议按“先基准、再采样、后压测”三步走:先跑 nccl-tests 摸清硬件延迟下限,再用 nsys 抓一次反例时间线确认瓶颈位置,最后用不同 batch 的压测验证优化是否生效。整个过程大概半小时就能把问题定性。

4.2 三个立竿见影的优化技巧

第一个技巧是合并小消息。在推理框架里,如果多个请求同时处于 decode 阶段,它们在同一时间可能都要跨 PP stage 传激活值。与其每个请求单独发一次 500B 的消息,不如先把所有请求的激活值拼成一个 tensor,再统一发送。这样消息尺寸变大,固定延迟仍然只有一次,单请求平摊的通信成本大幅下降。实现时注意申请一块连续 buffer,按请求顺序填充,接收方再拆开,逻辑并不复杂,收益却很直观。

第二个技巧是拓扑感知放置 stage。跨机通信的延迟通常比单机 NVLink 高 5 到 10 倍,所以部署时优先把有强通信需求的相邻 stage 放在同一台机器里。比如 PP 切成 4 段,两段放机器 A、两段放机器 B,让机器内 PP 通信走 NVLink,机器之间只跑每两段之间的那一次通信。MoE 的 Expert Parallel 也一样,尽量把 all-to-all 通信限制在同一机架甚至同一交换机下,能显著降低固定延迟。

第三个技巧是用异步通信把计算和通信重叠。PP 推理虽然 stage 间有依赖,但在同一 stage 内部,计算和“跟下一 stage 通信”其实可以有一部分重叠。典型的做法是用两个 CUDA stream:一个 stream 跑当前层的计算,另一个 stream 把上一轮算好的结果预先发出去。只要你不依赖通信结果去启动本 stage 的计算,消息就能“藏”在计算后面。Nsight Systems 里能看到通信和计算在时间上真正叠加,而不是排成一串。

4.3 哪些“看起来有用”的做法其实会踩坑

优化路上也有不少反直觉的坑,有些方案表面上合理,实际上会引入新问题。

第一个坑是盲目增大 batch。增大 batch 确实能把小消息合并成大消息,但与此同时,首 token 延迟会变长,因为 prempt 阶段要等更多请求到齐才开始算。如果业务场景对首 token 延迟很敏感,那就不能为了降低通信成本而无限等 batch,需要权衡。通常我在推理框架里会做一个动态 batching:请求到了一定数量就触发,或者设置一个超时上限,不能死等。

第二个坑是同时发送太多条小消息。有些人一看通信有延迟,赶紧在代码里开了 N 个线程,每个线程各自 send。结果不仅没快,反而把网卡的发送队列打满,引发拥塞。正确的做法是维护一个发送队列,把同一时间段、同一目标地址的消息合并成一次 send,线程数控制在个位数以内。

第三个坑是异步通信实现不当。异步 send/recv 如果用不好,很容易出现数据竞争或者顺序错乱。比如 stage 0 连续发了两批数据,stage 1 的接收 buffer 如果复用了,第二批数据可能把第一批覆盖掉。合理的做法是准备多组 buffer,按序交替使用,并且用 CUDA event 或者同步标记保证每个 buffer 都已经被接收完毕之后才能复用。这个坑我踩过很多次,每次都是偶现的内存错乱,排查起来特别费时,最后还是靠加一组 buffer 队列解决。

还有一点必须提醒:如果推理服务里同时存在多条通信路径,一定要给它们设置不同的优先级。比如 PP 的 stage 间通信应该优先于日志上报、指标收集这类次要通信。NCCL 本身不支持传统意义上的优先级,但你可以在框架层面控制发送顺序,或者把高优先级数据走独立的 GPU stream。流量一旦混在一起,低优先级的长传输会把高优先级的短消息堵在后面,性能瞬间变差。

收尾:来自实操现场的小技巧

做分布式推理排障这件事,前期最容易犯的错就是死死盯着 GPU 算力不放,等发现网络瓶颈时,往往已经浪费了大半天。我现在拿到一个新部署的第一反应,永远是先跑一遍基准通信测试,把同机、跨机的固定延迟记在小本本上,后续所有推理延迟的异常都有了一个对照系。

另外想分享一个比较实用的经验:把auto的 NCCL 通信 buffer 大小调一调。小消息通信场景下,NCCL 默认的 buffer 分配策略有时会预留太多显存,导致可用显存缩小、batch 上不去;把它调到一个适中的值,比如 2MB 到 8MB,对大部分推理场景都够用。这个参数是NCCL_BUFFSIZE,不同版本行为略有差异,改完记得重新压测验证。

最后,如果你正准备优化自己的推理服务,我会建议你从最小复现开始:固定一个模型、固定一个请求长度、固定 batch,先跑基准,再改一个变量。不要试图一次性优化十个点,通信延迟这种问题,往往一两个关键改动就能带来十倍收益,但前提是你真的知道瓶颈在哪里。测出来的数据不会骗你,时间线也不会骗你,剩下的就交给耐心。

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

通用 Agent 下沉金融腹地:三条技术路线的分化逻辑与生产环境落地的双重核心边界

【摘要】2026 年 3 家头部厂商集中布局金融 Agent 赛道,形成 Skill 生态、场景优化、独立行业版 3 条技术路线。数据可溯源性与执行权限构成生产环境落地的双重核心边界。结合海内外实践拆解工程路径与 7 步落地 SOP,为金融机构智能体部署提供选型框架与…

作者头像 李华
网站建设 2026/9/8 16:30:43

PID控制深度拆解:从理论到实战的完整整定指南

做自动控制的工程师,几乎没有人和PID打过照面。进实验室第一天,师傅可能就丢给你一段口诀:“先比例、后积分、再微分,比例大了会震荡,积分大了会超调,微分大了会共振。”你用这套口诀调好了好几套设备&…

作者头像 李华
网站建设 2026/9/8 16:29:35

量产前样品验证与测试流程标准:从风险识别到实战方法

1. 别急着送样,先想清楚你到底在验证什么量产前样品验证这件事,我见过太多团队在第一步就栽跟头。大家最常见的操作是:样品一到手,马上安排实验室上设备,高低温、振动、盐雾、跌落全部跑一遍,出来的报告厚厚…

作者头像 李华
网站建设 2026/9/8 16:27:59

RPCS3 汉化保姆级指南:三步让 PS3 模拟器说中文

RPCS3 汉化保姆级指南:三步让 PS3 模拟器说中文 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 给 RPCS3 装中文补丁,九成的人卡在同一处:补丁放进去了&#x…

作者头像 李华
网站建设 2026/9/8 16:27:30

跨境电商操作方法有哪些?2026年最全流程一次讲透

摘要:跨境电商操作方法并非神秘高深,选品、开店、物流、运营、数据五个环节环环相扣。2026年跨境出海竞争加剧,本文用最直白的方式,把一套完整可落地的跨境电商操作方法一次讲透,帮你少走弯路。 很多人一提到跨境电商…

作者头像 李华
网站建设 2026/9/8 16:23:43

每天手工核对库存台账太费时?Python一键自动标红缺货清单

做库管、采购、行政内勤的朋友,应该都有过这种窒息的日常: 别人按时下班, 你每日留在办公室, 对着几百行库存Excel台账一行一行核对, 眼睛看得发酸, 鼠标点到手麻, 只为找出库存不足的商品, 手动标红, 手动整理缺货清单。 最让人委屈的不是累&#xff…

作者头像 李华