AIBrix GPU Optimizer:面向异构 GPU 的 vLLM 自动扩缩容器实战指南 AIBrix GPU Optimizer面向异构 GPU 的 vLLM 自动扩缩容器实战指南【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrixAIBrix 的 GPU Optimizer 是一个面向异构 GPU 集群的 vLLM 自动扩缩容组件它通过性能 profiling 建立每类 GPU 的吞吐能力画像GPU Profile实时聚类网关侧采集的请求负载模式再用整数线性规划求解器Mélange在满足 SLO 的前提下给出最少花费、多 GPU 型号混合的副本数建议最后由 Kubernetes 控制器落地扩缩容。本文以 GPU Optimizer 主文档 为核心脉络结合其 profiling 工具链、负载监控与求解器源码完整演示从集群部署、性能画像生成、profile 下发到压测与可观测性的端到端使用流程并深入解释每步背后的实现原理。读完本文你将能够在 AIBrix 集群中独立完成 GPU Optimizer 的部署、调参与验证并理解其SLO 驱动 成本最优 异构 GPU 混排的自动扩缩容设计。一、GPU Optimizer 是什么定位与整体架构在 AIBrix 项目Cost-efficient and pluggable Infrastructure components for GenAI inference中GPU Optimizer 承担着在异构 GPU 环境下自动决定每个模型部署需要多少副本的职责。它不是一个简单的基于 CPU/内存利用率的 HPA而是一个SLOService Level Objective驱动的成本优化控制器核心特性包括异构 GPU 支持同一模型的不同 Deployment 可以运行在不同 GPU 型号上优化器为每种 GPU 维护独立的吞吐画像从而在 A100、A40、A10 等混合集群中按性价比混合调度SLO 驱动通过 E2E 延迟、TTFT、TPOT、吞吐等指标定义服务目标profile 生成阶段即依据 SLO 从压测数据中筛选合格点成本最优求解器以每小时 GPU 租赁总成本最小为目标函数输出每种 GPU 型号应保留的副本数负载感知从 AIBrix 网关读取请求记录输入/输出 token 数、时间戳用流式 DBSCAN 聚类出实时工作负载形态避免一刀切的固定阈值。从源码结构看GPU Optimizer 的 Python 实现位于 python/aibrix/aibrix/gpu_optimizer/主要分为三个子模块子模块职责关键文件optimizer/profiling压测采集吞吐/延迟数据并按 SLO 生成 GPU Profilebenchmark.sh、gen_profile.py、gpu_benchmark.pyload_monitor监控模型负载、聚类请求模式、触发优化与扩缩容monitor.py、load_reader.py、visualizer.pyoptimizer/solverMélange 整数线性规划ILP求解器输出最小成本 GPU 组合solver.py、runner.py最外层的 app.py 是 GPU Optimizer 的 HTTP 服务入口默认监听8080端口同时运行着一个独立的 Kubernetes Deployment informer 线程它持续watch所有带model.aibrix.ai/name标签的 Deployment为每个模型启动一个ModelMonitor线程并通过 REST API 暴露监控、profile 更新、手动扩缩容与指标读取能力。二、在 Kubernetes 中部署与更新 GPU Optimizer2.1 部署前置条件AIBrix 基础组件已就绪GPU Optimizer 依赖 AIBrix 的网关Gateway采集请求负载、依赖 Redis 存储 profile 数据。因此需要先完成 AIBrix 的整体安装见 config/default 与 config/dependency。模型可被监控待自动扩缩容的 vLLM Deployment 必须带有model.aibrix.ai/namemodel标签否则 GPU Optimizer 无法识别该模型——这一点在 app.py 的validate_model中会被强制校验并抛出异常提示。可选最小副本数标签Deployment 上可添加model.aibrix.ai/min_replicas标签用于在负载归零时保底缩容到的最小副本数app.py 会读取该标签并注入DeploymentStates.min_replicas。2.2 独立更新 GPU Optimizer 组件GPU Optimizer 可以独立于其他 AIBrix 组件进行迭代更新。官方文档给出的标准流程为cd ../../../../ make docker-build-runtime kubectl apply -k config/dependency --server-side kubectl apply -k config/default kubectl delete -k config/overlays/dev/gpu-optimizer kubectl apply -k config/overlays/dev/gpu-optimizer其中make docker-build-runtime重新构建包含 GPU Optimizer Python 代码的运行时镜像config/dependency 与 config/default 保证网关、Redis 等依赖与 CRD 处于最新状态config/overlays/dev/gpu-optimizer/kustomization.yaml 是开发 overlay它会以--debug模式启动 GPU Optimizercommand: [python, -m, aibrix.gpu_optimizer.app, --debug]便于本地联调时观察详细日志。生产形态的部署清单位于 config/gpu-optimizer/deployment.yaml单副本 Deployment容器监听8080通过环境变量REDIS_HOST指向集群内的aibrix-redis-master.aibrix-system.svc.cluster.local。GPU Optimizer 需要gpu-optimizer-sa服务账号见 config/gpu-optimizer/rbac.yaml以读取 Deployment 与执行扩缩容。三、准备模型与可选CPU 版 vLLM 模拟器GPU Optimizer 的压测和验证需要一个 OpenAI/vLLM 兼容的推理服务作为目标。官方文档建议Deploy your vLLM model. If run locally a CPU based vLLM simulator is provided. See development/app for details.即直接部署真实 vLLM 模型生产场景或使用 CPU 版 vLLM 模拟器本地开发/验证场景无需 GPU。模拟器的完整说明在 development/app/README.md。它支持两种形态Mock 应用STANDALONE_MODEtrue python app.py直接在本机启动监听8000端口或打包成镜像后kubectl create -k config/mock部署为集群 DeploymentvLLM 高保真模拟器集成 Vidurdocker build -t aibrix/vllm-simulator:nightly --build-arg SIMULATIONa100 -f Dockerfile . kind load docker-image aibrix/vllm-simulator:nightly # kind 集群需要Docker Desktop 可跳过 kubectl create -k config/simulator模拟器按SIMULATIONa100等构建参数模拟对应 GPU 的性能特征。仓库内置了模拟器压测产生的样本 profile见下文 4.3 节因此即使没有任何 GPU也能完整走通profiling → 生成 profile → 触发优化 → 观察扩缩容的全流程。四、性能 Profiling为 GPU 建立吞吐画像GPU Optimizer 的智能完全建立在GPU Profile之上一张描述在给定输入/输出长度下某 GPU 型号能达到的请求吞吐RPS上限的二维矩阵。profile 通过 optimizer/profiling 工具链分两步生成详见 optimizer/profiling/README.md。4.1 第一步benchmark.sh采集原始压测数据先部署目标模型到待 profiling 的 GPU 上当前支持 vLLM 类推理引擎修改benchmark.sh顶部的五个核心参数定义压测空间参数默认值含义input_start/input_limit4/2**124Kprofiling 的输入 token 长度范围output_start/output_limit4/2**124Kprofiling 的输出 token 长度范围rate_start/rate_limit1/2**664请求速率RPS范围TOTAL100每个组合发送的请求总数安装依赖后执行benchmark.sh还支持-m/--model、-o/--output、--input-start等命令行参数覆盖默认值并支持--workload指定 workload dataset、--dry-run仅打印将要执行的命令pip install -r requirements.txt ./benchmark.sh [your deployment name]脚本内部按输入长度 × 输出长度 × 请求速率三重循环每层以 2 倍步进见 benchmark.sh调用 gpu_benchmark.py 对 vLLM 服务施压输出追加写入result/deployment.jsonl。每行 JSON 记录包含input_tokens、output_tokens、request_rate、metricTPUT/E2E/TTFT及mean、P50、P90、P99等统计字段对应 gpu_benchmark.py 的指标输出逻辑。运行压测前需确保模型服务在本机可达官方文档给出的 port-forward 命令# Make sure pod is accessable locally: kubectl port-forward [pod_name] 8010:8000 1/dev/null 21 注意benchmark.sh内部对gpu_benchmark.py默认使用--port 8010benchmark.sh与文档中 port-forward 的 8010 端口一一对应而 5.3 节用户主动压测时使用的--port 8888是面向网关暴露的端口两者用途不同。4.2 第二步gen_profile.py按 SLO 生成 GPU Profile原始压测数据是每个 (输入长, 输出长, 速率) 组合下的吞吐/延迟而 profile 需要的是每个 (输入长, 输出长) 网格上、满足 SLO 的最大可持续吞吐。这一步由 gen_profile.py 完成。支持的 SLO 指标slos字典见 gen_profile.py命令行参数类型含义--tputfloat吞吐 SLO 目标RPS越大越好--ttfloatToken 吞吐 SLO 目标--e2efloat端到端请求延迟 SLO越小越好--ttftfloat首 token 延迟 SLO越小越好--tpatfloat全部 token 平均时间 SLO越小越好--tpotfloat每输出 token 时间 SLO越小越好--percentileint使用 P50/P90/P99 还是 mean0/50/90/99默认0即 mean--costfloat该 GPU 的每小时成本默认1.0用于求解器成本优化-ostr输出文件或 Redis URLredis://[user:pass]host:port[/db]?modelmodel算法核心gen_profile.py对每个 (输入, 输出) 网格点先用各 SLO 过滤出达标延迟类目标值、吞吐类目标值的压测记录再应用TPUT_TOLERANCE 0.9规则剔除吞吐明显低于请求速率、会导致请求排队堆积的速率点在剩余候选速率中取最大请求速率作为该网格点的 profile 吞吐同时记录该点对应的 E2E 延迟矩阵与 TTFT 矩阵。最终输出的 JSON profile 结构与 result/simulator-llama2-7b-a100.json 一致其字段定义可对照 types.py 中的 GPUProfile{ gpu: simulator-llama2-7b-a100, cost: 1.0, tputs: [[62.47, 32.31, ...], ...], indexes: [[4, 8, 16, 32, 64, 128, 256, 512], [128, 256, 512, 1024, 2048]], created: 1748888478.25, e2e: [[0.099, ...], ...], slos: {percentile: 99, e2e: 5.0} }其中tputs为(输出长度数 × 输入长度数)的二维矩阵indexes记录两个维度的长度刻度。profile 本质上是把性能天花板压缩成一张成本优化的输入表后续求解器只需查表即可。4.3 将 Profile 写入 Redis生成的 profile 需要落到 RedisGPU Optimizer 的RedisProfileReader才会读取到它。官方文档给出的两种等价方式以 CPU 模拟器为例# 方式一手动建立本地端口转发后直接执行 kubectl -n aibrix-system port-forward svc/aibrix-redis-master 6379:6379 1/dev/null 21 python optimizer/profiling/gen_profile.py simulator-llama2-7b-a100 -o redis://localhost:6379/?modelllama2-7b # 方式二使用 Makefile 封装debug-init 同时转发 8080 与 6379 两个端口 make debug-init make DPsimulator-llama2-7b-a100 gen-profilesimulator-llama2-7b-a100是 Deployment 名对应 result/ 目录下预置的模拟器压测结果含a100与a40两套样本以及一个_obsoleted_v1旧版副本Redis URL 中的modelllama2-7b指定模型名gen_profile.py会以aibrix:profile_model_deployment为 key 写入[gen_profile.py](https://link.gitcode.com/i/203aa6a01a087aced808d306238c3105#L26-L27, L264-L273)若-o是普通文件路径则直接写 JSON 文件--verbose可打印完整 profile 便于人工检查。实际使用中请将simulator-llama2-7b-a100替换为你的 Deployment 名llama2-7b替换为你的模型名。五、通知优化器与触发扩缩容5.1 通知 profile 就绪可选profile 写入 Redis 后GPU Optimizer 会周期性重载通常无需手动通知。官方文档也注明This is usually not necessary, the optimizer will reload profiles while there are enough data to re-optimize.如需立即生效可通过 HTTP 接口主动刷新kubectl -n aibrix-system port-forward svc/aibrix-gpu-optimizer 8080:8080 1/dev/null 21 curl http://localhost:8080/update_profile/llama2-7b该请求对应 app.py 的update_profile路由找到该模型的ModelMonitor后调用load_profiles()从 Redis 重新读取全部 profile 并注入优化器。注意llama2-7b为模型名需替换为你自己的模型名。5.2 GPU Optimizer 的 HTTP API 全景除update_profile外app.py 还暴露了以下端点便于日常运维与调试方法路径用途POST/monitor/{namespace}/{deployment_name}手动为某 Deployment 启动优化监控API 不可达时的兜底入口DELETE/monitor/{namespace}/{deployment_name}停止该 Deployment 的优化并移出监控PUT/scale/{namespace}/{deployment_name}手动覆盖副本数{replicas: N}传-1取消覆盖恢复自动优化GET/metrics/{namespace}/{deployment_name}以 Prometheus 文本格式输出当前建议副本数vllm:deployment_replicasGET/dash/{model_name}模型负载可视化 Dashboard见第 6 节5.3 启动压测观察扩缩容一切就绪后即可用压测流量驱动扩缩容。官方文档给出了使用 AIBrix benchmark 工具生成负载的示例# Make sure gateways local access, see development/app/README.md for details. python optimizer/profiling/gpu_benchmark.py --backendvllm --port 8888 --request-rate10 --num-prompts100 --input-len 2000 --output-len 128 --modelllama2-7bgpu_benchmark.py的常用参数gpu_benchmark.py--backendvllm或dryrun、--request-rateRPS默认inf表示瞬间全发、--num-prompts、--input-len/--output-len、--stream流式输出、--workload-dataset-fileJSON 格式 prompts 文件、--temperature默认0.0。从源码调用链看一次扩缩容的完整闭环是网关记录每个请求的输入/输出 token 数并写入 RedisGatewayLoadReaderload_reader.py周期性读取ModelMonitor将 token 对展开为DataPoint交给MovingDBSCANClusterer做流式聚类窗口默认 240 秒见 monitor.py得到若干个负载中心每个中心映射为 profile 矩阵中的下标签名optimizer.py 的set_workload_distribution构造出当前工作负载分布调用 Mélange 求解器在gpu_info各 GPU profile与workload_distribution约束下求最小成本解求解结果{gpu_type: replicas, ..., cost: total}写回各DeploymentStates由控制器侧落地为实际副本数当负载为空时进入_minimize()将副本缩到min_replicasmonitor.py。六、可观测性负载可视化6.1 在线 DashboardGPU Optimizer 内置了模型负载的实时可视化面板# 访问 http://localhost:8080/dash/llama2-7b 查看 workload pattern 可视化该路由由 visualizer.py 的mount_to挂载app.py渲染每个模型的实时聚类结果、负载分布与优化状态。将llama2-7b替换为你的模型名即可。6.2 独立可视化 Demo不依赖 Kubernetes 与 Redis 的离线演示python -m load_monitor.visualizer等价于仓库内make visualizer可传--dataset指定数据集、--redisprofile指定 Redis 中的 profile。该模式适合在开发机上回放历史负载数据观察聚类与优化行为。此外GPU Optimizer 在 debug 模式下会输出xxx optimization took N ms, cost $X, coverage: Y%形式的日志monitor.py其中coverage表示被聚类覆盖的请求比例可作为负载数据质量的直观指标cost则是当前解的总成本可用于验证成本优化的有效性。七、深入Mélange 求解器如何做成本最优分配Mélange 是 GPU Optimizer 的决策大脑其实现位于 optimizer/solver/melange/实现来源与算法细节记录在 melange/README.md。输入workload_distribution各请求尺寸桶的占比矩阵、total_request_rate总请求速率、gpu_info每种 GPU 的cost与tputs矩阵、slice_factor切片因子经验值 4 即足够。求解过程solver.py以 PuLP 构建整数线性规划把负载分布矩阵乘以总速率得到各桶的 RPS 直方图再按slice_factor切分成更细的slice通过 util.py 的tputs_to_loads_2d将每类 GPU 的吞吐矩阵换算为每个 slice 消耗的 GPU 负载定义决策矩阵x_{i,j}slice i 是否分配给 GPU 类型 j0/1 整数与决策向量y_jGPU 类型 j 需要多少块目标函数min Σ y_j * cost_j即每小时总租赁成本最小约束条件C1——每个 slice 必须且只能分配给一种 GPUC2——每种 GPU 上承载的 slice 负载之和不超过y_j的容量。求解器输出形如{A10G: 3, A100-80GB: 1, cost: 6.7}的结果——含义是用 3 块 A10G 加 1 块 A100-80GB每小时成本 6.7 美元。这正是 GPU Optimizer 异构混排 成本最优能力的来源它允许把不同大小的请求分派到不同 GPU 上而不是所有流量都挤在同一种卡上。注意Arm 架构 MacM1/M2/M3上 PuLP 默认 ILP 求解器可能不兼容官方建议brew install coin-or-tools/coinor/cbc后改用 COIN CBC 求解器melange/README.md。八、本地调试速查Makefile 封装Makefile 为整个工作流提供了便捷封装适合开发联调目标等价操作make debug-init清理旧进程并 port-forward GPU Optimizer8080与 Redis6379make benchmarkoptimizer/profiling/benchmark.sh -m $(DP)make gen-profilegen_profile.py $(DP) --cost $(COST) -o redis://localhost:6379/?modelllama2-7bmake debugpython -m app --debug本地启动 GPU Optimizermake debug-init-simulator对模拟器 Deployment 发起POST /monitor开始优化make debug-scale-simulatorPUT /scale手动设置副本数示例0make debug-update-profileGET /update_profile/llama2-7b刷新 profilemake debug-metricsGET /metrics/...查看建议副本数指标make debug-workload用gpu_benchmark.py生成压测负载make visualizer本地离线可视化 demo其中make DPsimulator-llama2-7b-a100 gen-profile与文档中的手动命令完全等价是验证模拟器 → profile → Redis链路的最快路径。九、常见问题与注意事项Deployment 缺少模型标签validate_model会强制要求model.aibrix.ai/name标签缺失时优化器直接跳过该 Deployment 并打印警告请检查 Deployment 标签是否齐全。profile 与 Deployment 匹配不上ModelMonitor.add_deployment会按namespace/name → deployment name两级匹配 profilemonitor.py匹配失败会提示No GPU profile found for xxx. Optimizer will skip the GPU请核对 Redis 中aibrix:profile_model_deployment的 key 命名。多个 profile 必须同构Optimizer.set_profile要求所有 GPU 的tputs矩阵形状与indexes刻度完全一致optimizer.py因此不同 GPU 的压测必须使用相同的输入/输出长度网格。请求速率过高的堆积风险profile 生成内置TPUT_TOLERANCE 0.9过滤如果压测发现吞吐远低于请求速率说明已过载该数据点会被剔除不会进入 profile。手动覆盖与自动优化的关系PUT /scale设置的副本数会覆盖优化结果overriden状态直到再次传-1才恢复自动优化调试完请记得复位。十、小结GPU Optimizer 是 AIBrix 异构 GPU 推理场景下的核心成本优化组件profiling 工具链负责把 GPU 性能压测转化为 SLO 约束下的吞吐画像负载监控负责实时刻画请求模式Mélange 求解器负责在满足 SLO与总成本最小之间求最优副本组合。按照本文的六步流程——更新组件、部署模型/模拟器、跑 benchmark、生成并下发 profile、通知优化器、压测观察——即可在自有集群中复现完整闭环若使用仓库预置的 CPU 模拟器与样本 profile甚至无需真实 GPU 就能验证全部机制。进一步阅读可参考 profiling README、Mélange README 与 GPU Optimizer 源码。【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考