☰
MaaS推理基础设施实战:从模型部署到服务化的关键技术
2026/9/30 5:02:11 网站建设 项目流程

开头

干这行久了,有个很深的感受:一说“AI Infra”,大家第一反应是训练集群、万卡调度,但真正到了推理这一步,画风完全变了。训练再牛,模型最终要以服务的形式跑起来才算落地,这中间的工程问题多到让人头皮发麻——显存怎么分、并发怎么控、延迟怎么压、成本怎么算。我最近梳理了一遍自己做MaaS(Model as a Service,模型即服务)推理基础设施的完整结构,把从模型部署到对外提供服务的整条链路拆开来看,发现很多环节比想象中更考验细节。

这篇博文不聊训练的分布式框架那一套,就聚焦在“推理服务化”这件事上,把AI Infra for Inference的结构从上到下捋一遍。适合正在做模型服务化、推理加速、GPU资源池化,或者准备搭建私有化MaaS平台的团队参考。咱就从用户发来一个请求开始,看这个请求在后台到底经历了什么。

1. 内容整体设计与思路拆解

1.1 MaaS的核心矛盾:不是“能推理”,而是“稳定地、低成本地推理”

先说个经常被低估的事实:把一个大模型跑起来,只要一张能用的GPU就行,哪怕慢点也无所谓。但MaaS要面对的问题远不止于此——你接的是外部流量,有高峰有低谷,有海量并发,也有个别又长又复杂的请求把显存吃穿。真实场景下,一个推理服务至少要过三道坎:

  • 稳定性:单卡挂了不能全站挂,一个请求超时不能拖垮整个Worker进程。
  • 确定性:P99延迟要可控,响应时间抖动不能太大,否则业务方会投诉。
  • 成本:GPU利用率上不去,就是纯烧钱。一个token的边际成本算不清楚,整个定价体系都是空中楼阁。

所以我梳理MaaS结构时,习惯把它分成四层来看:接入与网关层、调度与路由层、执行与引擎层、观测与运维层。这四层各干各的活,又相互咬合。模型推理在整个架构里是核心,但绝不是全部。

1.2 基于nano-vllm入门是最务实的路线

关于“如何上手大模型推理”,我见过很多人一上来就啃vLLM源码,结果被PagedAttention和各种Kernel劝退。我的经验是:先跑通nano-vllm(vLLM的精简教学版),再去看生产级代码。nano-vllm把关键路径抽出来了,包括Continuous Batching、KV Cache管理、Prefix Caching的实现逻辑,用很小的代码量说清楚核心机制,非常适合用来建立推理框架的“工程直觉”。

要理解MaaS,推理引擎的运行机制是地基。先搞懂请求、KVCache、显存管理、Batching策略这几个概念,再看网关、调度、弹性伸缩等外层设施,思路就清晰多了。后面我会用大量篇幅讲这些机制。

2. 核心细节解析与实操要点

2.1 推理引擎选型:vLLM、TensorRT-LLM、SGLang 还是自研?

这一节必须先讲清楚,因为整个MaaS的性能上限由推理引擎决定。市面上的引擎我基本都实际部署过,简单说说感受:

引擎优势适用场景踩坑点
vLLM生态好、吞吐高、易用性强、社区活跃通用对话、RAG、Function Calling长序列场景显存碎片化问题需要调参
TensorRT-LLM单卡性能极致,延迟低对时延敏感的线上SLA业务图编译耗时久、灵活性差
SGLangRadixAttention做Prefix Cache,多轮/多请求复用很猛高并发共享Prompt、Agent类场景新框架迭代快,稳定性要等版本成熟
自研完全可控、可极致定制算子与调度超大厂且场景极其固定成本极高,非必要不碰

选型逻辑很简单:90%的团队直接用vLLM就行,它已经把Continuous Batching、PagedAttention这些核心技术做成开箱即用的方案了。TensorRT-LLM适合那些“硬件型号统一、请求模式稳定、对延迟极度敏感”的纯线上业务。至于自研引擎的前提是——团队有CUDA优化能力,并且业务形态确实超出了开源引擎的优化边界。

2.2 一个请求在引擎内部的完整旅程:从Prefill到Decode

这部分是理解推理Infra的重中之重,所以我会拆得细一点。

