使用模型服务网格进行多模型推理服务

当您需要同时运行多个机器学习模型并进行推理时,可以使用模型服务网格部署和管理多模型推理服务。模型服务网格基于KServe ModelMesh实现,针对大容量、高密度和频繁变化的模型用例进行了优化,可以智能地将模型加载到内存中或从内存中卸载,以在响应性和计算之间取得平衡,简化多模型推理服务的部署和运维,提高推理效率和性能。

前提条件

说明

本文使用ASM入口网关作为集群网关,网关名称为默认的ingressgateway,开放8008端口,协议为HTTP。

功能介绍

模型服务网格提供了以下功能:

功能

说明

缓存管理

  • Pod作为根据使用频率和最近访问时间自动进行优化和管理。

  • 根据使用频率和当前请求量,加载和卸载模型的副本。

智能放置和加载

  • 模型放置通过Pod之间的缓存寿命和请求负载来平衡。

  • 使用队列来处理并发模型加载,并最大限度地减少对运行时流量的影响。

弹性

失败的模型加载会在不同的Pod中自动重试。

操作简便性

自动和无缝地处理滚动模型更新。

步骤一:在ASM中开启ModelMesh功能

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择生态集成中心 > KServe on ASM

  3. KServe on ASM页面,单击安装模型服务网格, 开启ModelMesh功能。

    注意:KServe依赖于CertManager,安装KServe会自动安装CertManager组件。如需使用自建CertManager,请关闭在集群中自动安装CertManager组件

  4. 等待几分钟就绪之后, 在ACK集群对应的KubeConfig环境下,执行以下命令,确认ServingRuntime资源是否可用。

  5. kubectl get servingruntimes -n modelmesh-serving

    预期输出:

    NAME                DISABLED   MODELTYPE     CONTAINERS   AGE
    mlserver-1.x                   sklearn       mlserver     1m
    ovms-1.x                       openvino_ir   ovms         1m
    torchserve-0.x                 pytorch-mar   torchserve   1m
    triton-2.x                     keras         triton       1m

    ServingRuntime定义为一个或多个特定模型格式提供服务的Pod模板,根据部署的模型的框架,会自动提供相应的Pod。

    目前默认包含的运行时及支持的模型格式如下。详细信息,请参见supported-model-formats。如果这些模型服务器不能满足您的所有特定要求,可以自定义模型运行时。具体操作,请参见使用模型服务网格自定义模型运行时

    模型服务运行时

    支持的模型框架

    mlserver-1.x

    sklearn、xgboost、lightgbm

    ovms-1.x

    openvino_ir、onnx

    torchserve-0.x

    pytorch-mar

    triton-2.x

    tensorflow、pytorch、onnx、tensorrt

