尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

大模型推理服务性能优化:从5万到2000万日调用的生产级实践

大模型推理服务性能优化:从5万到2000万日调用的生产级实践 1. 项目概述从概念验证到生产级服务的挑战去年年初我们团队接手了一个内部大模型应用项目最初它只是一个供几十个研发同事“尝鲜”的玩具。那时的架构简单粗暴一台搭载了A100的GPU服务器上面跑着一个用FastAPI写的简单封装后端挂载着一个7B参数的模型。日均调用量大概在5万次左右P99延迟虽然不太稳定但大家觉得“能跑就行”。然而随着产品正式上线和用户量的指数级增长这个“玩具”很快变成了整个系统的性能瓶颈。调用量在三个月内冲到了日均2000万次原有的服务在高峰时段频繁超时、崩溃用户体验直线下降。我们面临的核心矛盾非常典型如何在有限的硬件资源和急剧增长的用户请求之间找到平衡点保证服务的高可用、低延迟和高吞吐这不是简单地加机器就能解决的问题。大模型推理本身是计算和内存密集型的每一次生成Generation都伴随着巨大的计算图和显存操作。从5万到2000万这400倍的量级跃迁逼迫我们必须从“写一个能跑的Demo”的思维转向“构建一个生产级的推理服务平台”的性能工程思维。这涉及到从模型加载、请求调度、批处理优化、内存管理到监控告警的全链路深度重构。接下来的内容就是我作为这个项目的核心负责人在过去一年里带领团队将这套大模型推理服务从濒临崩溃的边缘优化到能够稳定支撑日均2000万次调用、P99延迟控制在可接受范围内的完整实践记录。我会避开那些空洞的理论直接分享我们踩过的坑、验证过的方案以及那些真正起效的“黑科技”。2. 性能瓶颈全景诊断找到真正的“慢”在动手优化之前盲目调整参数和架构是致命的。我们做的第一件事就是像医生一样对系统进行了一次全面的“体检”建立完整的性能画像Performance Profiling。这个过程让我们发现问题远比表面看到的“服务器CPU/GPU跑满了”要复杂。2.1 核心指标体系的建立我们首先定义了衡量推理服务健康度的核心黄金指标Golden Signals吞吐量Throughput每秒处理的请求数RPS或每秒生成的Token数TPS。这是容量规划的基础。延迟Latency特别是P50、P90、P99和P999千分位延迟。P99延迟是衡量用户体验和系统稳定性的关键它反映了长尾请求的糟糕程度。错误率Error Rate非200状态码的请求比例包括超时、模型加载失败、显存不足OOM等。资源利用率Resource UtilizationGPU利用率、GPU显存使用率、CPU利用率、系统内存使用率。这里有个关键认知GPU利用率高不等于性能好它可能意味着计算效率低下或存在阻塞。我们使用PrometheusGrafana搭建了监控大盘并通过在服务代码中埋点精细采集了每个阶段的耗时比如请求排队时间、预处理时间、模型计算时间可细分为Attention、FFN等、后处理时间、Token生成时间序列等。2.2 初期架构的瓶颈分析通过一周的监控数据分析和py-spy、NVIDIA Nsight Systems、torch.profiler等工具进行现场 profiling我们揪出了以下几个核心瓶颈瓶颈一串行处理与“空跑”的GPU。最初的服务是单进程单线程每个请求独占GPU进行计算。这意味着当一个请求在生成下一个Token时GPU的算力被完全占用但显存中的大部分数据如KV Cache可能只为这一个请求服务其他请求只能在队列中干等。GPU的算力利用率曲线呈“锯齿状”大量时间花在了等待I/O网络收发、数据加载和上下文切换上。瓶颈二动态批处理Naive Batching的缺失。没有批处理就无法利用GPU的并行计算能力处理多个请求。这是初期吞吐量无法提升的根本原因。瓶颈三显存管理的“野蛮生长”。每个请求独立加载模型权重尽管是同一份并且KV Cache随着生成长度线性增长缺乏有效的回收和共享机制。这导致在并发稍高时极易触发OOM服务直接崩溃。瓶颈四网络与序列化开销。我们的服务部署在Kubernetes集群通过负载均衡器如Nginx暴露。每个请求/响应的JSON序列化/反序列化以及网络传输在超高QPS下成为了不可忽视的开销。特别是在生成长文本时响应体巨大。瓶颈五冷启动与模型加载。每次服务发布或扩缩容加载一个几十GB的大模型到GPU显存需要数分钟这期间服务不可用造成流量损失。诊断结论是我们的系统不是一个“慢”的系统而是一个“低效”的系统。GPU这个最昂贵的资源大部分时间都在“磨洋工”。优化方向很明确想尽一切办法让GPU“忙”起来并且是高效地“忙”。3. 核心优化策略让GPU“饱和”工作基于诊断结果我们制定并实施了分阶段的优化策略。这些策略环环相扣共同作用才实现了质的飞跃。3.1 策略一拥抱动态批处理与连续批处理这是提升吞吐量最有效的一招。我们放弃了请求独占GPU的模式引入了动态批处理Dynamic Batching。原理与实现我们部署了一个推理服务器如vLLM或TGI它们内置了高效的调度器。当请求到达时调度器不会立即执行而是将其放入一个队列等待一个很短的时间窗口例如10-50毫秒。在这个窗口内到达的、具有相似参数如相同的模型、采样参数的请求会被动态地组合成一个批次Batch然后一次性送入GPU进行计算。为什么选择vLLM在对比了多个方案后我们选择了vLLM。它的核心优势在于PagedAttention算法这个我们后面会细说。但就批处理而言vLLM的调度器非常高效能实现接近零开销的请求排队和批次组建。我们实测在相同硬件和模型下从无批处理切换到vLLM的动态批处理吞吐量直接提升了8-10倍。连续批处理Continuous Batching的威力传统的批处理要求一个批次内的所有请求同时开始、同时结束。这对于生成任务极不友好因为每个请求的生成长度输出Token数差异巨大。让一个生成了10个Token的请求等待另一个生成了100个Token的请求是巨大的浪费。 vLLM和TGI实现了连续批处理。当一个批次中某个请求生成完毕如达到最大长度或遇到停止符它可以立即被“释放”出批次并将该请求占用的计算资源特别是KV Cache空间腾出来。同时调度器可以立即将队列中一个新的请求“插入”到这个刚刚空出的槽位加入当前正在进行的批次中。这样GPU的计算流水线几乎永远不会中断实现了极高的资源利用率。实操心得设置合适的max_batch_size和调度等待时间scheduler_delay是个平衡艺术。max_batch_size太大可能导致OOM或单个请求延迟激增太小则无法充分利用GPU。我们的经验是从一个保守值开始如8根据监控的GPU利用率和P99延迟逐步调优。调度等待时间通常设置在20ms左右在延迟和吞吐之间取得较好平衡。3.2 策略二实施PagedAttention与显存优化显存是比算力更紧俏的资源。大模型推理的显存占用主要来自两部分模型权重和KV Cache。对于7B~70B的模型在FP16精度下权重可能占用14GB到140GB显存。而KV Cache的占用与批次大小batch size和序列长度sequence length成正比。KV Cache的爆炸性增长在自回归生成中为了计算下一个Token模型需要缓存之前所有Token的Key和Value状态。对于Batch Size为B序列长度为L层数为N注意力头数为H每个头维度为D的模型KV Cache的显存占用大约是2 * B * L * N * H * D * sizeof(dtype)。这非常可观。例如一个13B模型N40 H40 D128处理批次为8、序列长度为2048的请求FP16下的KV Cache就可能占用近10GB显存。vLLM的PagedAttention这是游戏规则改变者。它受操作系统虚拟内存分页机制的启发将每个请求的KV Cache在物理显存中划分为固定大小的“块”Block例如16个Token一个块。这些块不需要连续存储。每个请求维护一个逻辑上的“块表”记录它使用了哪些物理块。优势一消除显存碎片。传统方式下不同长度的请求会导致显存中出现大量无法利用的碎片。PagedAttention通过小块分配实现了高效的显存复用。优势二高效共享。在并行采样如Beam Search或多轮对话将历史对话作为前缀场景中不同序列间可能共享大量的前缀Token。PagedAttention可以物理上只存储一份共享前缀的KV Cache多个逻辑序列通过块表指向它避免了重复存储有时能节省90%以上的相关显存。我们的实践启用vLLM后我们同样配置的A100服务器能够支持的并发请求数即有效Batch Size提升了3-5倍OOM错误几乎消失。这是支撑2000万日调用的基石。3.3 策略三量化与模型压缩当批处理和显存优化做到极致后模型权重本身的大小就成了瓶颈。为了在单张GPU上服务更大的模型或支撑更大的批次我们引入了量化。量化方案选型FP16/BF16基线保持最佳精度显存占用大。INT8权重量化将模型权重从FP16转换为INT8显存占用减半推理速度提升明显。通常使用bitsandbytes库实现。这对大多数任务精度损失可接受。GPTQ/AWQINT4/INT8更激进的量化方法。GPTQ是对权重进行逐层量化AWQ则通过分析激活分布来保护重要的权重通道。INT4量化能将显存占用降至FP16的1/4使得在24GB显存的消费级显卡上运行70B模型成为可能。SmoothQuant一种将激活的量化难度转移到权重上的技术使得模型在INT8下同时量化权重和激活获得更好的端到端加速。我们的选择路径我们采取了渐进式策略。首先对所有生产模型统一使用FP16确保基线精度。对于延迟敏感但吞吐要求不极致的在线服务尝试并上线了W8A8权重INT8激活INT8的SmoothQuant版本在精度损失0.5%的情况下获得了近2倍的推理速度提升。对于内部的一些工具类、对精度容忍度较高的场景我们测试了AWQ INT4量化显存节省了75%速度也有提升但需要仔细评估下游任务效果。注意事项量化不是无损的必须进行严格的评估。我们建立了自动化的评估流水线在量化后在多个下游任务如问答、摘要、代码生成的测试集上对比量化模型与原始模型的性能差异只有满足预设阈值如准确率下降不超过1%的量化模型才会被部署。3.4 策略四计算图优化与内核融合GPU擅长大规模并行计算但频繁启动大量的小型计算内核Kernel会导致严重的启动开销。框架默认的算子实现可能并非最优。使用TensorRT-LLM或FasterTransformer这些是NVIDIA推出的针对LLM推理的高度优化库。它们会对整个Transformer计算图进行编译优化包括算子融合Kernel Fusion将多个连续的小算子如LayerNorm、GeLU、矩阵乘加融合成一个大的CUDA内核减少内核启动次数和全局内存访问。针对性的内核优化使用高度优化的、手写的CUDA内核来替代框架如PyTorch的通用实现尤其针对Attention和激活函数。内存布局优化将Tensor在内存中的排列方式调整为对GPU缓存更友好的格式如Channel Last。我们的实践对于追求极致性能的固定模型我们使用TensorRT-LLM进行编译部署。编译过程可能需要数小时但生成的是一个高度优化的、序列化后的引擎Engine文件。部署时直接加载这个引擎推理速度相比原始PyTorch模型有显著提升在某些场景下可达50%以上。但它的缺点是灵活性差任何模型结构的改动都需要重新编译。更灵活的选择PyTorch 2.x 的torch.compile与scaled_dot_product_attention对于需要快速迭代模型的场景我们采用PyTorch 2.x的原生优化。使用torch.compile(model, modemax-autotune)对模型进行即时编译JIT可以自动进行图优化和内核融合。同时确保使用PyTorch内置的、经过高度优化的F.scaled_dot_product_attention函数它利用了FlashAttention等先进算法大幅提升了Attention计算效率。4. 系统工程与架构演进单点优化再强没有稳健的系统和架构支撑也无法应对日均2000万次的洪流。我们在系统层面做了大量工作。4.1 服务化与API网关设计我们摒弃了直连推理服务器的模式构建了清晰的三层架构API网关层使用Kong或Apache APISIX。负责鉴权、限流、熔断、负载均衡、请求路由、监控数据采集。所有客户端请求首先到达网关。限流我们实现了基于用户/API Key的分级限流防止恶意请求打垮后端。熔断当某个后端推理实例错误率超过阈值时网关自动将其熔断待其恢复后再逐步放量。推理服务层即运行vLLM/TGI的实例池。每个实例承载一个模型的一个版本。我们通过Kubernetes Deployment进行管理并配置了HPA水平Pod自动扩缩容根据GPU利用率或请求队列长度自动扩缩容。模型管理层一个独立的服务负责模型的版本管理、热加载、A/B测试流量分发。当需要上线新模型时通过该服务向推理服务层下发指令进行平滑更新。4.2 高效的请求调度与负载均衡网关层的负载均衡策略至关重要。简单的轮询Round Robin会导致不同实例负载不均因为请求的复杂度输入/输出长度差异很大。 我们采用了最少连接数Least Connections与响应时间加权相结合的策略。网关会轻微地倾向于将新请求发送给当前连接数较少且近期平均响应时间较短的实例。同时我们在每个推理实例上暴露了健康检查接口和负载指标如当前批次大小、队列长度网关可以基于这些指标做出更智能的路由决策。4.3 监控、告警与可观测性“没有度量就没有优化。” 我们建立了全方位的监控体系基础设施监控使用Node Exporter和DCGM Exporter监控服务器和GPU的硬件指标。应用性能监控APM在网关和推理服务代码中大量埋点追踪每个请求的生命周期生成分布式链路追踪使用Jaeger可以清晰看到一个请求在网关、排队、预处理、模型计算、后处理各阶段的耗时。业务指标监控记录总调用量、各模型调用量、Token消耗量用于成本核算、输出长度的分布等。告警基于P99延迟、错误率、GPU显存使用率、实例健康状态等设置告警规则。告警通过钉钉、短信、电话多级触达确保问题能被及时发现。我们有一个核心仪表盘实时展示着全局的QPS、P99延迟和错误率。这个大盘是团队所有人的“血压计”。5. 实战问题排查与调优实录理论很美好但现实总是骨感的。下面分享几个我们遇到的具体问题及其解决过程。5.1 案例一P99延迟的周期性毛刺现象服务整体运行平稳但每过大约5分钟P99延迟就会出现一个明显的尖峰从200ms飙升到2s以上持续十几秒后恢复。排查首先排除外部因素数据库、网络、上游服务均无异常。检查监控发现毛刺出现时GPU利用率有一个短暂的下降同时系统内存使用率有小幅上升。登录服务器使用dstat和pidstat观察发现在毛刺时段有一个名为journald的进程CPU占用率很高。恍然大悟这是Linux系统日志服务journald的日志轮转rotation和压缩。默认情况下journald会定期清理和压缩旧的系统日志这个操作是CPU密集型的会与推理进程争抢CPU资源。推理服务虽然主要用GPU但预处理tokenization、后处理detokenization、数据搬运CPU到GPU以及框架本身的管理调度都需要CPU。CPU的短暂瓶颈导致GPU喂料不足进而引发排队堆积表现为P99延迟飙升。解决为推理服务分配独立的CPU核心集taskset或K8s的cpu-manager-policy进行CPU隔离。调整journald的配置/etc/systemd/journald.conf降低日志压缩频率或将其设置为非实时任务nice值调低。将日志直接输出到文件并采用更轻量的日志轮转工具如logrotate。经验GPU服务的性能瓶颈很可能在CPU或I/O。必须对宿主机的系统级进程和行为有清晰的了解。5.2 案例二长文本生成导致的OOM现象服务在处理一些超长文本生成请求如生成长篇报告时会随机性地出现OOM导致整个推理实例崩溃重启。排查检查vLLM配置max_model_len模型支持的最大序列长度设置正确。观察崩溃前的监控发现显存是缓慢上升直至爆掉的而非瞬间。分析请求日志发现出问题的请求都是开启了流式输出Streaming的请求。深入代码发现我们在流式返回时为了拼接完整的响应以供后续审计在内存中缓存了整个生成的文本。当生成数千甚至上万个Token时这个缓存字符串会占用数百MB的系统内存。如果并发多个这样的长文本请求系统内存就会被耗尽。Linux OOM Killer会选择占用内存最大的进程通常是我们的推理进程杀掉。解决修改流式响应逻辑不再在服务端内存中缓存完整响应。审计日志改为记录请求和响应的元数据如Token数以及抽样片段。对于必须保存完整内容的场景将其异步写入到外部存储如对象存储S3或数据库而不是留在应用内存中。严格限制单个请求的最大生成Token数max_tokens并在网关层对超长请求进行拦截或降级。经验显存OOM只是冰山一角系统内存OOM同样致命。尤其是在处理流式、长上下文场景时对内存的管理要扩展到整个应用层面。5.3 案例三冷启动流量雪崩现象每当发布新模型版本或滚动更新服务时虽然采用了蓝绿部署但在新实例启动接收流量的瞬间其P99延迟极高导致部分用户请求失败。分析新启动的实例模型需要从磁盘加载到GPU显存这需要时间冷启动。在此期间如果网关将大量流量直接切过来这些请求要么堆积在队列中超时要么直接失败。更糟糕的是模型加载本身是计算和I/O密集的可能进一步拖慢第一个批次的处理。解决实施就绪探针Readiness Probe与渐进式流量切换。在Kubernetes的Deployment中为推理容器配置一个“就绪探针”。这个探针会执行一个轻量的脚本该脚本会检查模型是否已完全加载至GPU并可以正常执行一次前向推理。只有就绪探针通过后Kubernetes才会将该Pod标记为“Ready”并将其IP地址添加到Service的Endpoint列表中此时网关才会发现并开始向其分发流量。在网关层面我们配置了渐进式流量切换。当有新版本实例组上线时网关不会立即将100%流量切过去而是以每分钟增加10%-20%流量的速度逐步放大同时密切监控新实例的延迟和错误率。一旦指标异常立即回滚流量。经验发布的平滑度是稳定性的重要组成部分。任何变更尤其是涉及核心服务的变更都必须有自动化的、可观察的、可回滚的发布策略。6. 成本、效果与未来展望经过上述一系列优化我们的服务达到了以下状态吞吐量单台A100 80GB服务器服务7B模型从优化前的约200 RPS提升至稳定1500 RPS。延迟P99延迟从不可控经常5s稳定在800ms以下取决于输入输出长度。成本通过高效的批处理和量化在承载相同流量的情况下所需的GPU实例数减少了约65%直接计算成本大幅下降。稳定性服务可用性达到99.95%能够从容应对日常流量高峰和突发活动。回顾这段历程性能工程没有银弹它是一系列权衡Trade-off的艺术吞吐与延迟的权衡、精度与速度的权衡、灵活性与效率的权衡。核心思想始终是“让最贵的资源GPU保持高效、饱和的工作状态”。未来我们还在探索更多方向比如使用推测解码Speculative Decoding用小模型“猜测”大模型的输出再用大模型快速验证从而加速推理比如更精细的混合精度计算和算子编译优化再比如基于请求特征长度、优先级的差异化调度策略。性能优化之路永无止境。每一次流量增长都会带来新的挑战。但有了这套系统化的方法论和工具链我们至少有了应对挑战的底气和武器。希望我们的这些实践和踩过的坑能为你构建自己的大模型服务提供一些切实可行的参考。
返回列表