假设用户输入“请写一段Python代码计算斐波那契数列”,引擎内部大致发生这些事:

  1. Tokenization:把输入切成Token序列,变成模型的输入向量。
  2. Prefill阶段:一次前向计算,把整段输入并行算完,生成首个输出Token,同时产生KV Cache。这个阶段是计算密集型,GPU算力吃满,吞吐高。
  3. Decode阶段:一个Token一个Token地往后推,每步只输入最近的一个Token,用KV Cache加速上下文计算。这个阶段是访存密集型,瓶颈在显存带宽。
  4. 流式返回:每生成一个Token就通过流式接口返回给用户,这就是为什么你看到ChatGPT打字是一个字一个字蹦出来的。

为什么KV Cache是命门?因为Decode阶段每生成一个Token,都要把之前所有Token的KV Cache读出来算Attention。序列越长,Cache越大,显存占用涨得越快。一个7B模型,FP16权重只要14GB,但一个1K长度的请求叠加16个并发,KV Cache就能占到好几个GB。这也是为什么我们要引入PagedAttention和显存管理。

实操要点一:显存分配不要贪心很多人以为模型的KV Cache显存池越大越好,实际上留太小会频繁触发换入换出(Swap),留太大又压缩了并发上限。我常用经验值是:KV Cache显存 = 总显存 - 模型权重大小 - 激活值预留(通常1-2GB) - 计算储备。具体用gpu_memory_utilization参数控制在0.85到0.92之间,先跑压测再微调。

2.3 Continuous Batching和PagedAttention:吞吐翻倍的功臣

传统Batching是等一批请求都处理完再开下一批,很蠢——只要有一个长请求没走完,同批的短请求只能干等。Continuous Batching(持续批处理)的做法是:批内任何一个请求生成完毕后,立刻插入新请求。这样GPU始终在干活,不会出现“等最后一个长尾”的情况。

衡量这个逻辑有没有做对,看一个指标——MJ/s(每GPU每秒生成的百万token数)。在长尾请求场景下,Continuous Batching能让吞吐量提升2到3倍,这是MaaS盈利模型能不能成立的核心变量。

PagedAttention则是把KV Cache切成分页(Page)来管理,类似操作系统的虚拟内存分页。不必给每个请求提前分配连续的最大长度空间,而是按页动态分配。缺页时还能从CPU内存换入换出。这让显存利用率大幅上升,vLLM在长序列场景下还能保持稳定。

实操要点二:Prefix Caching别忽略对于RAG系统,用户问的问题前缀经常是固定的系统Prompt(“你是AI助手...”、“请基于以下文档回答...”)。启用Prefix Caching(前缀缓存)后,重复前缀的KV Cache直接跳过Prefill重算,能省下30%-50%的首Token延迟。vLLM里配置enable_prefix_caching=true即可。代价是前缀的LRU淘汰策略要观察,Cache命中和业务问法强相关,别盲目开。

3. 实操过程与核心环节实现

3.1 平台整体架构设计:从网关到GPU池

讲完引擎层,再往上一层看MaaS平台的健壮性。项目里我的典型架构是这样:

Client → API Gateway → Router/Scheduler → Engine Pool (vLLM/TensorRT-LLM Workers) ↓ Metrics/Logging/Monitoring

网关层:负责鉴权、限流、计费、请求灰度。这是MaaS的入口,也是商业化的第一道防线。常见做法是OpenResty或Go写的轻量网关,统一处理Token计量。

路由与调度层:这个是AI Infra for推理和普通后端服务最大的分水岭。调度器要懂模型,要知道哪些GPU上跑了哪个模型、剩余显存多少、当前并发多少,然后把新请求送到最优的Worker上。我常用的调度策略有三种:

策略逻辑适用场景
Round-Robin轮询分发同模型多副本,负载均匀
Least-Connections按当前请求数最少分发请求长短差异大的场景
Load-Aware按GPU利用率/显存余量动态分发异构GPU池、混布场景

想省事就直接用KServe或Serving框架自带的Router,但到了规模后,还是得自己写调度器。毕竟只有自己最清楚业务的请求画像。

3.2 GPU显存管理与弹性伸缩:算力资源池化

推理场景下GPU很贵,不能让每个模型固定独占一张卡。我在项目里用到的资源池化方案是:模型分片部署 + 显存超卖 + 弹性收缩。

