news 2026/6/26 2:01:04

大模型推理部署:从单卡到集群的工程化落地路径

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大模型推理部署:从单卡到集群的工程化落地路径

大模型推理部署:从单卡到集群的工程化落地路径

一、LLM 推理上线的三座大山:延迟、吞吐与显存

将一个大语言模型从实验环境推向生产环境,面临的第一个现实问题就是 GPU 显存。一个 70B 参数的模型,FP16 精度下需要约 140GB 显存,单张 A100(80GB)根本装不下。即使采用 INT4 量化,仍需约 35GB,加上 KV Cache 和运行时开销,单卡推理的并发能力极其有限。

某智能客服平台上线 LLM 服务后,发现单卡 A100 在并发 10 个请求时 P99 延迟已达 8 秒,用户等待超时率超过 30%。更棘手的是,不同请求的 prompt 长度差异巨大,短 prompt 推理 200ms 完成,长 prompt 需要 5 秒,混合调度导致短请求被长请求阻塞。LLM 部署不是简单的模型加载,而是一套涉及显存管理、请求调度、模型并行的系统工程。

二、LLM 推理引擎的架构设计

2.1 推理服务整体架构

graph TD A[API Gateway] --> B[请求调度器] B --> C[Prompt长度预估] B --> D[优先级排序] B --> E[批处理组装] E --> F[推理引擎] F --> G[模型并行层] G --> G1[TP: 张量并行] G --> G2[PP: 流水线并行] F --> H[KV Cache管理器] H --> H1[PagedAttention] H --> H2[显存池化复用] F --> I[量化与加速] I --> I1[INT8/INT4量化] I --> I2[FlashAttention] I --> I3[Continuous Batching] B --> J[推理节点集群] J --> J1[Node-1: 7B模型] J --> J2[Node-2: 70B模型-TP4] J --> J3[Node-3: 13B模型]

2.2 KV Cache 与显存管理

sequenceDiagram participant R1 as 请求1 participant R2 as 请求2 participant PM as PagedAttention管理器 participant VRAM as GPU显存 R1->>PM: 申请KV Cache(预估token=512) PM->>VRAM: 分配4个物理页(每页128token) PM-->>R1: 返回页表映射 R2->>PM: 申请KV Cache(预估token=256) PM->>VRAM: 分配2个物理页 PM-->>R2: 返回页表映射 Note over PM: 请求1生成超过512 token<br/>动态追加物理页 R1->>PM: 追加KV Cache PM->>VRAM: 再分配1个物理页 PM-->>R1: 更新页表映射 Note over PM: 请求2完成<br/>释放物理页供复用 R2->>PM: 释放KV Cache PM->>VRAM: 物理页归还显存池

PagedAttention 借鉴操作系统的虚拟内存分页机制,将 KV Cache 按固定大小的物理页管理,不同请求的 KV Cache 不需要连续显存,极大降低了显存碎片化问题。

三、生产级 LLM 推理服务实现

3.1 Continuous Batching 调度器

""" Continuous Batching 调度器 核心思想:不等整个batch完成,已完成请求立即移出,新请求动态加入 相比static batching,吞吐量提升2-4倍 """ import time import threading from collections import deque from dataclasses import dataclass, field from typing import List, Optional @dataclass class InferenceRequest: """推理请求封装""" request_id: str prompt_tokens: List[int] max_new_tokens: int = 512 temperature: float = 0.7 # 运行时状态 generated_tokens: List[int] = field(default_factory=list) kv_cache_pages: List[int] = field(default_factory=list) is_completed: bool = False submit_time: float = field(default_factory=time.time) class ContinuousBatchScheduler: """ 连续批处理调度器 核心机制:每个推理步完成后,移出已完成请求,从等待队列补充新请求 """ def __init__(self, max_batch_size: int = 32, max_waiting_queue: int = 1000): self.max_batch_size = max_batch_size self.max_waiting_queue = max_waiting_queue # 等待队列:按提交时间排序 self.waiting_queue: deque[InferenceRequest] = deque(maxlen=max_waiting_queue) # 当前活跃batch self.active_batch: List[InferenceRequest] = [] # 已完成请求的结果暂存 self.completed_results: dict[str, List[int]] = {} self._lock = threading.Lock() def submit_request(self, request: InferenceRequest) -> bool: """提交推理请求到等待队列""" with self._lock: if len(self.waiting_queue) >= self.max_waiting_queue: return False # 队列已满,拒绝 self.waiting_queue.append(request) return True def schedule_batch(self) -> List[InferenceRequest]: """ 调度下一批推理请求 1. 移出已完成请求 2. 从等待队列补充新请求到max_batch_size 3. 返回当前活跃batch """ with self._lock: # 移出已完成的请求,释放其资源 remaining = [] for req in self.active_batch: if req.is_completed: self.completed_results[req.request_id] = req.generated_tokens else: remaining.append(req) # 从等待队列补充新请求 available_slots = self.max_batch_size - len(remaining) for _ in range(min(available_slots, len(self.waiting_queue))): new_req = self.waiting_queue.popleft() remaining.append(new_req) self.active_batch = remaining return self.active_batch def get_result(self, request_id: str) -> Optional[List[int]]: """获取已完成请求的结果""" with self._lock: return self.completed_results.pop(request_id, None) def get_metrics(self) -> dict: """获取调度器运行指标""" with self._lock: return { "waiting_queue_size": len(self.waiting_queue), "active_batch_size": len(self.active_batch), "completed_count": len(self.completed_results), "utilization": len(self.active_batch) / self.max_batch_size if self.max_batch_size > 0 else 0, }

3.2 模型并行加载管理器

