前言大语言模型推理系统正在经历从单体部署向分布式解耦架构的演进。Prefill-DecodePD分离架构将推理过程拆分为预填充和解码两个阶段分别由不同计算节点承担从而提升整体吞吐和资源利用率。这种架构的核心挑战在于跨节点KV Cache的高效传输——Prefill节点生成的KV Cache需要低延迟、高带宽地传输到Decode节点任何通信瓶颈都会直接拖累端到端推理性能。昇腾CANN提供了HiXLHuawei Xfer Library单边通信库通过零拷贝Zero-Copy机制和单边通信One-Sided Communication能力为PD分离架构提供了高效的跨节点数据传输方案。HiXL在昇腾NPU之间建立直接内存访问通道避免传统通信模式中多次数据拷贝和CPU介入带来的延迟开销充分释放底层高速互联链路HCCS、RDMA的带宽潜力。PD分离架构的通信痛点传统通信模式的开销来源在典型的PD分离部署中Prefill节点负责处理用户输入的Prompt计算并缓存Key-Value向量Decode节点负责逐Token生成输出需要从Prefill节点拉取对应的KV Cache。这一过程涉及跨节点的内存数据传输传统实现方式存在多个性能瓶颈。基于Socket或gRPC的通信方案需要在发送端和接收端各进行一次内存拷贝应用层Buffer到内核Socket Buffer再从内核Socket Buffer到应用层Buffer。每次拷贝不仅消耗内存带宽还引入额外的延迟。当KV Cache规模达到百MB级别时这种开销变得不可忽视。即使使用RDMA的send/recv语义仍然需要在目标端准备接收Buffer并显式发起接收操作。这意味着Decode节点的CPU必须主动参与每次传输的生命周期管理无法与NPU的计算任务形成有效的流水线重叠。单边通信的技术优势单边通信One-Sided Communication允许源端在无需对端CPU介入的情况下完成数据传输。发送端准备好数据后直接写入接收端已预注册的内存区域接收端无需执行任何recv类操作即可在本地内存中看到完整数据。这种模式将通信的主导权完全交给源端目标端的计算任务可以持续运行仅在需要时直接读取已就绪的远程写入数据。零拷贝Zero-Copy进一步消除传输路径上的冗余数据移动。HiXL通过内存注册Memory Registration机制使发送端NPU能够直接访问接收端NPU或Host的物理内存数据从源Buffer经过网络链路直接写入目标Buffer全程不经过中间临时Buffer。这不仅降低了内存带宽消耗也减少了内存容量压力——在KV Cache规模持续增长的背景下每一分内存节省都具有实际价值。HiXL核心架构与关键概念三层设计HiXL采用分层架构设计从底层到上层依次为HiXL Engine、HiXL CSCommunication Service、LLM-DataDist。每一层面向不同的使用场景提供逐步抽象的接口。HiXL Engine是底层传输引擎提供最基础的点对点数据传输接口。它直接操作各类内存类型Device内存、Host内存和传输链路HCCS、RDMA支持D2DDevice-to-Device、D2HDevice-to-Host、H2DHost-to-Device等传输方向。Engine层接口最为灵活适合需要精细控制传输行为的场景。HiXL CS在Engine之上提供了面向通信服务的抽象支持更复杂的通信模式和多链路聚合。该接口目前仅支持Ascend 950PR和Ascend 950DT超节点场景利用UBUnified Bus协议实现超节点内高带宽传输。LLM-DataDist是最上层的语义接口携带KV Cache的业务语义直接与vLLM、SGLang等推理引擎对接。它屏蔽了底层传输的细节推理引擎通过简洁的接口完成KV Cache的发布和订阅无需关心数据传输的具体实现。内存模型与传输语义HiXL的内存模型区分本地内存和远程内存。本地内存是发起传输的进程所拥有的内存区域远程内存是目标进程预注册可供远程访问的内存区域。所有参与传输的内存区域都必须通过HiXL的内存注册接口进行注册以获取全局唯一的内存句柄Memory Handle。传输语义分为同步和异步两种模式。同步传输在数据写入远程内存后返回调用线程阻塞直至传输完成。异步传输立即返回传输句柄调用线程可以继续执行其他任务通过轮询或回调方式获知传输完成事件。异步模式是实现通信-计算重叠的关键——Prefill节点可以在启动KV Cache传输的同时开始处理下一个请求从而隐藏通信延迟。FabricMem是HiXL在Atlas A3超节点上提供的增强模式。它基于CANN的Virtual Memory Manager机制将超节点内所有计算节点的DRAM统一编址NPU可以通过HCCS高速链路直接访问远程节点的内存无需CPU介入。在128M数据传输场景下HCCS链路的带宽可达119GB/sRDMA链路可达22GB/s。实战基于HiXL构建PD分离通信层环境准备与编译安装在开始编写代码之前需要确保HiXL库已正确编译并安装到CANN软件路径下。HiXL的编译依赖HDK、CANN和灵衢计算网络组件版本要求如下HDK 25.5以上CANN 9.0以上灵衢计算网络1.5.0以上。# 克隆HiXL仓库gitclone https://atomgit.com/cann/hixl.gitcdhixl# 配置CANN安装路径根据实际安装位置调整exportASCEND_HOME/usr/local/Ascend/cann# 执行编译脚本bashbuild.sh# 编译成功后库文件位于 build/output 目录# 头文件路径include/hixl/hixl.h# 库文件路径build/output/libcann_hixl.soHiXL使用CMake构建系统build.sh封装了完整的编译流程包括依赖检查、编译选项配置和安装包生成。编译完成后头文件hixl.h包含所有Engine层接口的声明动态库libcann_hixl.so在运行时被链接。将ASCEND_HOME指向正确的CANN安装路径是确保编译找到正确依赖的关键步骤。初始化HiXL传输引擎任何HiXL程序的起点是初始化传输引擎。引擎初始化时需要配置本端和远端的通信地址、使用的传输链路类型以及可选的高级参数如FabricMem开关、内存池容量等。#includehixl/hixl.h#includeiostreamintmain(){// 创建HiXL引擎配置HixlConfig confignullptr;hixlCreateConfig(config);// 设置本端IP和端口hixlConfigSetString(config,HIXL_OPTION_LOCAL_IP,192.168.1.10);hixlConfigSetInt(config,HIXL_OPTION_LOCAL_PORT,18000);// 设置远端IP和端口Prefill节点连接Decode节点hixlConfigSetString(config,HIXL_OPTION_REMOTE_IP,192.168.1.20);hixlConfigSetInt(config,HIXL_OPTION_REMOTE_PORT,18000);// 使用HCCS链路超节点内跨节点使用RDMAhixlConfigSetString(config,HIXL_OPTION_LINK_TYPE,HCCS);// 启用FabricMem模式仅Atlas A3hixlConfigSetString(config,HIXL_OPTION_ENABLE_USE_FABRIC_MEM,1);// 创建引擎实例HixlEngine enginenullptr;HixlStatus statushixlCreateEngine(config,engine);if(status!HIXL_SUCCESS){std::cerrFailed to create engine: hixlGetErrorString(status)std::endl;return-1;}std::coutHiXL engine initialized successfullystd::endl;// ... 传输操作 ...// 销毁引擎hixlDestroyEngine(engine);hixlDestroyConfig(config);return0;}hixlCreateConfig创建一个配置对象通过hixlConfigSetString和hixlConfigSetInt设置引擎参数。LOCAL_IP/PORT和REMOTE_IP/PORT定义了通信端点的网络地址。LINK_TYPE选择传输链路HCCS用于超节点内高速互联RDMA用于跨节点标准网络。ENABLE_USE_FABRIC_MEM开启FabricMem模式后引擎将使用统一内存编址允许直接访问远端Host内存这对PD分离场景中Decode节点直接读取Prefill节点的KV Cache至关重要。内存注册与数据传输PD分离的核心数据流是Prefill节点将KV Cache写入Decode节点的预注册内存区域。以下代码展示完整的数据发送流程。// Prefill节点发送KV Cache到Decode节点// 1. 在Prefill节点本地申请Device内存KV Cache所在位置void*local_kv_cachenullptr;size_t kv_cache_size128*1024*1024;// 128MBaclrtMalloc(local_kv_cache,kv_cache_size,ACL_MEM_MALLOC_HUGE_FIRST);// 2. 获取Decode节点远程内存的句柄通过控制面协商得到// 实际部署中Decode节点调用hixlRegisterMemory获取handle通过控制面传给Prefill节点HixlMemHandle remote_mem_handle/* 从控制面获取 */;// 3. 将本地KV Cache传输到远程内存单边零拷贝写入HixlRequest requestnullptr;statushixlWriteRemote(engine,local_kv_cache,// 本地源地址kv_cache_size,// 传输大小remote_mem_handle,// 远程内存句柄0,// 远程偏移量request// 返回的请求句柄);if(status!HIXL_SUCCESS){std::cerrhixlWriteRemote failed: hixlGetErrorString(status)std::endl;return-1;}// 4. 异步模式下立即返回可做其他工作需要时查询完成状态// hixlWaitRequest阻塞等待完成hixlPollRequest非阻塞查询hixlWaitRequest(engine,request,HIXL_WAIT_FOREVER);std::coutKV Cache transferred successfully via zero-copy writestd::endl;// 5. 释放资源aclrtFree(local_kv_cache);hixlDestroyRequest(request);aclrtMalloc在昇腾NPU的Device内存上分配KV Cache缓冲区。HiXL的零拷贝写入通过hixlWriteRemote实现发送端NPU直接将数据写入接收端预注册的内存区域全过程无需接收端CPU参与。HixlMemHandle是内存区域的全局标识包含目标内存的物理地址信息由接收端通过hixlRegisterMemory注册后获得并通过控制面如Redis、etcd或gRPC分发给发送端。hixlWriteRemote支持异步执行返回HixlRequest句柄用于后续完成查询这使得Prefill节点可以在传输进行的同时继续处理其他请求实现通信与计算的流水线重叠。Decode节点内存注册与数据消费Decode节点需要预注册一块内存区域供Prefill节点写入并在写入完成后直接读取该区域获取KV Cache。// Decode节点注册远程可写内存区接收Prefill节点的KV Cache// 1. 在Decode节点申请Host或Device内存作为KV Cache接收缓冲区void*recv_buffernullptr;size_t recv_size128*1024*1024;// 使用Host内存DRAM作为接收缓冲区支持更大的缓存容量// Atlas A3上FabricMem模式支持D2RHDevice-to-Remote-HostaclrtMallocHost(recv_buffer,recv_size);// 2. 注册内存区域获取内存句柄供Prefill节点使用HixlMemHandle mem_handlenullptr;statushixlRegisterMemory(engine,recv_buffer,recv_size,HIXL_MEM_PERM_WRITE,// 允许远程写入mem_handle);if(status!HIXL_SUCCESS){std::cerrhixlRegisterMemory failed: hixlGetErrorString(status)std::endl;return-1;}// 3. 将mem_handle通过控制面发送给Prefill节点// 实际代码中通过gRPC/Redis等控制面组件分发// std::string handle_str hixlMemHandleSerialize(mem_handle);// control_plane-distributeHandle(handle_str);std::coutMemory registered, handle distributed to Prefill nodesstd::endl;// 4. 等待Prefill节点写入完成通过通知机制或轮询完成标记// 实际部署中可使用HiXL的完成通知机制wait_for_transfer_complete();// 5. 读取接收到的KV Cache无需拷贝直接访问// recv_buffer中已包含Prefill节点写入的KV Cache数据KVCacheHeader*headerstatic_castKVCacheHeader*(recv_buffer);std::coutReceived KV Cache: seq_lenheader-seq_len, num_layersheader-num_layersstd::endl;// 6. 将KV Cache注入本地推理引擎的解码过程inject_kv_cache_to_decoder(recv_buffer,recv_size);// 7. 使用完成后注销内存注册并释放hixlUnregisterMemory(engine,mem_handle);aclrtFreeHost(recv_buffer);Decode节点调用aclrtMallocHost在Host侧分配接收缓冲区这是因为Host DRAM容量通常远大于Device显存可以缓存更多的KV Cache。hixlRegisterMemory将这块内存注册到HiXL引擎生成HixlMemHandle该句柄编码了内存的物理地址和访问权限WRITE/READ。HIXL_MEM_PERM_WRITE标志允许远程节点向该区域写入数据。注册完成后内存句柄需要通过控制面分发给所有潜在的发送节点。Decode节点在消费数据时直接读取recv_buffer无需额外的接收拷贝操作——这是零拷贝通信的第二层含义接收端消费数据时也无需从内核Buffer或网络Buffer拷贝到应用Buffer。异步流水线通信计算重叠PD分离架构的性能关键在于隐藏通信延迟。以下示例展示如何利用HiXL的异步接口实现Prefill阶段与KV Cache传输的流水线执行。// 异步传输实现通信-计算重叠classPDPrefillWorker{private:HixlEngine engine_;std::vectorHixlRequestinflight_requests_;public:voidprocess_request(constInferenceRequestreq){// 阶段1Prefill计算生成KV CacheKVCache kv_cacherun_prefill(req.input_tokens);// 阶段2启动异步传输不等待完成HixlRequest req_handlenullptr;HixlMemHandle remote_handleget_remote_handle_for_request(req.request_id);HixlStatus statushixlWriteRemoteAsync(engine_,kv_cache.data(),kv_cache.size(),remote_handle,0,req_handle);if(statusHIXL_SUCCESS){inflight_requests_.push_back(req_handle);}// 阶段3立即继续处理下一个请求的Prefill// 传输在后台进行与下一个请求的计算并行}voidpoll_completions(){// 周期性轮询完成状态释放已完成请求的资源autoitinflight_requests_.begin();while(it!inflight_requests_.end()){HixlStatus poll_statushixlPollRequest(engine_,*it);if(poll_statusHIXL_SUCCESS){// 传输完成通知Decode节点可以开始Decodenotify_decode_complete((*it)-request_id);hixlDestroyRequest(*it);itinflight_requests_.erase(it);}else{it;}}}};hixlWriteRemoteAsync是非阻塞版本的数据传输接口调用后立即返回传输在后台继续执行。通过将传输过程与后续请求的计算过程并行化有效隐藏了跨节点通信延迟。在实际部署中这通常可以将通信开销从关键路径上完全移除——当第N个请求还在传输KV Cache时第N1个请求的Prefill计算已经在进行。poll_completions周期性检查传输完成状态完成后通过通知机制告知Decode节点启动对应请求的解码过程。这种生产者-消费者模式是PD分离架构中的标准范式。对接推理引擎LLM-DataDist接口vLLM集成路径HiXL通过LLM-DataDist层提供与vLLM的直接集成。vLLM在Prefill节点生成KV Cache后通过LLM-DataDist接口将Cache发布到HiXL传输层Decode节点的vLLM通过对应接口订阅并获取KV Cache注入本地解码过程。LLM-DataDist接口的设计目标是让推理引擎开发者无需理解底层传输细节。接口核心概念包括KVCachePublisher发布端、KVCacheSubscriber订阅端、CacheDescriptorCache描述符包含形状、数据类型、存储位置等元数据。# Decode节点使用LLM-DataDist Python接口订阅KV Cacheimportllm_datadistasldd# 初始化订阅端subscriberldd.KVCacheSubscriber()subscriber.init(rank_id0,local_ip192.168.1.20,local_port18000)# 注册本地接收缓冲区recv_bufferldd.allocate_host_memory(128*1024*1024)# 128MBsubscriber.register_buffer(recv_buffer)# 订阅来自特定Prefill节点的KV Cache# 通过Cache ID建立发布-订阅映射cache_idldd.CacheId(prompt_hashabc123,seq_len512)resultsubscriber.subscribe(cache_id,timeout_ms5000)ifresult.statusldd.SUBSCRIBE_STATUS_SUCCESS:# 直接访问接收到的KV Cache无需拷贝kv_cache_ptrsubscriber.get_cache_data(cache_id)print(fReceived KV Cache with{result.seq_len}tokens)# 注入vLLM的解码器model.executor.add_kv_cache(cache_id,kv_cache_ptr)Python接口降低了与vLLM等Python原生推理引擎的集成门槛。KVCacheSubscriber封装了HiXL Engine的初始化、内存注册、传输等待等底层操作。CacheId通过Prompt的哈希值和序列长度唯一标识一份KV Cache使Decode节点能够准确匹配需要订阅的Cache。allocate_host_memory内部调用aclrtMallocHost确保分配的内存可被HiXL用于远程写入。整个流程对vLLM透明——vLLM只需要处理标准的KV Cache数据结构传输细节完全由LLM-DataDist处理。使用前vs使用后使用前的通信路径在未使用HiXL的传统PD分离方案中KV Cache的跨节点传输通常依赖以下路径之一基于gRPC/socket的传输Prefill节点将KV Cache从Device内存拷贝到Host内存序列化为字节流通过TCP/gRPC发送到Decode节点Decode节点接收后反序列化再拷贝到Device内存。整个路径涉及至少3次数据拷贝D2H、H2N、N2H、H2D中的多个阶段每次拷贝消耗内存带宽和延迟。在128MB KV Cache场景下仅拷贝开销就可能达到毫秒级。基于传统RDMA的传输虽然RDMA可以减少拷贝次数但标准的send/recv语义仍然需要Decode节点的CPU主动参与接收操作。此外RDMA内存注册的区域通常较小大规模KV Cache需要分片传输增加了调度复杂度。CPU介入导致Decode节点的计算资源被通信任务占用降低了有效算力。基于NCCL等集合通信库的传输NCCL设计用于多GPU协同计算场景不适合PD分离这种非对称的Producer-Consumer模式。NCCL需要所有参与节点协同调用无法由Prefill节点独立主导传输。使用后的通信路径引入HiXL后通信路径得到显著简化零拷贝单边写入Prefill节点的NPU直接将数据写入Decode节点预注册的Device或Host内存全程无需Decode节点CPU参与。数据从发送端Device内存经网络链路直接写入接收端内存中间无任何临时Buffer。对于Decode节点接收到的数据已经位于可直接用于解码计算的内存位置无需额外整理或拷贝。异步流水线与细粒度重叠HiXL的异步传输接口允许Prefill节点在启动传输后立即切换至下一个请求的处理通信延迟完全被后续请求的计算掩盖。实测表明在Atlas A3超节点内部署时这种重叠可以将端到端推理延迟降低20%以上。统一内存编址FabricMem在Atlas A3超节点内FabricMem模式将各节点的Host DRAM统一编址Prefill节点的NPU可以直接访问Decode节点的Host内存D2RH无需经过Decode节点NPU的转发。这种直连路径的带宽达到119GB/sHCCS链路相比之下传统RoCE方案的带宽仅为20GB/s左右。与推理引擎的无缝集成通过LLM-DataDist接口vLLM、SGLang等推理引擎可以以最小化代码改动接入HiXL传输层。开发者无需重写通信模块只需在引擎初始化时配置KV Cache的发布/订阅策略即可。性能优化实践要点传输链路选择策略HiXL支持多种传输链路正确选择链路类型对性能至关重要。超节点内的节点间通信应优先使用HCCS链路其带宽显著高于RDMA。跨机架或跨服务器的通信则必须使用RDMA链路。在混合部署场景中可以通过HiXL的多链路支持同时配置多种链路由HiXL引擎根据目标地址自动选择最优路径。FabricMem模式仅适用于Atlas A3系列开启后自动启用统一内存编址。如果部署环境包含A2和A3混合节点需要关闭FabricMem以确保兼容性。HiXL支持A2/A3/A5异构互联但部分高级特性仅在同代际节点间可用。内存注册粒度内存注册的粒度影响传输效率和管理开销。过小的注册粒度导致每个KV Cache传输都需要多次注册/注销操作增加控制面开销过大的注册粒度则造成内存浪费。推荐的实践是为每个Decode节点预注册若干固定大小的内存池如每个池128MB通过内存池内的偏移量管理多个KV Cache的存储位置。HiXL的OPTION_GLOBAL_RESOURCE_CONFIG参数可以配置Fabric虚拟内存池的容量和起始地址建议在部署规划阶段根据典型KV Cache大小进行合理配置。异步传输的完成通知大规模部署中Decode节点需要同时处理来自多个Prefill节点的KV Cache传输请求。使用轮询方式检查传输完成状态会消耗CPU资源推荐的做法是结合HiXL的完成通知机制Completion Notification在传输完成后由HiXL主动通知目标节点。这需要在初始化引擎时配置通知通道并在Decode节点注册回调函数处理传输完成事件。总结HiXL为昇腾CANN生态提供了生产级的单边零拷贝通信能力其在PD分离架构中的价值可以归纳为三个维度性能维度上零拷贝和单边通信消除了传统传输路径上的冗余拷贝和CPU介入FabricMem模式进一步将超节点内传输带宽提升至百GB/s级别工程维度上分层接口设计允许开发者根据场景选择合适的抽象层级LLM-DataDist接口使主流推理引擎的集成成本降至最低生态维度上HiXL已对接Mooncake、DeepLink、vLLM、SGLang等开源项目形成了从底层传输到上层应用的完整技术栈。仓库地址https://atomgit.com/cann/hixl
昇腾CANN单边通信库HiXL实战:PD分离架构中的零拷贝通信优化实践
发布时间:2026/6/10 0:55:10
前言大语言模型推理系统正在经历从单体部署向分布式解耦架构的演进。Prefill-DecodePD分离架构将推理过程拆分为预填充和解码两个阶段分别由不同计算节点承担从而提升整体吞吐和资源利用率。这种架构的核心挑战在于跨节点KV Cache的高效传输——Prefill节点生成的KV Cache需要低延迟、高带宽地传输到Decode节点任何通信瓶颈都会直接拖累端到端推理性能。昇腾CANN提供了HiXLHuawei Xfer Library单边通信库通过零拷贝Zero-Copy机制和单边通信One-Sided Communication能力为PD分离架构提供了高效的跨节点数据传输方案。HiXL在昇腾NPU之间建立直接内存访问通道避免传统通信模式中多次数据拷贝和CPU介入带来的延迟开销充分释放底层高速互联链路HCCS、RDMA的带宽潜力。PD分离架构的通信痛点传统通信模式的开销来源在典型的PD分离部署中Prefill节点负责处理用户输入的Prompt计算并缓存Key-Value向量Decode节点负责逐Token生成输出需要从Prefill节点拉取对应的KV Cache。这一过程涉及跨节点的内存数据传输传统实现方式存在多个性能瓶颈。基于Socket或gRPC的通信方案需要在发送端和接收端各进行一次内存拷贝应用层Buffer到内核Socket Buffer再从内核Socket Buffer到应用层Buffer。每次拷贝不仅消耗内存带宽还引入额外的延迟。当KV Cache规模达到百MB级别时这种开销变得不可忽视。即使使用RDMA的send/recv语义仍然需要在目标端准备接收Buffer并显式发起接收操作。这意味着Decode节点的CPU必须主动参与每次传输的生命周期管理无法与NPU的计算任务形成有效的流水线重叠。单边通信的技术优势单边通信One-Sided Communication允许源端在无需对端CPU介入的情况下完成数据传输。发送端准备好数据后直接写入接收端已预注册的内存区域接收端无需执行任何recv类操作即可在本地内存中看到完整数据。这种模式将通信的主导权完全交给源端目标端的计算任务可以持续运行仅在需要时直接读取已就绪的远程写入数据。零拷贝Zero-Copy进一步消除传输路径上的冗余数据移动。HiXL通过内存注册Memory Registration机制使发送端NPU能够直接访问接收端NPU或Host的物理内存数据从源Buffer经过网络链路直接写入目标Buffer全程不经过中间临时Buffer。这不仅降低了内存带宽消耗也减少了内存容量压力——在KV Cache规模持续增长的背景下每一分内存节省都具有实际价值。HiXL核心架构与关键概念三层设计HiXL采用分层架构设计从底层到上层依次为HiXL Engine、HiXL CSCommunication Service、LLM-DataDist。每一层面向不同的使用场景提供逐步抽象的接口。HiXL Engine是底层传输引擎提供最基础的点对点数据传输接口。它直接操作各类内存类型Device内存、Host内存和传输链路HCCS、RDMA支持D2DDevice-to-Device、D2HDevice-to-Host、H2DHost-to-Device等传输方向。Engine层接口最为灵活适合需要精细控制传输行为的场景。HiXL CS在Engine之上提供了面向通信服务的抽象支持更复杂的通信模式和多链路聚合。该接口目前仅支持Ascend 950PR和Ascend 950DT超节点场景利用UBUnified Bus协议实现超节点内高带宽传输。LLM-DataDist是最上层的语义接口携带KV Cache的业务语义直接与vLLM、SGLang等推理引擎对接。它屏蔽了底层传输的细节推理引擎通过简洁的接口完成KV Cache的发布和订阅无需关心数据传输的具体实现。内存模型与传输语义HiXL的内存模型区分本地内存和远程内存。本地内存是发起传输的进程所拥有的内存区域远程内存是目标进程预注册可供远程访问的内存区域。所有参与传输的内存区域都必须通过HiXL的内存注册接口进行注册以获取全局唯一的内存句柄Memory Handle。传输语义分为同步和异步两种模式。同步传输在数据写入远程内存后返回调用线程阻塞直至传输完成。异步传输立即返回传输句柄调用线程可以继续执行其他任务通过轮询或回调方式获知传输完成事件。异步模式是实现通信-计算重叠的关键——Prefill节点可以在启动KV Cache传输的同时开始处理下一个请求从而隐藏通信延迟。FabricMem是HiXL在Atlas A3超节点上提供的增强模式。它基于CANN的Virtual Memory Manager机制将超节点内所有计算节点的DRAM统一编址NPU可以通过HCCS高速链路直接访问远程节点的内存无需CPU介入。在128M数据传输场景下HCCS链路的带宽可达119GB/sRDMA链路可达22GB/s。实战基于HiXL构建PD分离通信层环境准备与编译安装在开始编写代码之前需要确保HiXL库已正确编译并安装到CANN软件路径下。HiXL的编译依赖HDK、CANN和灵衢计算网络组件版本要求如下HDK 25.5以上CANN 9.0以上灵衢计算网络1.5.0以上。# 克隆HiXL仓库gitclone https://atomgit.com/cann/hixl.gitcdhixl# 配置CANN安装路径根据实际安装位置调整exportASCEND_HOME/usr/local/Ascend/cann# 执行编译脚本bashbuild.sh# 编译成功后库文件位于 build/output 目录# 头文件路径include/hixl/hixl.h# 库文件路径build/output/libcann_hixl.soHiXL使用CMake构建系统build.sh封装了完整的编译流程包括依赖检查、编译选项配置和安装包生成。编译完成后头文件hixl.h包含所有Engine层接口的声明动态库libcann_hixl.so在运行时被链接。将ASCEND_HOME指向正确的CANN安装路径是确保编译找到正确依赖的关键步骤。初始化HiXL传输引擎任何HiXL程序的起点是初始化传输引擎。引擎初始化时需要配置本端和远端的通信地址、使用的传输链路类型以及可选的高级参数如FabricMem开关、内存池容量等。#includehixl/hixl.h#includeiostreamintmain(){// 创建HiXL引擎配置HixlConfig confignullptr;hixlCreateConfig(config);// 设置本端IP和端口hixlConfigSetString(config,HIXL_OPTION_LOCAL_IP,192.168.1.10);hixlConfigSetInt(config,HIXL_OPTION_LOCAL_PORT,18000);// 设置远端IP和端口Prefill节点连接Decode节点hixlConfigSetString(config,HIXL_OPTION_REMOTE_IP,192.168.1.20);hixlConfigSetInt(config,HIXL_OPTION_REMOTE_PORT,18000);// 使用HCCS链路超节点内跨节点使用RDMAhixlConfigSetString(config,HIXL_OPTION_LINK_TYPE,HCCS);// 启用FabricMem模式仅Atlas A3hixlConfigSetString(config,HIXL_OPTION_ENABLE_USE_FABRIC_MEM,1);// 创建引擎实例HixlEngine enginenullptr;HixlStatus statushixlCreateEngine(config,engine);if(status!HIXL_SUCCESS){std::cerrFailed to create engine: hixlGetErrorString(status)std::endl;return-1;}std::coutHiXL engine initialized successfullystd::endl;// ... 传输操作 ...// 销毁引擎hixlDestroyEngine(engine);hixlDestroyConfig(config);return0;}hixlCreateConfig创建一个配置对象通过hixlConfigSetString和hixlConfigSetInt设置引擎参数。LOCAL_IP/PORT和REMOTE_IP/PORT定义了通信端点的网络地址。LINK_TYPE选择传输链路HCCS用于超节点内高速互联RDMA用于跨节点标准网络。ENABLE_USE_FABRIC_MEM开启FabricMem模式后引擎将使用统一内存编址允许直接访问远端Host内存这对PD分离场景中Decode节点直接读取Prefill节点的KV Cache至关重要。内存注册与数据传输PD分离的核心数据流是Prefill节点将KV Cache写入Decode节点的预注册内存区域。以下代码展示完整的数据发送流程。// Prefill节点发送KV Cache到Decode节点// 1. 在Prefill节点本地申请Device内存KV Cache所在位置void*local_kv_cachenullptr;size_t kv_cache_size128*1024*1024;// 128MBaclrtMalloc(local_kv_cache,kv_cache_size,ACL_MEM_MALLOC_HUGE_FIRST);// 2. 获取Decode节点远程内存的句柄通过控制面协商得到// 实际部署中Decode节点调用hixlRegisterMemory获取handle通过控制面传给Prefill节点HixlMemHandle remote_mem_handle/* 从控制面获取 */;// 3. 将本地KV Cache传输到远程内存单边零拷贝写入HixlRequest requestnullptr;statushixlWriteRemote(engine,local_kv_cache,// 本地源地址kv_cache_size,// 传输大小remote_mem_handle,// 远程内存句柄0,// 远程偏移量request// 返回的请求句柄);if(status!HIXL_SUCCESS){std::cerrhixlWriteRemote failed: hixlGetErrorString(status)std::endl;return-1;}// 4. 异步模式下立即返回可做其他工作需要时查询完成状态// hixlWaitRequest阻塞等待完成hixlPollRequest非阻塞查询hixlWaitRequest(engine,request,HIXL_WAIT_FOREVER);std::coutKV Cache transferred successfully via zero-copy writestd::endl;// 5. 释放资源aclrtFree(local_kv_cache);hixlDestroyRequest(request);aclrtMalloc在昇腾NPU的Device内存上分配KV Cache缓冲区。HiXL的零拷贝写入通过hixlWriteRemote实现发送端NPU直接将数据写入接收端预注册的内存区域全过程无需接收端CPU参与。HixlMemHandle是内存区域的全局标识包含目标内存的物理地址信息由接收端通过hixlRegisterMemory注册后获得并通过控制面如Redis、etcd或gRPC分发给发送端。hixlWriteRemote支持异步执行返回HixlRequest句柄用于后续完成查询这使得Prefill节点可以在传输进行的同时继续处理其他请求实现通信与计算的流水线重叠。Decode节点内存注册与数据消费Decode节点需要预注册一块内存区域供Prefill节点写入并在写入完成后直接读取该区域获取KV Cache。// Decode节点注册远程可写内存区接收Prefill节点的KV Cache// 1. 在Decode节点申请Host或Device内存作为KV Cache接收缓冲区void*recv_buffernullptr;size_t recv_size128*1024*1024;// 使用Host内存DRAM作为接收缓冲区支持更大的缓存容量// Atlas A3上FabricMem模式支持D2RHDevice-to-Remote-HostaclrtMallocHost(recv_buffer,recv_size);// 2. 注册内存区域获取内存句柄供Prefill节点使用HixlMemHandle mem_handlenullptr;statushixlRegisterMemory(engine,recv_buffer,recv_size,HIXL_MEM_PERM_WRITE,// 允许远程写入mem_handle);if(status!HIXL_SUCCESS){std::cerrhixlRegisterMemory failed: hixlGetErrorString(status)std::endl;return-1;}// 3. 将mem_handle通过控制面发送给Prefill节点// 实际代码中通过gRPC/Redis等控制面组件分发// std::string handle_str hixlMemHandleSerialize(mem_handle);// control_plane-distributeHandle(handle_str);std::coutMemory registered, handle distributed to Prefill nodesstd::endl;// 4. 等待Prefill节点写入完成通过通知机制或轮询完成标记// 实际部署中可使用HiXL的完成通知机制wait_for_transfer_complete();// 5. 读取接收到的KV Cache无需拷贝直接访问// recv_buffer中已包含Prefill节点写入的KV Cache数据KVCacheHeader*headerstatic_castKVCacheHeader*(recv_buffer);std::coutReceived KV Cache: seq_lenheader-seq_len, num_layersheader-num_layersstd::endl;// 6. 将KV Cache注入本地推理引擎的解码过程inject_kv_cache_to_decoder(recv_buffer,recv_size);// 7. 使用完成后注销内存注册并释放hixlUnregisterMemory(engine,mem_handle);aclrtFreeHost(recv_buffer);Decode节点调用aclrtMallocHost在Host侧分配接收缓冲区这是因为Host DRAM容量通常远大于Device显存可以缓存更多的KV Cache。hixlRegisterMemory将这块内存注册到HiXL引擎生成HixlMemHandle该句柄编码了内存的物理地址和访问权限WRITE/READ。HIXL_MEM_PERM_WRITE标志允许远程节点向该区域写入数据。注册完成后内存句柄需要通过控制面分发给所有潜在的发送节点。Decode节点在消费数据时直接读取recv_buffer无需额外的接收拷贝操作——这是零拷贝通信的第二层含义接收端消费数据时也无需从内核Buffer或网络Buffer拷贝到应用Buffer。异步流水线通信计算重叠PD分离架构的性能关键在于隐藏通信延迟。以下示例展示如何利用HiXL的异步接口实现Prefill阶段与KV Cache传输的流水线执行。// 异步传输实现通信-计算重叠classPDPrefillWorker{private:HixlEngine engine_;std::vectorHixlRequestinflight_requests_;public:voidprocess_request(constInferenceRequestreq){// 阶段1Prefill计算生成KV CacheKVCache kv_cacherun_prefill(req.input_tokens);// 阶段2启动异步传输不等待完成HixlRequest req_handlenullptr;HixlMemHandle remote_handleget_remote_handle_for_request(req.request_id);HixlStatus statushixlWriteRemoteAsync(engine_,kv_cache.data(),kv_cache.size(),remote_handle,0,req_handle);if(statusHIXL_SUCCESS){inflight_requests_.push_back(req_handle);}// 阶段3立即继续处理下一个请求的Prefill// 传输在后台进行与下一个请求的计算并行}voidpoll_completions(){// 周期性轮询完成状态释放已完成请求的资源autoitinflight_requests_.begin();while(it!inflight_requests_.end()){HixlStatus poll_statushixlPollRequest(engine_,*it);if(poll_statusHIXL_SUCCESS){// 传输完成通知Decode节点可以开始Decodenotify_decode_complete((*it)-request_id);hixlDestroyRequest(*it);itinflight_requests_.erase(it);}else{it;}}}};hixlWriteRemoteAsync是非阻塞版本的数据传输接口调用后立即返回传输在后台继续执行。通过将传输过程与后续请求的计算过程并行化有效隐藏了跨节点通信延迟。在实际部署中这通常可以将通信开销从关键路径上完全移除——当第N个请求还在传输KV Cache时第N1个请求的Prefill计算已经在进行。poll_completions周期性检查传输完成状态完成后通过通知机制告知Decode节点启动对应请求的解码过程。这种生产者-消费者模式是PD分离架构中的标准范式。对接推理引擎LLM-DataDist接口vLLM集成路径HiXL通过LLM-DataDist层提供与vLLM的直接集成。vLLM在Prefill节点生成KV Cache后通过LLM-DataDist接口将Cache发布到HiXL传输层Decode节点的vLLM通过对应接口订阅并获取KV Cache注入本地解码过程。LLM-DataDist接口的设计目标是让推理引擎开发者无需理解底层传输细节。接口核心概念包括KVCachePublisher发布端、KVCacheSubscriber订阅端、CacheDescriptorCache描述符包含形状、数据类型、存储位置等元数据。# Decode节点使用LLM-DataDist Python接口订阅KV Cacheimportllm_datadistasldd# 初始化订阅端subscriberldd.KVCacheSubscriber()subscriber.init(rank_id0,local_ip192.168.1.20,local_port18000)# 注册本地接收缓冲区recv_bufferldd.allocate_host_memory(128*1024*1024)# 128MBsubscriber.register_buffer(recv_buffer)# 订阅来自特定Prefill节点的KV Cache# 通过Cache ID建立发布-订阅映射cache_idldd.CacheId(prompt_hashabc123,seq_len512)resultsubscriber.subscribe(cache_id,timeout_ms5000)ifresult.statusldd.SUBSCRIBE_STATUS_SUCCESS:# 直接访问接收到的KV Cache无需拷贝kv_cache_ptrsubscriber.get_cache_data(cache_id)print(fReceived KV Cache with{result.seq_len}tokens)# 注入vLLM的解码器model.executor.add_kv_cache(cache_id,kv_cache_ptr)Python接口降低了与vLLM等Python原生推理引擎的集成门槛。KVCacheSubscriber封装了HiXL Engine的初始化、内存注册、传输等待等底层操作。CacheId通过Prompt的哈希值和序列长度唯一标识一份KV Cache使Decode节点能够准确匹配需要订阅的Cache。allocate_host_memory内部调用aclrtMallocHost确保分配的内存可被HiXL用于远程写入。整个流程对vLLM透明——vLLM只需要处理标准的KV Cache数据结构传输细节完全由LLM-DataDist处理。使用前vs使用后使用前的通信路径在未使用HiXL的传统PD分离方案中KV Cache的跨节点传输通常依赖以下路径之一基于gRPC/socket的传输Prefill节点将KV Cache从Device内存拷贝到Host内存序列化为字节流通过TCP/gRPC发送到Decode节点Decode节点接收后反序列化再拷贝到Device内存。整个路径涉及至少3次数据拷贝D2H、H2N、N2H、H2D中的多个阶段每次拷贝消耗内存带宽和延迟。在128MB KV Cache场景下仅拷贝开销就可能达到毫秒级。基于传统RDMA的传输虽然RDMA可以减少拷贝次数但标准的send/recv语义仍然需要Decode节点的CPU主动参与接收操作。此外RDMA内存注册的区域通常较小大规模KV Cache需要分片传输增加了调度复杂度。CPU介入导致Decode节点的计算资源被通信任务占用降低了有效算力。基于NCCL等集合通信库的传输NCCL设计用于多GPU协同计算场景不适合PD分离这种非对称的Producer-Consumer模式。NCCL需要所有参与节点协同调用无法由Prefill节点独立主导传输。使用后的通信路径引入HiXL后通信路径得到显著简化零拷贝单边写入Prefill节点的NPU直接将数据写入Decode节点预注册的Device或Host内存全程无需Decode节点CPU参与。数据从发送端Device内存经网络链路直接写入接收端内存中间无任何临时Buffer。对于Decode节点接收到的数据已经位于可直接用于解码计算的内存位置无需额外整理或拷贝。异步流水线与细粒度重叠HiXL的异步传输接口允许Prefill节点在启动传输后立即切换至下一个请求的处理通信延迟完全被后续请求的计算掩盖。实测表明在Atlas A3超节点内部署时这种重叠可以将端到端推理延迟降低20%以上。统一内存编址FabricMem在Atlas A3超节点内FabricMem模式将各节点的Host DRAM统一编址Prefill节点的NPU可以直接访问Decode节点的Host内存D2RH无需经过Decode节点NPU的转发。这种直连路径的带宽达到119GB/sHCCS链路相比之下传统RoCE方案的带宽仅为20GB/s左右。与推理引擎的无缝集成通过LLM-DataDist接口vLLM、SGLang等推理引擎可以以最小化代码改动接入HiXL传输层。开发者无需重写通信模块只需在引擎初始化时配置KV Cache的发布/订阅策略即可。性能优化实践要点传输链路选择策略HiXL支持多种传输链路正确选择链路类型对性能至关重要。超节点内的节点间通信应优先使用HCCS链路其带宽显著高于RDMA。跨机架或跨服务器的通信则必须使用RDMA链路。在混合部署场景中可以通过HiXL的多链路支持同时配置多种链路由HiXL引擎根据目标地址自动选择最优路径。FabricMem模式仅适用于Atlas A3系列开启后自动启用统一内存编址。如果部署环境包含A2和A3混合节点需要关闭FabricMem以确保兼容性。HiXL支持A2/A3/A5异构互联但部分高级特性仅在同代际节点间可用。内存注册粒度内存注册的粒度影响传输效率和管理开销。过小的注册粒度导致每个KV Cache传输都需要多次注册/注销操作增加控制面开销过大的注册粒度则造成内存浪费。推荐的实践是为每个Decode节点预注册若干固定大小的内存池如每个池128MB通过内存池内的偏移量管理多个KV Cache的存储位置。HiXL的OPTION_GLOBAL_RESOURCE_CONFIG参数可以配置Fabric虚拟内存池的容量和起始地址建议在部署规划阶段根据典型KV Cache大小进行合理配置。异步传输的完成通知大规模部署中Decode节点需要同时处理来自多个Prefill节点的KV Cache传输请求。使用轮询方式检查传输完成状态会消耗CPU资源推荐的做法是结合HiXL的完成通知机制Completion Notification在传输完成后由HiXL主动通知目标节点。这需要在初始化引擎时配置通知通道并在Decode节点注册回调函数处理传输完成事件。总结HiXL为昇腾CANN生态提供了生产级的单边零拷贝通信能力其在PD分离架构中的价值可以归纳为三个维度性能维度上零拷贝和单边通信消除了传统传输路径上的冗余拷贝和CPU介入FabricMem模式进一步将超节点内传输带宽提升至百GB/s级别工程维度上分层接口设计允许开发者根据场景选择合适的抽象层级LLM-DataDist接口使主流推理引擎的集成成本降至最低生态维度上HiXL已对接Mooncake、DeepLink、vLLM、SGLang等开源项目形成了从底层传输到上层应用的完整技术栈。仓库地址https://atomgit.com/cann/hixl