先说显存超卖。一个模型实际部署时KV Cache是动态增长的,但峰值显存需求并不总是满载。可以在系统层面设置enable_gpu_memory_utilization为一个安全上限,但实际请求并发跑不满,剩下的显存可以临时跑小模型任务。这里要特别小心显存溢出把Worker炸掉,所以需要精细化记账:

  • 每个Worker启动时记录基础显存占用(模型权重+静态结构)
  • 运行时按请求池状态的增减实时更新剩余显存
  • 新任务申请前检查“剩余显存 > 峰值需用 + 20%缓冲”,否则不调度

再说弹性伸缩。MaaS流量潮汐效应非常明显,白天上班高峰、晚上和周末下降。我们做了按请求量自动扩缩容:指标触发为GPU利用率 > 70%持续5分钟扩容一个副本,GPU利用率 < 25%持续30分钟缩容一个副本。缩容前要保证当前Worker上的请求全部排空,否则会有大量超时。

3.3 推理任务的加速细节:从量化到算力换速度

推理加速的手段很多,但有一条原则贯穿始终:延迟和成本不可兼得,必须在业务SLA下做权衡。

量化是降本提效的第一步。从FP16到INT8,显存立减一半,吞吐最高能提升60%-80%。如果对精度要求不那么苛刻的模型,AWQ或GPTQ量化是首选。4-bit量化虽然能进一步压显存,但实测下来某些模型的推理质量会掉,特别是数学、代码类场景,建议先跑一遍评测集再上。

我常用的量化选型参考:

模型量级推荐量化显存节省精度损失
7B-13BFP16/INT80-50%几乎没有
13B-70BINT8/AWQ50%-75%可接受
70B以上AWQ/GPTQ 4-bit80%-90%需业务侧验证

还有一个容易忽略的点:Batch Size与模型并发的匹配。推理引擎里的max_num_seqs、max_num_batched_tokens这些参数直接影响吞吐。我在7B模型上实测,max_num_seqs=256时P99延迟能控制在1.5秒内,吞吐比默认配置高45%左右,但显存压力也更大,得对着监控逐步上调。

3.4 Serving框架与API设计细节

一个成熟的MaaS平台,对外API要支持的参数远不止model和prompt。我这边实际开放的能力包括:

  • 流式与非流式:所有模型必须支持stream=true,否则用户感知“打字机效果”就没有了,长文本场景超时风险也大。
  • 参数透传:temperature、top_p、max_tokens这些基础参数要透传到引擎。
  • 结构化输出:支持JSON Mode和Function Calling——这是Agent类应用的刚需,底层要用到guided decoding,对延迟有影响。
  • 自定义停词:业务方常要求“输出到某个词就停止”,这些做在网关层统一处理,不侵入引擎。
  • 排队与超时:高峰期不能让请求直接失败,要有排队机制和明确的超时反馈。我这里的逻辑是:排队超过10秒就拒绝并返回503,让客户端自动重试。

实操要点三:长连接别全链路开流式接口用WebSocket或SSE时,网关到引擎之间千万注意连接池大小。我踩过一个坑:网关开500个连接,引擎只配了256个并发槽位,结果大量连接处于半开状态,P99直接飙到10秒。后来改成“网关无状态转发 + 引擎从连接池取连接”就好多了。

4. 常见问题与排查技巧实录

4.1 排查问题的方法论:先测引擎,再查平台

我自己调试MaaS平台有一套固定流程,能省下大量时间:

  1. 先直连引擎测:绕过网关和调度器,用vllm serve或在代码里直接调用引擎接口,定位问题在引擎还是平台其他层。这一步能在五分钟内排除掉80%的干扰项。
  2. 再压测网关:用Locust或wrk单独打网关,看会不会引入额外延迟。重点看网关有没有超时截断、重试风暴、连接复用失效。
  3. 最后观测调度决策:查日志,看请求被调度到哪个Worker、当时的显存和并发快照是否有问题。
  4. 全程看监控:没有Prometheus+Grafana这套的话,几乎没法排查。必须埋的指标:PV、UV、请求延迟分位(TP50/TP99/TP999)、GPU利用率/显存/温度、KV Cache命中率、排队等待时长、请求拒绝率。

4.2 经典报错与对应解法速查表