步骤二:配置ASM环境

  1. 从Kubernetes集群同步命名空间到ASM中, 具体操作,请参见从数据平面集群同步自动注入标签至ASM实例。 同步之后, 确认命名空间modelmesh-serving已经存在。

  2. 创建入口网关规则。

    1. 使用以下内容,创建grpc-gateway.yaml。

      展开查看grpc-gateway.yaml

      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: grpc-gateway
        namespace: modelmesh-serving
      spec:
        selector:
          istio: ingressgateway
        servers:
          - hosts:
              - '*'
            port:
              name: grpc
              number: 8008
              protocol: GRPC
      
    2. 在ASM集群(实例)对应的KubeConfig环境下,执行以下命令,创建网关规则。

      kubectl apply -f grpc-gateway.yaml
  3. 创建虚拟服务。

    1. 使用以下内容,创建vs-modelmesh-serving-service.yaml。

      展开查看vs-modelmesh-serving-service.yaml

      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: vs-modelmesh-serving-service
        namespace: modelmesh-serving
      spec:
        gateways:
          - grpc-gateway
        hosts:
          - '*'
        http:
          - match:
              - port: 8008
            name: default
            route:
              - destination:
                  host: modelmesh-serving
                  port:
                    number: 8033
      
    2. 在ASM集群(实例)对应的KubeConfig环境下,执行以下命令,创建虚拟服务。

      kubectl apply -f vs-modelmesh-serving-service.yaml
  4. 配置gRPCJSON转码器。

    1. 使用以下内容,创建grpcjsontranscoder-for-kservepredictv2.yaml。

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMGrpcJsonTranscoder
      metadata:
        name: grpcjsontranscoder-for-kservepredictv2
        namespace: istio-system
      spec:
        builtinProtoDescriptor: kserve_predict_v2
        isGateway: true
        portNumber: 8008
        workloadSelector:
          labels:
            istio: ingressgateway
    2. 在ASM集群(实例)对应的KubeConfig环境下,执行以下命令,部署gRPC-Json-Transcoder。

      kubectl apply -f grpcjsontranscoder-for-kservepredictv2.yaml
    3. 使用以下内容,创建grpcjsontranscoder-increasebufferlimit.yaml,设置per_connection_buffer_limit_bytes,以提升响应的大小。

      展开查看grpcjsontranscoder-increasebufferlimit.yaml

      apiVersion: networking.istio.io/v1alpha3
      kind: EnvoyFilter
      metadata:
        labels:
          asm-system: "true"
          manager: asm-voyage
          provider: asm
        name: grpcjsontranscoder-increasebufferlimit
        namespace: istio-system
      spec:
        configPatches:
        - applyTo: LISTENER
          match:
            context: GATEWAY
            listener:
              portNumber: 8008
            proxy:
              proxyVersion: ^1.*
          patch:
            operation: MERGE
            value:
              per_connection_buffer_limit_bytes: 100000000
        workloadSelector:
          labels:
            istio: ingressgateway
      
    4. 在ASM集群(实例)对应的KubeConfig环境下,执行以下命令,部署EnvoyFilter。

      kubectl apply -f grpcjsontranscoder-increasebufferlimit.yaml

