【字节三面题】PD分离技巧大揭秘,面试通关必备!_nccl nixl
01.为什么要 PD 分离?
首先要了解 LLM 的推理可以分为两个阶段:
-
Prefilling:对输入的 prompt,一次计算全部的 kvcache,输出首 token,此时的耗时为 TTFT,通常在几百 ms。
-
Decoding:根据计算好的 kv cache,迭代式的生成每一个 token。耗时为 TBT,通常在 10~20ms。
画出 LLM 的推理过程示意图,可以看出,当 prefilling 和 decoding 在同一个 batch 中时,Prefilling 操作会严重影响 Decoding 结果的输出效率。
如果是 PD 分离架构:
从上图可以看出,PD 分离可以提高 decoding 部分的效率。但是从 TP2 变成 1P1D,prefilling 的卡减少,大 bs、长输入时会导致 TTFT 变长。
另外因为 prefill 的计算量大,decoder 阶段的传输量大,因此 PD 分离可以对两个阶段使用不同类型的显卡,最大化性价比。
因为相比 A 系列和 H 系列的卡,4090 的算力可能在 30%~50% 左右,但是带宽只有 10% 不到,所以非常适合用于 prefill 阶段计算,性价比很高。
02.怎么进行 PD 分离?
PD分离-XpYd系统服务化:
https://zhuanlan.zhihu.com/p/30619735151
当前的 server 框架(比如 vllm、sglang)通常用于单机 server。
XpYd 就是在这个基础上,再封装一层 server 代码,根据参数启动多个独立的 server,分别标为 prefill server 和 decoder server,管理不同 server 之间的 cache 调度。
相同的 vllm server 怎么分为 prefill server 和 decoder server 呢?
其实在启动参数上并没多大区别,启动两个 server 服务,所有的 request 首先发送到 prefill server,并将 max_tokens 设为 1。
处理完成后将相同的 request 再输入 decoder server,获取输出即可。那么这两个 server 自然就会一个只处理 prefilling、一个只处理 decoding 了。
# prefill server
CUDA_VISIBLE_DEVICES=\'0\' python3 -m vllm.entrypoints.openai.api_server \\
--model $MODEL_NAME \\
--port 8100 \\
--trust-remote-code \\
--enforce-eager \\
--kv-transfer-config \\
\'{\"kv_connector\":\"SharedStorageConnector\",\"kv_role\":\"kv_both\",\"kv_connector_extra_config\": {\"shared_storage_path\": \"local_storage\"}}\' &
# decoder server
CUDA_VISIBLE_DEVICES=\'1\' python3 -m vllm.entrypoints.openai.api_server \\
--model $MODEL_NAME \\
--port 8200 \\
--trust-remote-code \\
--enforce-eager \\
--kv-transfer-config \\
\'{\"kv_connector\":\"SharedStorageConnector\",\"kv_role\":\"kv_both\",\"kv_connector_extra_config\": {\"shared_storage_path\": \"local_storage\"}}\' &
# proxy server
python3 disagg_pd_proxy_server.py &
其中 disagg_pd_proxy_server.py 可以参考代码:
https://github.com/vllm-project/vllm/blob/main/examples/online_serving/disaggregated_serving/disagg_proxy_demo.py
核心代码如下:
@app.route(\'/v1/completions\', methods=[\'POST\'])
async def handle_request():
try:
original_request_data = await request.get_json()
prefill_request = original_request_data.copy()
# change max_tokens = 1 to let it only do prefill
prefill_request[\'max_tokens\'] = 1
# finish prefill
async for _ in forward_request(\'http://localhost:8100/v1/completions\',
prefill_request):
continue
# return decode
generator = forward_request(\'http://localhost:8200/v1/completions\',
original_request_data)
response = await make_response(generator)
response.timeout = None
return response
except Exception as e:
print(\"Error occurred in disagg prefill proxy server\")
当然,只是上面的简单修改还不够,vllm 中的代码也要修改,要将 prefill server 中计算的 kv cache 发送到 decoder server。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
对于 vllm server 来说,每次推理前,检查当前输入的 token_ids 有没有处理过的 kv cache 缓存,如果有,则可以直接复用,即 decoding 处理。
如果没有,则进行 prefilling 处理,并将 kv cache 保存,保存的 key 需要和 token_ids 相关。
https://github.com/vllm-project/vllm/blob/main/vllm/v1/worker/gpu_model_runner.py
基本的 PD 分离逻辑基本介绍完了,当初看的时候感觉是个很复杂的工程,现在用来也没有多麻烦。(当然是 vllm 和多位大神代码集成的好,而且实际在用的话还需要很多的优化)
到这里大家就知道了,PD 分离的核心其实在于 cache 的调度。
03.vllm 的 PD 分离
vllm0.9.1 版本,kv cache 调度器支持的 KVconnector 类型如下:
下面只介绍 v1 版本的几种 PD 分离:
(1)SharedStorageConnector
https://github.com/vllm-project/vllm/blob/main/vllm/distributed/kv_transfer/kv_connector/v1/shared_storage_connector.py
从代码中可以看出主要包含 save_kv_layer 和 start_load_kv 两个函数。
prefill 阶段,会将计算的 kvcache 通过 save_kv_layer 函数保存到本地文件夹中。
decoder 阶段,会通过 start_load_kv 函数从本地文件夹中读取 kv cache。
测试发现,代码中目前只支持 1P1D,且 prefill_tp_size=decoder_tp_size=1。
若要支持 prefill_tp_size != decoder_tp_size,则需要修改代码:在 save_kv_layer 中增加 rank 标记,保证多 rank 同时保存时不互相覆盖。
在 start_load_kv 函数中增加读取多个 rank 读取 cache,并根据当前 server 的 tp 数量进行 cache 拆分的逻辑。
分析:从代码中可以看出,在 prefill 和 decoder 之间有文件保存和读取操作,会大幅影响结果耗时。
(2)P2pNcclConnector
从代码中可以看出,P2pNcclConnector 相比于 SharedStorageConnector,就是把 safetensors save/load 操作换成了 nccl 的 send 和 reciver 操作。
NCCL(NVIDIA Collective Communications Library)是 NVIDIA 提供的一个用于多 GPU 和多节点之间高效通信的库。
它主要用于深度学习和高性能计算(HPC),支持常见的集合通信操作,如 AllReduce
、Broadcast
、Reduce
、Scatter
和 Gather
等。
特点:
-
高性能:针对 NVIDIA GPU 进行优化,支持 PCIe、NVLink 和 InfiniBand。
-
多节点扩展:支持跨多个节点的 GPU 通信。
-
支持多种数据类型和通信模式(LL、LL128、SIMPLE 协议等)。
-
可配置参数(如 NCCL_PROTO,NCCL_ALGO,NCCL_MAX_NCHANNELS)以优化性能。
使用 NCCl 在 GPU 之间直接处理数据,大幅降低了数据传输耗时。
NCCL 负责 GPU 间的数据传输,而 ZMQ 仅用于控制信道(metadata 交换)。两者配合使用,但并不直接通过 ZMQ 传输张量数据。
# 在 P2pNcclEngine 中:
self.nccl = NCCLLibrary(library_path) # 初始化 NCCL 库
self._create_connect(remote_address) # 使用 ZMQ 发起连接请求,并初始化 NCCL Comm
self._send(comm, tensor, dst, stream) # 实际调用 ncclSend 进行 GPU 数据传输
(3)LMCacheConnectorV1——LMCache
https://github.com/LMCache/LMCache
封装了一层 LMCache 调用逻辑。
LMCache 是一个针对 vllm 的 cache 复用框架。
主要优点:
-
减少推理时间:通过重用缓存的 KV 张量消除冗余计算(通过 CPU 以及磁盘缓存,可以保存更多的 cache)
-
更高的吞吐量:处理处理过的文本,节省 GPU 周期
-
内存效率:分层存储系统优化 GPU、CPU 和磁盘的内存使用率
-
非前缀缓存:支持缓存任何文本片段,而不仅仅是前缀(decoding 过程的 cache 也可以全部保存)
-
框架集成:与 vLLM 服务堆栈无缝集成(推理直接调用 vllm,保存 vllm 的 cache)
入口:
https://github.com/LMCache/LMCache/tree/dev/lmcache/integration/vllm/vllm_v1_adapter.py
的 LMCacheConnectorV1Impl 类。
根据类型,选择创建 SCHEDULER 还是 SERVER WORKER:
在 vllm 中的调用过程:
prefill 阶段调用流程:
-
save_kv_layer
-
self._lmcache_engine.save_kv_layer
-
self.lmcache_engine.store_layer
decoder 阶段调用流程:
-
start_load_kv
-
self._lmcache_engine.start_load_kv
-
self.lmcache_engine.retrieve_layer
可以看出 storage_manager 是存储管理。gpu_connector 是负责数据传输。
StorageManager 包含 storage_backends,主要支持 NixlBackend、LocalCPUBackend、LocalDiskBackend 和 RemoteBackend 等类。
其中分别是通过本地 GPU、本地 CPU、本地 disk 和跨结点传输数据。(Nixl 是 nvidia 开源的 gpu 传输技术,后面会单独开一节详细介绍)跨结点传输包含了 mooncake 实现。
vllm_Connector 支持下面几种,外部支持调用的是最后三种。
Connector 总结对比:
KV 缓存请求流程和数据处理管道:
LMCache 还有一个 enable_blending 功能,可以支持 kv cache 的位置编码解耦,从而能够复用非前缀缓存,进一步提高推理效率。
(4)NixlConnector——nixl
NixlConnector 中使用了 nvidia-smi 的 nixl 库进行通信,其他用法和 P2pNcclConnector 没有什么区别。
nixl 的具体内容以及 nixl 和 nccl 的比较放到下面的 dynamo 一节中详细讲解。
04.sglang 的 PD 分离
Deploying DeepSeek with PD Disaggregation and Large-scale Expert Parallelism on 96 H100 GPUs
https://github.com/sgl-project/sglang/issues/4655
https://docs.sglang.ai/backend/pd_disaggregation.html
收到输入请求后,工作流程如下:
-
预填充服务器和解码服务器通过握手配对,分别建立本地发送方和接收方。
-
解码服务器预先分配 KV 缓存,向预填充服务器发出信号,开始模型前向传递并计算 KV 缓存。
-
一旦计算完成,数据就会传输到解码服务器,由其处理迭代令牌生成。
(1)github 代码详解
代码框架如下:
Engine 中创建 Scheduler。
PrefillBootstrapQueue 和 DecodePreallocQueue 中都会创建 kv_manager 对 kv cahce 进行管理。
支持 mooncake 和 nixl 后端。
状态值:
调用 /v1/chat/completions 接口时,会走到 generate 接口:
-
_global_state.tokenizer_manager.generate_request()
-
self._send_one_request()
-
self.send_to_scheduler.send_pyobj()
将 request 发送到两个 server 的 scheduler。
(2)prefill server 处理流程
1. 在 schedule 中调用 handle_generate_request()->_add_request_to_queue() 处理新的 request。
2. 在 _add_request_to_queue() 中调用调用 PrefillBootstrapQueue().add() 将 request 添加到 queue 中。并添加到 schedule.waiting_queue 中。
3. 后台运行的 event_loop_normal_disagg_prefill() 检测到 queue 中包含未处理的 req,进行处理。
4. 在 process_batch_result_disagg_prefill() 中通过 disagg_kv_sender 发送处理过的 kv cache。
(3)decode server 处理流程
1. 在 schedule 中调用 handle_generate_request()->_add_request_to_queue() 处理新收到的 request。
2. 在 _add_request_to_queue() 中调用调用 DecodePreallocQueue().add() 将 request 添加到 queue 中。并添加到 schedule.waiting_queue 中。
3. 后台运行的 event_loop_overlap_disagg_decode() --> process_decode_queue() 检测到 queue 中包含未处理的 req,进行处理。
其中 MooncakeKVManager 使用的 Mooncake 开源项目,NixlKVManager 使用的 nixl 开源项目。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
05.Mooncake
Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving
https://github.com/kvcache-ai/Mooncake
Mooncake 最新进展:SGLang 和 LMCache 基于 Mooncake 实现高效 PD 分离框架
https://zhuanlan.zhihu.com/p/1906034699358437813
Mooncake (1):在月之暗面做月饼,Kimi 以 KVCache 为中心的分离式推理架构
https://zhuanlan.zhihu.com/p/705754254
Mooncake阅读笔记:深入学习以Cache为中心的调度思想,谱写LLM服务降本增效新篇章
https://zhuanlan.zhihu.com/p/706097807
从MoonCake看大模型推理的PD分离,太快会扯到蛋吗?
https://zhuanlan.zhihu.com/p/8056351077
论文介绍了 Mooncake,这是一个为 LLM 服务设计的 KVCache 中心分布式架构,旨在高效处理高并发请求并满足 SLO。
Mooncake 通过分离预填充和解码集群,利用 GPU 集群中的闲置资源构建分布式 KVCache,并采用 KVCache 中心调度器来优化请求调度。
(1)arxiv
Mooncake 采用分解式架构,不仅将预填充节点与解码节点分离,还将 GPU 集群的 CPU、DRAM、SSD 和 RDMA 资源分组,以实现分解式 KVCache。
这种分解式缓存能够充分利用未充分利用的资源,提供充足的缓存容量和传输带宽,从而实现高效的近 GPU 前缀缓存,而无需额外成本。
论文详细介绍了 Mooncake 架构的设计,该架构以 KVCache 为中心,通过分离预填充和解码集群,并利用 GPU 集群中未充分利用的 CPU、DRAM 和 SSD 资源实现 KVCache 的分布式缓存。
具体方法如下:
分离预填充和解码集群:预填充阶段主要处理输入令牌的并行计算,而解码阶段则逐个处理输出令牌。通过分离这两个阶段,可以针对它们不同的计算特性进行优化。
分布式 KVCache 设计:利用 GPU 集群中的闲置资源构建分布式 KVCache,提高缓存容量和传输带宽,实现高效的近 GPU 前缀缓存。
KVCache 中心调度器:核心是 KVCache 中心调度器(Conductor),它负责根据当前 KVCache 分布和工作负载调度请求,并根据需要复制或交换 KVCache 块。
请求处理流程:对于每个请求,Conductor 选择一对预填充和解码实例,并按照以下步骤调度请求:
KVCache 重用:预填充实例根据请求的前缀缓存块 ID 从远程 CPU 内存加载 KVCache 到 GPU 内存,以启动请求处理。
增量预填充:预填充实例完成预填充阶段,并将新生成的增量 KVCache 存储回 CPU 内存。如果未缓存的输入令牌数量超过一定阈值,则将预填充阶段拆分为多个块,并以流水线方式执行。
KVCache 传输:使用基于 RDMA 的 Messenger 服务在节点间管理和传输这些缓存,将模型各层生成的 KVCache 流式传输到目标解码节点的 CPU 内存,减少等待时间。
解码:解码节点在接收到所有 KVCache 后,将请求加入下一批次进行连续批处理。Conductor 根据当前负载预选解码节点,以确保不违反 TBT SLO。
缓存感知调度:在预填充阶段,调度器会根据请求的前缀缓存匹配长度和实例负载选择预填充实例,以平衡缓存重用和负载均衡。
缓存负载均衡:通过自动复制热点 KVCache 块,将它们分布到多个机器上,以避免缓存获取拥塞。
统计了线上的输入和输出:平均输入长度为 7,590 个 token,平均输出长度为 182 个 token。
比较了三种缓存策略:LRU、LFU 和 LengthAwareCache。
将缓存容量从 1,000 个块增加到 50,000 个块,缓存命中率会从 30% 提升到 50%。继续增加则没有明显改善。
CPP(chunked pipeline parallelism)
输入越来越长,需要做 chunk_prefill,继续提升:对于每个请求,其输入令牌会被划分为多个块,每个块的长度不超过 prefill_chunk。
同一请求的不同块可以由不同的节点同时处理,从而实现并行处理并减少 TTFT。
Layer-wise Prefill
理论上,如果一个请求的 KVCache 大小为 S,处理时间为 T,则其占用成本为 S∗T。
如果在分块预填充中,将请求分块处理,并将每个分块的处理与其他解码请求内联,则 T 会增加,导致占用成本更大。
不同请求长度的 KVCache 存储延迟
- Prefill Global Scheduling
在 Mooncake 中,预填充实例的选择不仅考虑负载,还考虑前缀缓存命中长度以及可重用 KVCache 块的分布。
对于每个新请求,其输入令牌会被分成多个块,并为每个块计算一个哈希键。这涉及生成一个块中令牌的哈希键,该哈希键与前一个块的哈希键(如果可用)连接。
然后将请求的块键与每个预填充实例的缓存键逐一进行比较,以确定前缀匹配长度(prefix_len)。
利用这些匹配信息,Conductor 会根据请求长度和 prefix_len(因实例而异)估算相应的执行时间。
然后,它会添加该请求的预计等待时间,以获得该实例的 TTFT。最后,Conductor 将请求分配给 TTFT 最短的实例,并相应地更新该实例的缓存和队列时间。
Cache Load Balancing
每台预填服务器都管理着自己的一组本地前缀缓存。这些缓存的使用频率差异很大。
解决此 KVCache 调度问题的一个简单解决方案是收集每个块的全局使用情况,使用预测模型预测其未来使用情况,并据此做出调度决策。
如果预估的额外预填充时间短于传输时间,则指挥者会将缓存位置和请求转发到备用实例。此实例会主动从持有者处检索 KVCache 并将其存储在本地。
更重要的是,我们倾向于在最佳远程前缀匹配长度不大于当前本地可重用前缀乘以阈值 1 这两种策略不仅可以减少请求的预填充时间,还可以促进热点缓存的自动复制。
- Early Rejection
预填充或解码实例的负载并不能准确反映系统实际处理的请求数量。这种差异是由于单个请求的预填充和解码实例调度之间存在时间差造成的。
为了解决这个问题,很自然地需要将解码实例的负载评估提前到预填充阶段开始之前。
请求到达后,Conductor 会根据预填充池和解码池中较大的负载来评估是否接受该请求。
早期拒绝(Early Rejection)可以显著减少因被拒绝请求而导致的无效计算,并增强负载均衡。
经过进一步研究,我们发现这种负载波动问题的根源在于预测解码负载与实际执行之间的时间滞后。基于当前解码负载的调度本质上存在延迟。
- 效果测试
每个 node 配置 8 块 NVIDIA-A800-SXM4-80GB GPU,通过 NVLINK 连接;配备 RDMA 网卡,节点间互联带宽最高可达 800Gbps。
Mooncake-[3P+1D] 的吞吐量分别比 vLLM-[4M] 提高了 20% 和 40%,同时满足服务水平目标(SLO)。
尽管 Mooncake-[2P+2D] 拥有较低的 TBT 延迟,但在 TTFT 指标上的表现不如 Mooncake-[3P+1D] 和 vLLM-[4M]。
(2)github 代码框架
Mooncake 由三个主要组件组成,它们协同工作以实现高效的分解 LLM 服务:Transfer Engine、Mooncake Store 和 P2P Store。
Transfer Engine
它通过调度程序架构支持 TCP、RDMA(InfiniBand/RoCEv2)、NVLink 和 NVMe-oF 协议。提供跨多个协议和存储设备的统一、高性能数据传输。
-
多协议支持:根据拓扑和可用性自动选择协议
-
带宽聚合:利用多个 RDMA NIC 设备来提高吞吐量
-
拓扑感知路由:根据 NUMA 关联性和设备位置选择最佳传输路径
-
容错:出现网络错误时自动故障转移到替代路径
- Mooncake Store
专为 LLM 推理工作负载设计的分布式 KVCache 存储引擎:
-
多副本支持:存储同一对象的多个副本,以缓解访问热点
-
并行 I/O:支持大型对象的数据条带化和并行传输
-
内存管理:集成以实现高效的内存段分配
BufferAllocatorManager
-
协调:用于元数据管理和对象生命周期控制
MasterService
P2P Store:为 checkpoint 转移、模型权重分配等场景提供去中心化的临时对象共享。
06.Dynamo/nixl
https://github.com/ai-dynamo/dynamo
怎么看英伟达GTC新发布的推理框架Dynamo
https://zhuanlan.zhihu.com/p/31583638702
Nvidia Dynamo 详解一
https://ata.atatech.org/articles/11020396057?spm=ata.21736010.0.0.675927713lFoan
Dynamo 与推理引擎无关,支持 TRT-LLM、vLLM、SGLang 等,并捕获 LLM 特定的功能。
例如:
-
分解预填充和解码推理:最大化 GPU 吞吐量并促进吞吐量和延迟之间的权衡。
-
动态 GPU 调度:根据波动的需求优化性能。
-
LLM 感知请求路由:消除不必要的 KV 缓存重新计算。
-
加速数据传输:使用 NIXL 减少推理响应时间。
-
KV 缓存卸载:利用多个内存层次结构实现更高的系统吞吐量。
Dynamo 采用了 NIXL 技术,这项技术旨在通过减少同步和智能批处理来加快传输速度。
为了实现最佳性能和可扩展性,Dynamo 充分利用了 Rust 和 Python 的优势。
(1)nixl
https://github.com/ai-dynamo/nixl
NIXL 解决了分布式推理工作负载面临的复杂挑战,尤其是在网络和通信方面。
这些挑战包括高性能要求、跨内存和存储的异构数据路径以及动态扩展的需求。
NIXL 通过支持多个后端插件(如 UCX、GDS 和其他协议)的多功能 API,跨内存类型(HBM、DRAM、本地/远程 SSD)和存储系统提供高带宽、低延迟的点对点数据传输和统一抽象。
NIXL 通过内存部分抽象出各种内存类型,允许跨异构系统进行统一的内存处理。Memory 部分表示可访问以进行数据传输的已注册内存段。
NIXL 目前支持以下后端技术:
-
UCX (Unified Communication X):用于高性能网络的通信框架。
-
GDS (GPUDirect Storage):NVIDIA Magnum IO GPUDirect Storage,用于在 GPU 内存和存储之间直接传输数据。
-
UCX_MO (UCX Memory Operations):UCX 的扩展,专注于内存作。
(2)gdrcopy
GDRCopy 是一个基于 NVIDIA GPUDirect RDMA 技术构建的低延迟 GPU 内存复制库。
它支持从 CPU 直接访问 GPU 内存,与传统的 CUDA 内存操作相比,数据传输延迟显著降低。
-
非常低的开销:GDRCopy 操作由 CPU 驱动,典型操作的开销仅为 0.1-0.2μs,而传统操作的开销为 6-7μs cudaMemcpy。
-
高带宽:在支持的平台上,写入操作(主机到设备)可以达到 6-8 GB/s。
-
直接内存访问:应用程序可以直接读取和写入 GPU 内存,而无需中间复制。
07.测试脚本
vllm
#!/bin/bash
# This file demonstrates the example usage of disaggregated prefilling
# We will launch 2 vllm instances (1 for prefill and 1 for decode),
# and then transfer the KV cache between them.
set -xe
MODEL_NAME=\"/opt/llm/input/pretrain/Qwen--QwQ-32B\"
MAX_MODEL_LEN=32768
GPU_MEMORY_UTILIZATION=0.95
gpu_id_prefill=\"0,1\"
gpu_id_decoder=\"2,3\"
kv_cache_type=\"SharedStorageConnector\" # SharedStorageConnector/ LMCacheConnectorV1 / NixlConnector
# Trap the SIGINT signal (triggered by Ctrl+C)
trap \'cleanup\' INT
export VLLM_HOST_IP=$(hostname -I | awk \'{print $1}\')
# a function that waits vLLM server to start
wait_for_server() {
local port=$1
timeout 1200 bash -c \"
until curl -s localhost:${port}/v1/completions > /dev/null; do
sleep 1
done\" && return 0 || return 1
}
# You can also adjust --kv-ip and --kv-port for distributed inference.
gpu_count_prefill=$(echo \"$gpu_id_prefill\" | tr \',\' \'\\n\' | wc -l)
gpu_count_decode=$(echo \"$gpu_id_decoder\" | tr \',\' \'\\n\' | wc -l)
echo \"Using LMCacheConnectorV1 for kv cache\"
# prefilling instance, which is the KV producer
CUDA_VISIBLE_DEVICES=$gpu_id_prefill python3 -m vllm.entrypoints.openai.api_server \\
--model $MODEL_NAME \\
--disable-log-requests \\
--port 8100 \\
--max-model-len $MAX_MODEL_LEN \\
--gpu-memory-utilization $GPU_MEMORY_UTILIZATION \\
--trust-remote-code \\
--enforce-eager \\
--tensor-parallel-size $gpu_count_prefill \\
--kv-transfer-config \\
\'{\"kv_connector\":\"LMCacheConnectorV1\",\"kv_role\":\"kv_producer\",\"kv_connector_extra_config\": {\"discard_partial_chunks\": false, \"lmcache_rpc_port\": \"producer1\"}}\' &
CUDA_VISIBLE_DEVICES=$gpu_id_decoder python3 -m vllm.entrypoints.openai.api_server \\
--model $MODEL_NAME \\
--disable-log-requests \\
--port 8200 \\
--max-model-len $MAX_MODEL_LEN \\
--gpu-memory-utilization $GPU_MEMORY_UTILIZATION \\
--trust-remote-code \\
--enforce-eager \\
--tensor-parallel-size $gpu_count_decode \\
--kv-transfer-config \\
\'{\"kv_connector\":\"LMCacheConnectorV1\",\"kv_role\":\"kv_consumer\",\"kv_connector_extra_config\": {\"discard_partial_chunks\": false, \"lmcache_rpc_port\": \"consumer1\"}}\' &
# wait until prefill and decode instances are ready
wait_for_server 8100
wait_for_server 8200
python3 disagg_pd_proxy_server.py &
output2=$(curl -X POST -s http://localhost:8000/v1/completions \\
-H \"Content-Type: application/json\" \\
-d \'{
\"model\": \"\'$MODEL_NAME\'\",
\"prompt\": \"hello. Santa Clara is a\",
\"max_tokens\": 10,
\"temperature\": 0
}\')
lmcache 最好从官方 docker 中安装。
sglang
参考:sglang Dense LLM PD 分离部署
https://blog.csdn.net/u013701860/article/details/147745303
同一个 PD 组中,P/D 的 tp_size 需要相同,可以设置多个 P 或者多个 D。
#!/bin/bash
MODEL_NAME=\"Qwen/Qwen3-0.6B\"
MAX_MODEL_LEN=32768
gpu_id_prefill=0,1
gpu_id_decoder=2,3
GPU_MEMORY_UTILIZATION=0.95
# prefill
echo \"async start prefill server.\"
CUDA_VISIBLE_DEVICES=$gpu_id_prefill python3 -m sglang.launch_server --model-path $MODEL_NAME \\
--disaggregation-mode prefill \\
--context-length $MAX_MODEL_LEN \\
--tp-size $gpu_count_prefill \\
--disable-radix-cache \\
--mem-fraction-static $GPU_MEMORY_UTILIZATION \\
--disaggregation-transfer-backend $disaggregation_transfer_backend \\
--trust-remote-code \\
--page-size 16 \\
--port 8100 &
# decoder
echo \"async start decoder server.\"
CUDA_VISIBLE_DEVICES=$gpu_id_decoder python3 -m sglang.launch_server --model-path $MODEL_NAME \\
--disaggregation-mode decode \\
--context-length $MAX_MODEL_LEN \\
--tp-size $gpu_count_decoder \\
--disable-radix-cache \\
--mem-fraction-static $GPU_MEMORY_UTILIZATION \\
--disaggregation-transfer-backend $disaggregation_transfer_backend \\
--trust-remote-code \\
--page-size 16 \\
--port 8200 &
echo \"start schedule server.\"
python3 -m sglang.srt.disaggregation.mini_lb \\
--prefill http://localhost:8100 --decode http://localhost:8200 --host 0.0.0.0 --port 8002 &
# 多个prefill和decoder node 链接:https://blog.csdn.net/u013701860/article/details/147745303
08.结论
1、实测对于超长上下文+大模型+高并发,PD 分离可以始终保持 TBT 在一个很稳定的状态,吞吐量可以提升 20%~50% 不等。
一般来说,至少也要输入>8k、输出>100、并发>10、模型大于 32B 左右,才有一些效果。
2、PD 分离优化的是 TBT,对 TTFT 没有提升。
3、PD 分离时,如果 prefill server 少太多,可能会导致 prefill 阶段的计算能力不够,从而使 TTFT 变慢。因此 M4 改成 3P1D 差不多,2P2D 一般不太行。
4、PD 分离时的 prefill tp_size 和 decoding 的 tp_size 可以不同。server 数量也可以不同。server 数量可以根据流量动态的增加和减少。
5、kv cache 传输人有 GPU、CPU 和 disk 等多种方式,其中 GPU 最快,基本可以保持原本的 TTFT,其他都会导致 TTFT 变慢。
NCCL 需要在初始化时就确定全部的 GPU,因此不适合于规模动态调整的 PD 分离场景,且不支持 cpu 和 disk 传输,Mooncake 在此基础上进行了统一,支持多种传输方式。Dynamo 也重新封装了一层 nixl 传输协议。
6、request 调度是 PD 分离的核心,不能只考虑负载均衡,还要考虑 cache 复用率、显存剩余空间等。
7、PD 分离后,会存在 Prefill server 宽带利用率低,decoder server 的 GPU 利用率低的情况。
NVIDIA Dynamo 的 PD 分离有问题?我们提出的大模型推理系统\"肾上腺素\",是良药!
8、PD 分离适用于 bs 较大、输入、输出都比较长的场景。普通场景没必要折腾。能单卡跑的没必要多卡,能单机承载的没必要多机。
9、PD 分离优势——异构框架:计算性能极强但传输带宽较低的 GPU 进行 prefill,使用计算能力一般但传输带宽很高的 GPU 进行 decoding。这样才能更好的发挥优势。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
一、大模型风口已至:月薪30K+的AI岗正在批量诞生
2025年大模型应用呈现爆发式增长,根据工信部最新数据:
国内大模型相关岗位缺口达47万
初级工程师平均薪资28K
70%企业存在\"能用模型不会调优\"的痛点
真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!
二、如何学习大模型 AI ?
🔥AI取代的不是人类,而是不会用AI的人!麦肯锡最新报告显示:掌握AI工具的从业者生产效率提升47%,薪资溢价达34%!🚀
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
1️⃣ 提示词工程:把ChatGPT从玩具变成生产工具
2️⃣ RAG系统:让大模型精准输出行业知识
3️⃣ 智能体开发:用AutoGPT打造24小时数字员工
📦熬了三个大夜整理的《AI进化工具包》送你:
✔️ 大厂内部LLM落地手册(含58个真实案例)
✔️ 提示词设计模板库(覆盖12大应用场景)
✔️ 私藏学习路径图(0基础到项目实战仅需90天)
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
* 大模型 AI 能干什么?
* 大模型是怎样获得「智能」的?
* 用好 AI 的核心心法
* 大模型应用业务架构
* 大模型应用技术架构
* 代码示例:向 GPT-3.5 灌入新知识
* 提示工程的意义和核心思想
* Prompt 典型构成
* 指令调优方法论
* 思维链和思维树
* Prompt 攻击和防范
* …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
* 为什么要做 RAG
* 搭建一个简单的 ChatPDF
* 检索的基础概念
* 什么是向量表示(Embeddings)
* 向量数据库与向量检索
* 基于向量检索的 RAG
* 搭建 RAG 系统的扩展知识
* 混合检索与 RAG-Fusion 简介
* 向量模型本地部署
* …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
* 为什么要做 RAG
* 什么是模型
* 什么是模型训练
* 求解器 & 损失函数简介
* 小实验2:手写一个简单的神经网络并训练它
* 什么是训练/预训练/微调/轻量化微调
* Transformer结构简介
* 轻量化微调
* 实验数据集的构建
* …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
* 硬件选型
* 带你了解全球大模型
* 使用国产大模型服务
* 搭建 OpenAI 代理
* 热身:基于阿里云 PAI 部署 Stable Diffusion
* 在本地计算机运行大模型
* 大模型的私有化部署
* 基于 vLLM 部署大模型
* 案例:如何优雅地在阿里云私有部署开源大模型
* 部署一套开源 LLM 项目
* 内容安全
* 互联网信息服务算法备案
* …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】