资讯动态

NanoFlow:基于设备内并行的LLM推理框架,吞吐量提升近2倍

发布时间:2026/8/7 2:01:23 来源:尧图企业网站定制
1. 项目概述NanoFlow一个追求极致吞吐的LLM推理框架最近在折腾大模型推理部署的朋友估计没少为“吞吐量”和“延迟”这两个指标头疼。尤其是在做高并发、大规模服务时你会发现即使堆了再多GPU框架本身的调度效率往往才是真正的瓶颈。今天要聊的这个项目——NanoFlow就是冲着解决这个核心痛点来的。它不是一个简单的模型加载器而是一个从底层硬件调度视角重新设计的、面向极致吞吐量的大语言模型服务框架。简单来说NanoFlow的核心目标就是在给定的硬件比如8张A100上用同样的模型比如Llama2-70B跑出比vLLM、TensorRT-LLM等主流框架更高的每秒处理令牌数Tokens/s。根据其官方数据在某些场景下其吞吐量能达到TensorRT-LLM的1.91倍。这个提升幅度对于动辄成千上万张卡的服务集群来说意味着巨大的成本节约和效率飞跃。这个框架适合谁呢如果你正在或计划构建面向海量用户的大模型服务对服务端的吞吐量和资源利用率有极致要求或者你是一个对底层系统、CUDA编程和LLM推理优化有浓厚兴趣的开发者、研究员那么NanoFlow的设计思路和实现细节绝对值得你深入探究。它不仅仅是一个工具更提供了一套优化LLM服务系统性能的全新方法论。2. 核心设计思路打破串行拥抱“设备内并行”要理解NanoFlow为何能实现性能突破我们必须先看看现有主流框架的“通病”。传统的LLM推理服务框架其执行流程通常是高度串行化的。一个典型的推理步骤可以简化为1) CPU准备数据、管理KV缓存2) 将数据拷贝到GPU3) GPU执行计算密集的Attention和FFN层4) 将结果拷贝回CPU5) CPU处理生成结果如采样、判断EOS并准备下一轮。这个过程就像一条单车道车流数据流必须按顺序通过即使某些路段如CPU处理很空后面的车GPU计算也得等着。NanoFlow提出的核心理念叫做“设备内并行”。它认为GPU设备内部的计算单元、内存带宽、PCIe总线等资源是可以被同时利用的而不是让它们轮流“上班”。为了实现这一点NanoFlow祭出了两大“杀器”纳米批处理Nano-batching和异步CPU调度。2.1 纳米批处理将请求拆解到操作粒度传统批处理是以“请求”为单位的。一个批次里包含N个完整的请求它们一起走完上述的串行流水线。NanoFlow的“纳米批处理”则更为激进它将批处理的粒度下沉到了单个计算操作的层面。举个例子假设我们有多个正在生成的请求。在传统框架中这些请求的当前步必须等待所有请求的上一步完成后才能开始。而在NanoFlow中系统可以将不同请求的不同计算阶段例如请求A的Attention计算、请求B的矩阵乘、请求C的数据传输组合成一个“纳米批次”只要硬件资源允许就让它们同时执行。这相当于把单车道改造成了多车道不同型号的车不同类型的操作可以并行行驶。这种拆解打破了操作间的严格数据依赖为后续的重叠执行创造了条件。当然这需要对计算图有极其精细的调度和控制能力。2.2 执行单元调度与设备级流水线光有可并行的小任务还不够还得有能同时执行它们的“车间”。现代GPU如NVIDIA A100/H100内部有多个流式多处理器SM、张量核心、以及独立的内存拷贝引擎DMA。NanoFlow设计了一个设备级流水线它将GPU的硬件执行单元进行逻辑分区。例如一部分SM专门负责执行Attention计算另一部分SM和Tensor Core负责GEMM矩阵乘操作而DMA引擎则持续处理主机与设备间的数据传输。通过精心编排的调度器NanoFlow让这些不同的硬件单元在同一时刻“各司其职”分别处理不同的纳米批次任务从而实现计算、内存访问、网络通信的真正重叠。注意实现这种重叠的难点在于依赖管理和同步。NanoFlow需要确保在重叠执行时后续操作所依赖的数据已经准备就绪。这通常需要借助CUDA Stream、Event以及精细的屏障同步机制来实现其调度逻辑的复杂性远高于传统框架。2.3 异步CPU调度让CPU不再成为“看客”当GPU被高度利用后CPU端的开销就变得不容忽视。在传统同步模式下GPU在生成第i个令牌时CPU在“空闲等待”GPU完成后CPU才匆忙开始为第i1个令牌做批次整理、KV缓存管理等准备工作此时GPU又在“空闲等待”CPU。NanoFlow采用了异步控制流来打破这个僵局。其调度时序如下图所示它的核心思想是“预测”和“提前做”超前决策在GPU正在执行第i次迭代推理的同时CPU就已经开始分析当前所有请求的状态并提前做出第i1次迭代的批处理决策决定哪些请求继续生成新请求如何加入。提前分配同时CPU会为第i1次迭代所需的KV缓存空间做好分配。延迟回收对于在第i次迭代中刚刚生成结束EOS的请求系统不会立即回收其KV缓存而是等到第i2次迭代时才进行。这样就把缓存回收这个可能阻塞的操作与关键路径解耦了。这样当第i次迭代的GPU计算一结束第i1次迭代所需的所有数据和元信息都已就绪GPU可以几乎无停顿地立即开始下一次计算。CPU和GPU实现了高效的流水线并行CPU从“看客”变成了与GPU协同工作的“预备队”。3. 关键技术细节与实操解析理解了宏观设计我们深入到一些关键的技术实现细节这些是决定NanoFlow能否稳定高效运行的核心。3.1 KV缓存的异步分层卸载大模型推理尤其是长上下文场景KV缓存对显存的占用是巨大的。为了服务更多并发请求必须及时回收已结束请求的KV缓存。但直接回收意味着丢失对于多轮对话场景用户可能再次唤醒历史会话这就需要缓存持久化。NanoFlow采用了一种**“急切”的、层级的KV缓存卸载策略**异步卸载系统不会等到整个请求的KV缓存都生成完毕再处理。而是在每一层计算完成后如果判断该请求已结束就立即将该层对应的KV缓存标记为可回收并启动异步传输将其从GPU显存拷贝到主机内存。分层并行这个拷贝过程是“层-by-layer”的并且与后续层的推理计算重叠进行。当GPU正在计算第L层的Attention时DMA引擎可能正在将第L-1层已结束请求的KV缓存传输到CPU。SSD持久化对于需要持久化的缓存会进一步从主机内存异步写入SSD。论文中计算指出服务Llama2-70B模型所需的卸载带宽约为5GB/s而单个高性能NVMe SSD的顺序写入速度可达3GB/s以上这意味着仅需少量SSD即可满足需求成本可控。实操心得实现这套机制需要精细管理GPU显存、主机内存和SSD之间的数据流。必须确保数据传输的异步性不能阻塞计算流。同时缓存索引和查找逻辑会变得复杂需要设计高效的数据结构来映射请求、层、缓存块和存储位置。3.2 自动化流水线参数搜索设备级流水线听起来美好但具体如何划分硬件资源每个执行单元分配多少SM纳米批次的大小设为多少这些参数与模型结构层数、注意力头数、隐藏层维度、硬件配置、甚至输入输出长度都密切相关手动调优几乎不可能。NanoFlow集成了一个自动化参数搜索算法。你可以将其理解为一个针对当前部署环境和目标模型的“微型超参数调优”过程。算法会构建一个包含关键操作GEMM, Attention, Memory Copy等和资源约束SM数量、内存带宽的性能模型。在定义的参数空间如纳米批次大小、执行单元划分比例中进行搜索。通过快速的分析模型或小规模的实测评估每组参数的预期吞吐量。选择最优或近似最优的配置用于实际服务。这使得NanoFlow能够灵活地适配不同的模型如Llama3、Qwen2和硬件而不需要工程师为每个新组合进行耗时的手工优化。3.3 与顶尖内核库的深度集成NanoFlow没有重复造轮子而是站在了巨人的肩膀上集成了当前最先进的高性能计算内核库CUTLASS用于通用矩阵乘法GEMM操作。CUTLASS是NVIDIA官方维护的模板库能针对不同的GPU架构和数据类型生成近乎最优的矩阵乘法内核。FlashInfer用于注意力Attention计算。它实现了高度优化的Flash Attention变体能高效处理可变序列长度的批处理并支持前缀缓存等特性是当前LLM推理中Attention计算的标杆。MSCCL用于多GPU间的通信。在张量并行或流水线并行模式下GPU间需要高速交换激活值或梯度。MSCCL微软集体通信库提供了比NCCL更灵活、在某些拓扑下性能更优的通信原语。这种集成策略保证了NanoFlow在单个计算内核上的性能处于第一梯队从而让系统级优化的效果能真正体现出来而不是被低效的内核所拖累。4. 从零开始环境搭建与部署实战理论说了这么多我们来点实际的。如何在你的机器上把NanoFlow跑起来以下是一个基于Docker的详细部署指南我结合自己的踩坑经验补充了一些官方文档中未提及的细节。4.1 基础环境与Docker准备NanoFlow强烈推荐在Docker环境中运行以保证依赖库版本的一致性。这里我们使用NVIDIA官方提供的CUDA基础镜像。# 1. 在宿主机上创建一个工作目录用于和Docker容器共享代码和数据 mkdir -p ~/nanoflow_workspace # 2. 启动一个具备GPU权限和共享内存的Docker容器 # --gpus all: 将所有GPU暴露给容器 # --nethost: 使用主机网络避免容器内网络复杂度可选根据需求 # --privileged: 赋予容器一些特权便于调整内核参数如io_uring # -v /dev/shm:/dev/shm: 挂载共享内存某些多进程通信需要 # -v ~/nanoflow_workspace:/code: 将宿主机目录挂载到容器的/code路径 docker run --gpus all --nethost --privileged \ -v /dev/shm:/dev/shm \ --name nanoflow-container \ -v ~/nanoflow_workspace:/code \ -it nvcr.io/nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 # 进入容器后更新包管理器并安装系统依赖 apt update apt install -y pybind11-dev liburing-dev libopenmpi-dev wget git # 3. 启用io_uring并配置大页内存 # io_uring是Linux的高性能异步I/O接口可能被底层通信库使用 sysctl -w kernel.io_uring_disabled0 # 配置大页内存有助于提升大规模内存访问性能如KV缓存 sysctl -w vm.nr_hugepages65536 # 使配置生效可能需要根据系统情况调整 mkdir -p /dev/hugepages mount -t hugetlbfs nodev /dev/hugepages注意事项vm.nr_hugepages参数设置的大页数量65536个2MB页约128GB可能超过你机器的物理内存。请根据你的实际内存大小调整例如sysctl -w vm.nr_hugepages3276864GB。设置过大可能导致系统无法启动或报错。4.2 Gurobi优化器许可证配置NanoFlow的自动化流水线参数搜索功能依赖于Gurobi这个数学优化求解器。Gurobi需要有效的许可证学术用户可以免费申请。# 在宿主机上操作假设你已获得gurobi.lic文件 # 1. 在宿主机创建许可证目录 mkdir -p ~/gurobi_license # 2. 将下载的 gurobi.lic 文件移动到此目录 # mv ~/Downloads/gurobi.lic ~/gurobi_license/ # 3. 重新运行Docker容器将许可证目录也挂载进去 # 首先退出并删除旧容器如果存在 docker stop nanoflow-container docker rm nanoflow-container # 重新运行新增一个挂载卷 docker run --gpus all --nethost --privileged \ -v /dev/shm:/dev/shm \ -v ~/nanoflow_workspace:/code \ -v ~/gurobi_license:/opt/gurobi_license \ # 挂载许可证目录 --name nanoflow-container \ -it nvcr.io/nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 # 进入容器后设置环境变量指向许可证文件 echo export GRB_LICENSE_FILE/opt/gurobi_license/gurobi.lic ~/.bashrc source ~/.bashrc4.3 依赖安装与项目构建环境准备好后开始安装NanoFlow及其Python前端。# 1. 克隆代码库在容器内的/code目录下操作 cd /code git clone https://github.com/efeslab/Nanoflow.git cd Nanoflow # 2. 安装Anaconda并配置Python环境 # 运行项目提供的脚本它会安装Miniconda并创建一个名为nanoflow的conda环境 chmod x ./installAnaconda.sh ./installAnaconda.sh # 脚本执行完毕后需要重新加载bash配置 source ~/.bashrc # 3. 配置Hugging Face访问用于下载模型权重 mkdir -p hf echo export HF_HOME$(pwd)/hf ~/.bashrc source ~/.bashrc # 你需要一个Hugging Face账户的访问令牌 huggingface-cli login # 按照提示输入你的token # 4. 安装Python端的依赖 cd Nanoflow-python # 这个setup.sh脚本会安装pytorch, transformers, flashinfer等一堆包 # 使用yes命令自动确认可能出现的提示 yes | bash setup.sh # 这个过程可能会比较长取决于网络速度 # 5. 构建C后端核心通过pybind提供Python接口 cd ../pybind mkdir -p build cd build # 执行CMake配置和编译。-j 256指定并行编译任务数请根据你CPU核心数调整如-j32 cmake .. make -j $(nproc) # 使用$(nproc)自动获取CPU核心数更安全4.4 运行端到端测试构建成功后可以运行一个简单的测试脚本来验证整个流程。# 回到项目根目录的入口示例处 cd /code/Nanoflow/entry # 运行Llama3-8B的示例脚本 # -load_hf_weightTrue 表示从Hugging Face下载模型权重 python run_llama3.py -load_hf_weightTrue这个脚本会尝试下载Llama3-8B的模型权重加载到NanoFlow引擎中并运行一个简单的推理任务。首次运行需要下载约16GB的模型文件请确保磁盘空间和网络畅通。实操心得与常见问题编译错误如果make阶段失败最常见的原因是依赖库版本冲突或缺失。请确保严格按照步骤安装了liburing-dev和libopenmpi-dev。查看CMake输出的错误信息通常是解决问题的关键。CUDA版本不匹配项目可能依赖特定版本的CUDA特性。我们使用的是cuda:12.8.1镜像这通常是安全的。如果你使用其他版本可能需要调整CMakeLists.txt中的CUDA架构设置。内存不足运行70B模型需要大量GPU显存。确保你的测试环境如8xA100 80GB与脚本配置匹配。对于消费级显卡你可能需要修改示例脚本使用更小的模型如Llama3-8B或调整批处理大小。Gurobi许可证问题如果运行时提示找不到Gurobi许可证请检查GRB_LICENSE_FILE环境变量路径是否正确以及许可证文件是否在容器内可读。5. 性能对比分析与场景解读官方论文和README中展示了一系列对比实验我们来深入解读一下这些数据背后的含义以及它们在实际场景中的指导作用。5.1 离线吞吐量基准测试测试设置8张NVIDIA A100 80GB GPU模型为Llama2-70B。对比框架包括vLLM (v0.5.3), Deepspeed-FastGen (v0.2.3), TensorRT-LLM (v0.8.0)。所有框架均关闭了量化、推测解码、前缀缓存等特定优化以在相同基础上对比核心调度能力。测试负载恒定长度所有请求的输入和输出令牌数固定如1024输入512输出。这种测试压力稳定最能体现框架的峰值吞吐能力。真实轨迹使用从实际产品中收集的请求轨迹Splitwise, LMSYS-Chat-1M, ShareGPT。这些请求的输入输出长度变化大符合真实场景的“长尾”分布。结果解读在恒定长度测试中NanoFlow的吞吐量显著高于所有基线最高达到TensorRT-LLM的1.91倍。这直接证明了其“设备内并行”设计在挖掘硬件峰值算力方面的有效性。在真实轨迹测试中NanoFlow同样保持领先但优势幅度可能因轨迹特性而异。这说明了其调度策略不仅适用于理想情况也能很好地适应动态、不规则的真实负载。吞吐量的稳定领先意味着在服务成本固定的情况下NanoFlow能处理更多的用户请求。5.2 在线延迟测试测试设置同样在8xA100上服务Llama2-70B使用真实轨迹并模拟不同的请求到达率每秒请求数RPS。衡量指标是归一化延迟总端到端延迟除以输出令牌数这比绝对延迟更能公平地比较不同长度请求的处理效率。结果解读随着RPS增加所有框架的延迟都会上升但NanoFlow的延迟曲线上升得更慢。关键洞察在相同的延迟SLO服务水平目标下NanoFlow能够支撑更高的RPS。例如如果要求归一化延迟低于50毫秒/令牌NanoFlow能处理的RPS可能是其他框架的1.5倍以上。这对于需要保证响应速度的高并发服务至关重要意味着用同样的硬件你能服务更多用户而不超时。5.3 多模型可行性验证为了证明其设计不局限于特定模型NanoFlow团队将其移植到了多个代表性模型上Llama2-70B, Llama3-70B, Llama3.1-70B, Llama3-8B, Llama3.1-8B, Qwen2-72B。测试结果在恒定长度1024输入512输出的离线吞吐测试中NanoFlow在所有模型上都取得了可观的吞吐量Tokens/s/GPU。更重要的是其实现的吞吐量达到了各模型“理论最优吞吐量”的59%到72%之间。这个“理论最优吞吐量”通常是通过Roof-line模型等只考虑计算峰值而忽略所有开销的理想值。能达到其60%-70%说明NanoFlow已经极大地减少了系统层面的开销效率非常高。场景选择建议追求极致吞吐成本比如果你的场景是离线批量处理、AI写作工厂、大规模数据标注等对延迟不敏感但对处理总量和成本极其敏感NanoFlow是目前看到的最优选择之一。高并发在线服务如果你需要构建类似ChatGPT的在线聊天服务面对突发流量且要求稳定的低延迟NanoFlow的异步调度和高资源利用率能帮助你在满足SLO的前提下承载更高的并发量。研究与定制开发如果你需要深入探索LLM推理的系统优化NanoFlow的代码约4000行C核心是一个极佳的学习和实验平台。相比之下vLLM和TensorRT-LLM的代码库要庞大和复杂得多。6. 深入原理为什么“设备内并行”有效要真正欣赏NanoFlow的设计我们需要从硬件和计算本质的角度理解其有效性。现代GPU是一个异构计算系统其性能瓶颈会在不同阶段转移。1. 计算密集型 vs. 内存密集型操作LLM推理中Attention中的矩阵运算和FFN中的大矩阵乘法是典型的计算密集型操作需要大量浮点运算受限于GPU的SM和Tensor Core的算力。而像数据在HBM高带宽内存中的读写、GPU与CPU之间的数据传输PCIe则是内存密集型或IO密集型操作受限于内存带宽或总线带宽。在传统串行流水线中当GPU在执行计算时内存控制器和PCIe总线可能是空闲的反之亦然。这就造成了资源闲置。NanoFlow的纳米批处理和执行单元调度目的就是让计算单元和IO单元同时忙起来。2. 隐藏延迟在计算机体系结构中隐藏延迟是提升性能的关键技术。GPU通过大量线程的切换来隐藏计算延迟。NanoFlow则将这个思想提升到了操作级别用内存传输的“等待时间”去执行另一批任务的计算从而将原本串行的“计算-传输-计算”流程变成了并行的“计算与传输重叠”。3. 异步执行的代价与收益异步调度不是没有代价的。它增加了调度器的复杂性需要更精细的依赖跟踪和同步机制如更多的CUDA Event和Stream也可能会略微增加内核启动的开销。但是当单个LLM推理步骤的时间较长例如几十毫秒时这些额外开销相对于通过重叠获得的性能收益可能是成倍的提升就变得微不足道了。这就是为什么NanoFlow在70B这类大模型上效果尤为显著。7. 总结与展望NanoFlow的启示与挑战NanoFlow的出现标志着LLM推理服务系统的优化进入了一个新的阶段从单纯优化计算内核Kernel到优化内存访问如PagedAttention再到如今优化整个系统的资源调度与并行粒度。它告诉我们在硬件算力增长逐渐进入平缓期的当下通过系统软件层面的创新依然能从现有硬件中榨取出巨大的性能潜力。给开发者的启示思维转变不要只盯着FLOPs浮点运算次数。在推理服务中利用率和延迟隐藏往往比峰值算力更重要。多思考如何让不同的硬件单元同时工作。层次化优化优化需要发生在所有层次计算内核、内存层级、数据调度、系统流程。NanoFlow的成功是这些层次协同优化的结果。拥抱异步在高性能计算中异步并行是释放性能的利器。在设计系统时尽早考虑哪些操作可以异步化、流水线化。NanoFlow当前面临的挑战与未来方向生态与易用性相比vLLM和TensorRT-LLMNanoFlow还是一个新兴项目其模型支持范围、文档、社区工具链如监控、部署工具还比较薄弱。对于大多数生产团队来说易用性和稳定性是首要考虑。动态负载适应性其自动化参数搜索可能针对特定负载模式如训练用的轨迹进行了优化。在面对与训练轨迹差异极大的、不断变化的真实线上流量时调度策略是否需要在线调整是一个待解决的问题。更复杂的模型与特性目前主要测试了Decoder-only的密集模型。对于MoE混合专家模型、多模态模型、或需要复杂采样策略如束搜索的场景其调度器需要如何扩展仍有待探索。与上层系统的集成如何将NanoFlow作为一个高性能引擎无缝集成到Kubernetes、Ray Serve等现有的云原生部署和扩缩容体系中是它走向大规模生产必须跨越的一步。从我个人的实践来看NanoFlow更像是一个“性能探索者”和“基准挑战者”。它可能不会立刻取代vLLM成为你的默认选择但它所展示的性能上限和设计思路无疑为整个行业树立了一个新的标杆并指明了未来几年LLM服务系统优化的一个重要方向。对于有极致性能追求和足够技术深度的团队现在就是深入研究和尝试NanoFlow的最佳时机。你可以先从复现其基准测试开始感受其性能提升再逐步评估将其集成到自身业务流水线中的成本和收益。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价