步骤三:部署模型示例

  1. 创建存储类StorageClass。更多信息,请参见使用NAS动态存储卷

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择存储 > 存储类

    3. 存储类页面右上角,单击创建,配置如下信息,然后创建

      Dingtalk_20231107170754.png

  2. 创建存储声明PVC。

    1. 使用以下内容,创建存储声明my-models-pvc.yaml。

      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: my-models-pvc
        namespace: modelmesh-serving
      spec:
        accessModes:
          - ReadWriteMany
        resources:
          requests:
            storage: 1Gi
        storageClassName: alibabacloud-cnfs-nas
        volumeMode: Filesystem
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,创建存储声明。

      kubectl apply -f my-models-pvc.yaml
    3. 执行以下命令,查看modelmesh-serving命名空间下的PVC。

      kubectl get pvc -n modelmesh-serving

      预期输出:

      NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS            AGE
      my-models-pvc    Bound    nas-379c32e1-c0ef-43f3-8277-9eb4606b53f8   1Gi        RWX            alibabacloud-cnfs-nas   2h
  3. 创建Pod以访问PVC。

    为了使用新的PVC,需要将其作为卷安装到Kubernetes Pod,然后使用该Pod将模型文件上传到持久卷。

    1. 使用以下内容,创建pvc-access.yaml。

      以下YAML表示创建一个pvc-access Pod,并要求Kubernetes控制器通过指定“my-models-pvc”来声明之前请求的PVC。

      apiVersion: v1
      kind: Pod
      metadata:
        name: "pvc-access"
      spec:
        containers:
          - name: main
            image: ubuntu
            command: ["/bin/sh", "-ec", "sleep 10000"]
            volumeMounts:
              - name: "my-pvc"
                mountPath: "/mnt/models"
        volumes:
          - name: "my-pvc"
            persistentVolumeClaim:
              claimName: "my-models-pvc"
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,创建Pod。

      kubectl apply  -n modelmesh-serving  -f pvc-access.yaml
    3. 确认pvc-access Pod处于运行状态。

      kubectl get pods -n modelmesh-serving | grep pvc-access

      预期输出:

      pvc-access             1/1     Running   0          51m
  4. 将模型存储在持久卷上。

    将AI模型添加到存储卷中。本文将使用scikit-learn训练的MNIST手写数字字符识别模型。您可以从kserve/modelmesh-minio-examples仓库下载mnist-svm.joblib模型文件的副本。

    1. 在ACK集群对应的KubeConfig环境下,执行以下命令,将mnist-svm.joblib模型文件复制到pvc-access Pod的/mnt/models文件夹中。

      kubectl -n modelmesh-serving cp mnist-svm.joblib pvc-access:/mnt/models/
    2. 执行以下命令,确认Model已经加载成功。

      kubectl -n modelmesh-serving exec -it pvc-access -- ls -alr /mnt/models/

      预期输出:

      -rw-r--r-- 1  501 staff 344817 Oct 30 11:23 mnist-svm.joblib
  5. 部署推理服务。

    1. 使用以下内容,创建sklearn-mnist.yaml。

      展开查看sklearn-mnist.yaml

      apiVersion: serving.kserve.io/v1beta1
      kind: InferenceService
      metadata:
        name: sklearn-mnist
        namespace: modelmesh-serving
        annotations:
          serving.kserve.io/deploymentMode: ModelMesh
      spec:
        predictor:
          model:
            modelFormat:
              name: sklearn
            storage:
              parameters:
                type: pvc
                name: my-models-pvc
              path: mnist-svm.joblib
    2. 在ACK集群对应的KubeConfig环境下,执行以下命令,部署sklearn-mnist推理服务。

      kubectl apply -f sklearn-mnist.yaml
    3. 等待几十秒后(时间取决于镜像拉取速度),执行以下命令,查看sklearn-mnist推理服务是否部署成功。

      kubectl get isvc -n modelmesh-serving

      预期输出:

      NAME            URL                                               READY
      sklearn-mnist   grpc://modelmesh-serving.modelmesh-serving:8033   True
  6. 运行推理服务。

    使用curl命令发送推理请求到sklearn-mnist模型。数据数组表示待分类的数字图像扫描中64个像素的灰度值。

    MODEL_NAME="sklearn-mnist"
    ASM_GW_IP="ASM网关IP地址"
    curl -X POST -k "http://${ASM_GW_IP}:8008/v2/models/${MODEL_NAME}/infer" -d '{"inputs": [{"name": "predict", "shape": [1, 64], "datatype": "FP32", "contents": {"fp32_contents": [0.0, 0.0, 1.0, 11.0, 14.0, 15.0, 3.0, 0.0, 0.0, 1.0, 13.0, 16.0, 12.0, 16.0, 8.0, 0.0, 0.0, 8.0, 16.0, 4.0, 6.0, 16.0, 5.0, 0.0, 0.0, 5.0, 15.0, 11.0, 13.0, 14.0, 0.0, 0.0, 0.0, 0.0, 2.0, 12.0, 16.0, 13.0, 0.0, 0.0, 0.0, 0.0, 0.0, 13.0, 16.0, 16.0, 6.0, 0.0, 0.0, 0.0, 0.0, 16.0, 16.0, 16.0, 7.0, 0.0, 0.0, 0.0, 0.0, 11.0, 13.0, 12.0, 1.0, 0.0]}}]}'

    JSON响应如下,表示推断扫描的数字是8

    {
     "modelName": "sklearn-mnist__isvc-3c10c62d34",
     "outputs": [
      {
       "name": "predict",
       "datatype": "INT64",
       "shape": [
        "1",
        "1"
       ],
       "contents": {
        "int64Contents": [
         "8"
        ]
       }
      }
     ]
    }

相关文档

  • 当您遇到多模型部署时存在差异化运行时环境需求,或者需要优化模型推理效率、控制资源分配的问题时,可以使用模型服务网格自定义模型运行时,通过精细配置运行环境,确保每个模型都能在最适宜的条件下执行。具体操作,请参见使用模型服务网格自定义模型运行时

  • 当您需要处理大量自然语言数据或希望建立复杂的语言理解系统时,可以将大语言模型转化为推理服务。具体操作,请参见将大语言模型转化为推理服务

  • 当您的Pod在运行时出现异常,请参见Pod异常问题排查