GPU利用率接近100%!——vGPU在推理过程应用

语言: CN / TW / HK

vGPU torchserve/tfserving latency指标专项性能测试

上篇介绍了 vGPU device plugin for Kubernetes 组件,可实现在k8s集群里即插即用,无需更改代码,即可实现GPU虚拟化(详细请阅读https://my.oschina.net/u/5259489/blog/5137710 )。这个组件尤其适合在机器学习推理过程使用,今天介绍下关于torchserve/tfserving 过程延迟等方面的测试结果。

开源地址:https://github.com/4paradigm/k8s-device-plugin

测试目的:

在一张GPU卡虚拟成多张GPU卡的时候,服务因虚拟化对latency造成的影响。尤其是当服务众多时,验证通过内存置换显存所带来的overhead。

测试结论:

在GPU使用率低于30%的情况下,对延迟的影响很低。使用率在30%到50%之间时,有一定 的影响,大部分场景可接受,在使用率超过50%,服务会受到较大影响,对于时效性要求不高 的场景,有时仍可接受。如果可接受时效性的部分损失,可将GPU利用率提升接近百分之百。

测试方法:

此实验与多卡无关,所以可以只使用一张卡进行验证,故以下测试均假设机器只有一张卡。

任务描述:

每个任务为一个deployment,每个replica一个pod,一个pod内有两个container。 container1是模型服务,分别是tf-serving和torch-serve, container2是jmeter,用来给同属于自己的pod的container1以固定的qps发压,同时打印日 志记录latency等信息。

注意:(这些magic已经在yml的cmd里了)

注意jmeter的cmd,程序开始先sleep 15s,确保服务已经启动,如果pull镜像太慢 的,15s可能不够程序开始时,需要先发一个请求,预热服务 需要随机sleep一段时间,避免所有请求非常整齐的提交,造成GPU瞬时被打满。

对照组

对照组不做虚拟化,故replica设置为1,设置合理的发送频率,同时通过nvidia-smi 或者其他方式记录显卡利用率,尽量确保GPU的平均利用率不超过30%,记录下此时的latency为 $lat_1$ ms,QPM(每分钟请求数)为$qpm_1$。

实验组

将此卡虚拟 $ n $ 份,例如 $n=10$,对于16G显存的卡,我们不建议超过10,同时设置任务的replica $m(m \le n)$,调整QPM让GPU利用率尽量不超过30%(超过了要有latency变高的心理预期),为了公平也可以设置为$qpm_1 / m$,计算得到latency为$lat_M$ ms,对比 $lat_M$与 $lat_1$,期望差距不会显著增大。

测试用例:

模型列表

镜像说明:

| 镜像 | 说明 | | 4pdosc/tf-serving-benchmark | 这个镜像基于tf-serving 2.0.0-gpu,内置了4个模型,给定环境变量 MODEL_NAME=XXX 即可serve对应模型 | | 4pdosc/torch-serve-benchmark | 这个镜像基于torch-serve:gpu-latest,内置了3个模型,给定环境变量 MODEL_NAME=XXX 即可serve对应模型 | | 4pdosc/jmeter-benchmark | 这个镜像可以发出对应的模型的请求,并打印每个请求的latency等信息,配置参考yaml的环境变量的说明 |

k8s yml以及脚本使用说明:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: serving-benchmark
spec:
  selector:
    matchLabels:
      app: serving-benchmark
  # 副本数,如果该Node有多张卡,最好让副本数等于的该Node的所有虚拟卡,保证均匀
  # 确保机器内存够用,tf-serving有时会直接占满整张卡,加上limit限制
  replicas: 1
  template:
    metadata:
      labels:
        app: serving-benchmark
    spec:
      containers:
      - name: serving
        image: goblin911/tf_serving_benchmark # 这是dockerhub镜像,下载后改成内网镜像
        imagePullPolicy: Always
        env:
          - name: MODEL_NAME
            value: resnet50
        resources:
          requests:
            nvidia.com/gpu: 1
          limits:
            nvidia.com/gpu: 1
      - name: jmeter
        image: goblin911/jmeter # 这是dockerhub镜像,下载后,改成内网镜像
        env:
        - name: JMETER_CONFIG_QPM # 每分钟请求数,根据使用率等酌情修改
          value: "60"
        - name: MODEL_NAME
          value: resnet50
        - name: JMETER_CONFIG_DUR_SEC # 测试时间,单位是秒,建议5分钟以上
          value: "300"
        command: ["/bin/sh", "-c", "sleep 15; jmeter -n -t tfserving.jmx -JpayloadFile=tfserving/${MODEL_NAME}.json -Jmodel=${MODEL_NAME} -Jduration=1; sleep $((${RANDOM}%10)).${RANDOM}; jmeter -n -t tfserving.jmx -JpayloadFile=tfserving/${MODEL_NAME}.json -Jmodel=${MODEL_NAME} -Jqpm=${JMETER_CONFIG_QPM} -Jduration=${JMETER_CONFIG_DUR_SEC} -l ./result.jtl   && ls -ahl && cat ./result.jtl ; sleep infinity"]
        workingDir: /test

另外,压缩包还内置了 calc.sh 与 print_log.sh,calc.sh会获取namespace下所有的pod的log(请修改脚本第一行),最终计算出平均latency,tp50,tp90,tp99,这几个latency。print_log.sh会直接打印所有相关log用于debug(当心刷屏)。

测试结果:

测试环境:

centos7 3.10.0-1127.19.1.el7.x86_64
40 cores
1 * T4
Driver Version: 450.51.05
CUDA Version: 11.0

结果:

注:复现时,注意调整QPM,因为fasterrcnn这个模型本身计算很重,单并发的延迟已经到达 677ms,GPU达到60%的利用率,不降低QPM会直接导致GPU被打满,latency也不再具有参 考意义。另,faster-rcnn是经过一系列优化后的模型,对显存的访问远比计算重,这也是目前 对内存置换显存overhead最大的case

这是一个参数较多的图像分类模型。一张卡虚拟10张卡时,GPU利用率已经达到50%,此时 仍能保证在百毫秒内返回。

maskrcnn是图像检测模型,计算量远比分类的大。

这个项目github地址:https://github.com/4paradigm/k8s-device-plugin