""" 张量并行(Tensor Parallelism)加载管理器 将模型权重按列或行切分到多张GPU,协同推理 """ import torch import torch.distributed as dist class TensorParallelLoader: """ 张量并行模型加载器 支持将Transformer层权重按列切分到多卡 """ def __init__(self, model_config: dict, tp_size: int = 4): self.tp_size = tp_size # 张量并行度 self.tp_rank = None # 当前进程的并行秩 self.model_config = model_config # 初始化分布式进程组 if dist.is_initialized(): self.tp_rank = dist.get_rank() else: self.tp_rank = 0 def load_sharded_weight(self, weight_path: str, layer_name: str) -> torch.Tensor: """ 加载分片权重:每个GPU只加载属于自己的分片 避免全量加载导致单卡OOM """ # 读取权重元数据,确定切分维度 full_weight = torch.load(weight_path, map_location="cpu") weight_tensor = full_weight[layer_name] if "column" in layer_name or "gate" in layer_name: # 列切分:按输出维度切分,每个GPU持有1/tp_size的列 shard = torch.chunk(weight_tensor, self.tp_size, dim=0)[self.tp_rank] elif "row" in layer_name or "down" in layer_name: # 行切分:按输入维度切分 shard = torch.chunk(weight_tensor, self.tp_size, dim=1)[self.tp_rank] else: # 不切分的权重(如LayerNorm),每卡持有完整副本 shard = weight_tensor # 释放全量权重,节省CPU内存 del full_weight return shard.cuda() def all_reduce_output(self, tensor: torch.Tensor) -> torch.Tensor: """ 张量并行的输出归约:行切分层需要AllReduce求和 确保多卡结果一致 """ if self.tp_size <= 1: return tensor dist.all_reduce(tensor, op=dist.ReduceOp.SUM) return tensor

四、LLM 部署的架构权衡

4.1 量化精度与推理质量的博弈

INT4 量化将显存需求降低至 FP16 的 1/4,但对模型能力有不可忽视的损伤。在代码生成和数学推理任务上,INT4 量化的 70B 模型可能不如 FP16 的 13B 模型。GPTQ/AWQ 等算法通过校准数据集优化量化参数,在多数场景下可将精度损失控制在 1-2%,但在长文本生成和低资源语言场景下退化明显。

4.2 TP vs PP 的选择

张量并行(TP)将单层计算切分到多卡,通信量大但延迟低,适合节点内多卡;流水线并行(PP)将不同层分配到不同卡,通信量小但存在气泡,适合跨节点部署。生产中通常混合使用:节点内 TP,节点间 PP。

4.3 推理与训练的资源冲突

GPU 集群同时承载训练和推理任务时,训练任务的显存占用波动大,可能导致推理服务 OOM。解决方案是物理隔离推理与训练 GPU 池,或通过 Kubernetes GPU 优先级抢占确保推理服务的显存保障。

4.4 禁用场景

  • 请求量极低(<10 QPS)的内部工具,单卡部署即可满足
  • 对延迟不敏感的离线批处理推理,无需 Continuous Batching
  • 模型参数量小于 7B,单卡即可高效推理

五、总结

LLM 推理部署是一项从显存管理到请求调度的系统工程。PagedAttention 解决了 KV Cache 的显存碎片问题,Continuous Batching 显著提升了推理吞吐,张量并行与流水线并行使得大模型跨卡部署成为可能。架构选型时需在量化精度与显存节省、并行策略与通信开销、推理延迟与吞吐量之间做出精准权衡,核心原则是:根据模型规模、流量特征和 SLA 要求,选择最小复杂度的部署方案。

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

第八次作业

可以在这个页面上进行增删改查 增加图书 删除图书

作者头像 李华
网站建设 2026/6/26 1:58:35

NXP传感器在智能家居中的工程实践:从原理到应用

1. 智能家居的“感官”&#xff1a;为什么传感器是基石在智能家居这个庞大的系统中&#xff0c;我们常常关注那些看得见、摸得着的“大脑”和“四肢”——比如智能音箱、手机App、自动窗帘电机。但真正让这个系统“活”起来&#xff0c;能感知环境、理解状态、做出反应的&#…

作者头像 李华
网站建设 2026/6/26 1:56:37

如何删除系统旧盘EFI引导分区

此环境基于windowskali双系统环境。 1.管理员运行cmd,输入bcdedit /enum firmware 查看固件引导项&#xff0c;找到你的另一个系统&#xff08;如kali)的引导标识符&#xff0c;然后bcdedit /delete {标识符} 2.清理EFI系统分区中的残留文件。 &#xff08;1&#xff09;挂载…

作者头像 李华
网站建设 2026/6/26 1:55:08

AI 生成 UI 的质量评测:从像素对齐到交互一致性的多维评估框架

AI 生成 UI 的质量评测&#xff1a;从像素对齐到交互一致性的多维评估框架 一、AI 生成 UI 的评测困境——"看起来像"不等于"用起来对" 当 AI 从设计稿生成前端代码时&#xff0c;传统的"肉眼比对"评测方式暴露出严重不足。某次评测中&#xff0…

作者头像 李华
网站建设 2026/6/26 1:51:55

产线柔性化改造中的视觉系统设计:让一条线干十种活

柔性视觉系统的设计要点硬件模块化设计采用快拆式相机支架和光源模组&#xff0c;支持电动调节与自动切换。相机位置、光源参数通过伺服电机或气动元件实现程控化调整&#xff0c;硬件换型时间可压缩至3分钟内。零点定位夹具系统确保重复定位精度5μm&#xff0c;避免机械校准耗…

作者头像 李华
网站建设 2026/6/26 1:50:31

抖音无水印下载终极指南:3分钟搞定批量下载与智能管理

抖音无水印下载终极指南&#xff1a;3分钟搞定批量下载与智能管理 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…

作者头像 李华