现象根因解决方式
CUDA OOMKV Cache池过大或并发暴涨降gpu_memory_utilization;限流接入层;检测并发护栏
首Token延迟飙升Prefill计算过长或Prefix Cache未命中开启前缀缓存;限制单请求输入长度;对超长prompt拆分
长时间卡顿后超时Decode阶段单批过长检查max_num_batched_tokens;开启Continuous Batching
生成质量突然下降量化精度受损回退FP16;量化前跑评测集
多卡设备利用率不均调度策略与模型放置不均匀手动绑定模型到卡;调研设计负载感知调度
Worker内存上涨无法回收长连接泄漏检查连接池生命周期设置;加入max_requests周期性重启Worker
部分请求流式输出中断网络层缓冲导致连接被切断检查代理缓冲区,配置SSE event的flush节拍

4.3 一个真实案例分析:混布场景下显存“吸血鬼”

有一次,平台同时部署了三个模型,其中一个是13B的代码模型,另外两个是7B的对话模型。跑着跑着,突然代码模型的P99延迟从1.2秒飙到4.5秒,而且一查GPU显存,代码模型Worker的显存占用一直在涨。

排查过程:先按前面说的方法直连代码模型引擎,延迟正常。回到调度器看日志,发现有一个7B模型的请求被调度到了代码模型所在的卡上,因为这块卡“剩余显存”刚好够。问题出在7B模型压进来的那一刻,把KV Cache池的剩余页挤掉了,代码模型开始频繁做Swap换页,全卡性能骤降。

解法就是严格的“卡级隔离 + 显存超售阈值收紧”:同卡只能跑同优先级的服务模型,异模型混布时剩余显存阈值从20%提高到40%。这个案例再次验证了那句话——调度上的宽松,最终代价都是延迟和稳定性。

5. 资源与成本的量化分析

5.1 推理成本怎么算才准?

很多团队算推理成本只算GPU租赁费,这是不对的。实际成本包含五块:

  • 硬件成本:GPU服务器折旧/租赁(大头)
  • 电力成本:单卡功耗按300W算,实际机柜还有散热开销
  • 工程成本:运维、MLOps、调参的人力分摊
  • token成本:输入和输出Token都消耗时间与显存,输出Token更贵(因为Decode慢)
  • 失败成本:超时重试、排队等待、坏掉的请求占用的资源

成本计算公式我习惯按“单个请求的边际成本=GPU单卡时成本×请求占用时长”,然后向上取整到“每百万Token成本”做定价。一个典型例子:8卡A100集群跑一个70B模型,月成本约5万(含电力和运维),日均处理1000万输入Token、300万输出Token,摊下来每百万输出Token成本约20元左右。定价低于这个数,就是亏本做慈善了。

5.2 提效与降本的实操经验总结

从实际操作角度,四个最有效的降本动作:

  1. 模型瘦身:蒸馏+量化双管齐下。能用7B,不跑13B;能用INT8,不上FP16。
  2. Batch优化:调大max_num_seqs,把GPU的算力和带宽榨干。前提是显存管得住。
  3. 负载转移:Prefix Cache的复用率做上去后,大量Prompt直接跳过Prefill计算,成本下降立竿见影。
  4. 缩容策略:非高峰时段直接停止副本,切到Serverless模式——VLM的镜像能秒级起。

实操要点四:利用率不是越高越好GPU利用率在95%以上看着爽,但这时候延迟曲线通常已经翘尾了。我一般把长稳态目标放在70%-85%。太低是浪费钱,太高是拿延迟换成本效率,业务SLA会出事。

6. 写在最后的一个经验

这些年在推理侧做Infra,心里最深的一个体会是:AI Infra for推理的复杂度是系统的,不是单点的。引擎再快,网关和调度拖后腿,用户体验还是烂;显存算得再精,业务请求一乱,照样OOM。要从整体去看整条链路,哪里是瓶颈就补哪里,而不是迷信某个“神奇参数”。

还有一个不得不提的细节:日志和监控一定从第一天就做。很多平台上线后才发现上线的推理服务像“黑盒”,出了事故只能靠猜。我经历过一个凌晨事故——新版本的推理引擎在某种Transformer结构下会出现偶发死锁,没有完善的消息队列和心跳监控,根本定位不到。后来我们给每个Worker加了心跳和请求级全链路Trace,这类问题基本都能在五分钟内圈定范围。

最后分享一个小技巧:如果你刚开始搭建推理MaaS,不要一上来就追求全功能。先把“单模型、单卡、稳定服务”这条最小闭环跑通,再逐步加多模型、多卡、弹性伸缩、租户隔离。一口吃不成胖子,把地基打扎实了,后面加什么功能都顺。这套结构梳理到这里,希望能帮正在做这个方向的你少走一点弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询