自动语音识别服务常见的成本问题,不是模型无法跑满 GPU,而是单个请求只短暂占用一部分计算资源。为了守住延迟目标,团队往往增加 GPU 实例,结果是显存已经分配、CUDA 上下文已经建立,计算单元却仍有大量空闲。
在 Amazon EC2 GPU 实例上组合 NVIDIA CUDA Multi-Process Service(MPS)与 NVIDIA Triton Inference Server,可以让多个 ASR 推理进程更有效地共享同一块 GPU。来源测试显示,这种方式在维持亚秒级延迟的同时,达到每块 GPU 92.1 requests/s,并将 GPU 基础设施需求降低 75%。这些数字来自特定模型、实例和流量条件,不能直接当作所有 ASR 系统的固定收益,但它们说明了一个重要方向:先提高单卡并发密度,再考虑横向扩容。
ASR 服务为什么容易浪费 GPU
语音请求的工作负载通常不均匀:音频长度不同,预处理时间不同,解码阶段也可能包含 CPU 与 GPU 交替执行。如果每个 Triton 进程独占一个 CUDA 上下文,多个进程之间的 GPU 工作提交和资源使用可能缺少有效协调。
MPS 在多个 CUDA 客户端进程和 GPU 之间增加一个共享执行层,使来自不同进程的 CUDA 工作可以并发提交。对 ASR 服务而言,它适合处理以下场景:
- 多个 Triton 进程承载同一模型,需要共享一块 GPU。
- 单个请求无法持续占满 GPU,但总体请求量足够高。
- 服务要求亚秒级响应,不能仅靠大批次提高吞吐。
- 团队希望在不立即更换模型的情况下提高单卡请求密度。
MPS 和 Triton 的职责并不相同。Triton 负责模型加载、动态批处理、实例调度和协议接口;MPS 负责多个 CUDA 进程之间的 GPU 执行共享。两者配合时,Triton 在应用层组织请求,MPS 在 CUDA 层提高并发执行机会。
75% 成本下降应该怎样解读
“GPU 基础设施降低 75%”通常意味着,在相同吞吐量和延迟目标下,优化后的部署只需要原方案约四分之一的 GPU 数量。它不等于 EC2 单价下降,也不意味着把任意四个进程放到一张卡上就一定得到相同结果。
来源给出的关键结果是:
- 单块 GPU 吞吐达到 92.1 requests/s。
- 请求延迟保持在亚秒级。
- 满足同等服务目标所需的 GPU 基础设施减少 75%。
评估这组结果时还要明确延迟口径。摘要没有说明亚秒级延迟对应平均值、P95 还是 P99,也没有交代音频长度分布。因此,在自己的环境中复现时,应同时记录吞吐、分位延迟、GPU 利用率、显存占用和错误率,不能只比较平均响应时间。
动态批处理也是关键变量。批次太小,GPU 利用率仍然偏低;批次太大,请求会在队列中等待,尾延迟可能迅速恶化。实际调优通常需要同时搜索 Triton 批处理参数、Triton 进程数量和每个 MPS 客户端的资源比例。
可以这样搭建四进程 MPS 实验
下面是一个可改造的最小实验。假设 EC2 实例已经安装兼容的 NVIDIA 驱动、Docker、NVIDIA Container Toolkit 和 CUDA MPS 控制程序,并且当前目录包含 Triton 模型仓库 model_repository/。
运行前需要修改两个位置:把 TRITON_IMAGE 换成团队验证过的 Triton 镜像标签,并确保模型仓库符合该版本 Triton 的要求。
#!/usr/bin/env bash
set -euo pipefail
export CUDA_VISIBLE_DEVICES=0
export CUDA_MPS_PIPE_DIRECTORY=/tmp/nvidia-mps
export CUDA_MPS_LOG_DIRECTORY=/tmp/nvidia-mps-log
TRITON_IMAGE="nvcr.io/nvidia/tritonserver:24.08-py3"
MODEL_REPOSITORY="$(pwd)/model_repository"
WORKERS=4
THREAD_PERCENTAGE=25
mkdir -p "$CUDA_MPS_PIPE_DIRECTORY" "$CUDA_MPS_LOG_DIRECTORY"
nvidia-cuda-mps-control -d
for worker in $(seq 0 $((WORKERS - 1))); do
http_port=$((8000 + worker * 10))
grpc_port=$((8001 + worker * 10))
metrics_port=$((8002 + worker * 10))
docker run -d --rm \
--name "asr-triton-${worker}" \
--gpus 'device=0' \
--ipc=host \
-e CUDA_VISIBLE_DEVICES=0 \
-e CUDA_MPS_PIPE_DIRECTORY="$CUDA_MPS_PIPE_DIRECTORY" \
-e CUDA_MPS_ACTIVE_THREAD_PERCENTAGE="$THREAD_PERCENTAGE" \
-v "$CUDA_MPS_PIPE_DIRECTORY:$CUDA_MPS_PIPE_DIRECTORY" \
-v "$MODEL_REPOSITORY:/models:ro" \
-p "${http_port}:8000" \
-p "${grpc_port}:8001" \
-p "${metrics_port}:8002" \
"$TRITON_IMAGE" \
tritonserver --model-repository=/models
done
for port in 8000 8010 8020 8030; do
curl --fail --retry 20 --retry-delay 2 "http://127.0.0.1:${port}/v2/health/ready"
echo "Triton on port ${port} is ready"
done
这里的四个进程和 25% 只是实验起点,不是来源结果的精确部署参数。CUDA_MPS_ACTIVE_THREAD_PERCENTAGE 用来限制客户端可用的执行线程比例,但它不是严格的成本、延迟或显存配额。不同驱动和容器运行方式还可能要求调整 MPS 管道目录权限,以及让宿主机 MPS 守护进程和容器使用兼容的用户身份。
完成测试后,可以停止容器和 MPS:
docker rm -f asr-triton-0 asr-triton-1 asr-triton-2 asr-triton-3 2>/dev/null || true
echo quit | nvidia-cuda-mps-control
如果模型支持 Triton 动态批处理,可以在模型的 config.pbtxt 中从较保守的队列延迟开始。以下是需要合并进现有模型配置的片段,不能替代模型完整配置:
max_batch_size: 8
dynamic_batching {
preferred_batch_size: [ 2, 4, 8 ]
max_queue_delay_microseconds: 2000
}
instance_group [
{
count: 1
kind: KIND_GPU
gpus: [ 0 ]
}
]
max_queue_delay_microseconds: 2000 表示调度器最多等待约 2 毫秒以凑批。对交互式 ASR,可以从 1 至 2 毫秒开始压测,再根据 P95、P99 延迟逐步调整。模型是否支持批处理、允许的批次形状以及输入音频的长度处理方式,仍由具体后端和模型决定。
压测时不要只看 GPU 利用率
一个可靠的对照实验至少应包含三组配置:不启用 MPS 的基线、启用 MPS 但不改变批处理参数,以及同时调优 MPS 与 Triton 动态批处理的配置。每组都应使用相同的音频样本、到达率和预热过程。
建议记录以下指标:
- 每块 GPU 的成功请求数和音频秒数吞吐。
- 平均、P50、P95 和 P99 端到端延迟。
- GPU SM 利用率、显存占用和功耗。
- Triton 队列时间、计算输入时间、推理时间和计算输出时间。
- 超时、CUDA 错误、容器重启和失败请求。
- 在目标负载下实际需要的 EC2 GPU 实例数量。
92.1 requests/s 只有在请求定义一致时才适合比较。一个两秒音频请求和一个一分钟音频请求显然不是同样的工作量,因此 ASR 系统最好同时报告 requests/s 与 real-time factor,或者报告每秒能够处理的音频时长。
上线前的边界检查
MPS 提高共享效率,但不会提供完整的故障隔离和显存硬隔离。一个客户端的 CUDA 故障、异常显存增长或高优先级工作,仍可能影响同卡上的其他服务。对于需要强隔离或多租户安全边界的环境,应同时评估 NVIDIA MIG 或独立 GPU 部署,而不是把 MPS 当成隔离机制。
上线时可以按以下顺序推进:
- 用真实音频长度分布建立单进程、单 GPU 基线。
- 固定延迟 SLO,逐步增加 MPS 客户端数量,不要一次跳到最大并发。
- 分别调节线程比例、动态批次和队列等待时间,观察 P99 而不只是平均值。
- 做进程崩溃、超长音频和显存压力测试,确认共享 GPU 下的故障影响范围。
- 根据峰值而非平均流量保留容量余量,再用 EC2 自动伸缩处理持续峰值。
来源结果证明,MPS 与 Triton 的组合能够显著提高 ASR 的单卡承载能力。不过,真正决定成本下降幅度的仍是模型结构、音频长度、批处理策略和延迟目标。把 75% 当作可验证的优化目标,而不是部署承诺,才能得到可信的容量规划。