本文介绍如何通过Serverless Devs工具基于异步任务调用GPU函数,并将调用结果自动回调至配置的异步目标函数。

背景信息

GPU实例

随着机器学习,特别是深度学习的广泛应用,大量向量、矩阵、张量运算所产生的算力需求,包括训练场景对高精度计算的需求,以及推理场景对低精度计算的需求,传统CPU俨然已无法胜任。2007年英伟达推出可编程通用计算平台CUDA框架,大量的科研人员和开发者将大量算法进行改写,从而获得几十至几千倍的加速效果。在机器学习的趋势来临后,GPU更是成为各类工具、算法、框架的基础底层设施之一。

2021年云栖大会,阿里云函数计算正式推出基于Turing架构的GPU实例,使得Serverless开发者可以将AI训练与推理的业务负载下沉到GPU硬件加速,从而加快模型训练、推理服务的效率。

异步任务

函数计算提供异步任务的分发、执行和观测的全栈能力,使得您只需要专注于任务处理逻辑的编写,创建任务处理函数,然后提交任务。函数计算不但提供异步任务日志、指标以及各个处理阶段耗时统计等丰富的可观测能力,也提供实例自动弹性伸缩、任务去重、指定任务终止以及批量任务暂停、恢复和删除等功能。更多信息,请参见异步任务

应用场景

在面向非实时、偏离线的AI推理场景、AI训练场景和音视频生产场景,基于异步任务调用GPU函数,使得开发者可以聚焦于业务本身,缩短业务达成路径。具体实现如下。
  • 提供GPU虚拟化,支持以1/8、1/4、1/2或独占方式使用GPU,允许业务以更精细化的方式配置GPU实例。
  • 提供异步管理、任务去重、任务监控、任务重试、事件触发、结果回调和任务编排等一系列成熟的异步任务处理能力。
  • 屏蔽运维GPU集群的繁重负担,包括驱动以及CUDA版本管理、机器运行管理和GPU坏卡管理等,使得开发者专注于代码开发,聚焦于业务目标的达成。

实现原理

本文以部署一个GPU函数tgpu_basic_func、异步调用成功回调函数async-callback-succ-func和异步调用失败回调函数async-callback-fail-func为例,介绍异步调用GPU函数并实现结果回调的功能原理。函数具体信息,如下表所示。

函数名称 函数说明 运行环境 实例类型 触发类型
tgpu_basic_func 基于函数计算的GPU实例,运行AI准实时任务、AI离线任务等。 Custom Container GPU实例 HTTP函数
async-callback-succ-func 任务执行成功后的目标回调函数。 Python 3 弹性实例 事件函数
async-callback-fail-func 任务执行失败后的目标回调函数。 Python 3 弹性实例 事件函数
实现原理简单概括如下图。dg-gpu-async

前提条件

步骤一:部署成功回调函数

  1. 初始化项目。
    s init devsapp/start-fc-event-python3 -d async-succ-callback
    创建的项目目录如下所示。
    ├── async-succ-callback
    │   ├── code
    │   │   └── index.py
    │   └── s.yaml
  2. 进入项目所在目录。
    cd async-succ-callback
  3. 按照实际情况修改目录文件中的参数配置。
    • 编辑s.yaml文件。示例如下:
      edition: 1.0.0
      name: hello-world-app
      # access是当前应用所需要的密钥信息配置:
      # 密钥配置请参见:https://www.serverless-devs.com/serverless-devs/command/config
      # 密钥使用请参见:https://www.serverless-devs.com/serverless-devs/tool
      access: "default"
      
      vars: # 全局变量
        region: "cn-shenzhen"
      
      services:
        helloworld: # 业务名称/模块名称
          component: fc
          props:
            region: ${vars.region}
            service:
              name: "async-callback-service"
              description: 'async callback service'
              # logConfig配置文档:https://gitee.com/devsapp/fc/blob/main/docs/zh/yaml/service.md#logconfig
              logConfig:
                project: tgpu-prj-sh             # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的project
                logstore: tgpu-logstore-sh       # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的logstore
                enableRequestMetrics: true
                enableInstanceMetrics: true
                logBeginRule: DefaultRegex
            function:
              name: "async-callback-succ-func"
              description: 'async callback succ func'
              runtime: python3
              codeUri: ./code
              handler: index.handler
              memorySize: 128
              timeout: 60
    • 编辑index.py文件。示例如下:
      # -*- coding: utf-8 -*-
      import logging
      
      # To enable the initializer feature
      # please implement the initializer function as below:
      # def initializer(context):
      #   logger = logging.getLogger()
      #   logger.info('initializing')
      
      def handler(event, context):
        logger = logging.getLogger()
        logger.info('hello async callback succ')
        return 'hello async callback succ'
  4. 部署代码至函数计算
    s deploy
    您可以在函数计算控制台查看部署成功的函数。
  5. 本地调用调试函数。
    s invoke
    调用完成后,返回结果hello async callback succ

步骤二:部署失败回调函数

  1. 初始化项目。
    s init devsapp/start-fc-event-python3 -d async-fail-callback
    创建的项目目录如下所示。
    ├── async-fail-callback
    │   ├── code
    │   │   └── index.py
    │   └── s.yaml
  2. 进入项目所在目录。
    cd async-fail-callback
  3. 按照实际情况修改目录文件中的参数配置。
    • 编辑s.yaml文件。示例如下:
      edition: 1.0.0
      name: hello-world-app
      # access是当前应用所需要的密钥信息配置:
      # 密钥配置请参见:https://www.serverless-devs.com/serverless-devs/command/config
      # 密钥使用请参见:https://www.serverless-devs.com/serverless-devs/tool
      access: "default"
      
      vars: # 全局变量
        region: "cn-shenzhen"
      
      services:
        helloworld: # 业务名称/模块名称
          component: fc
          props:
            region: ${vars.region}
            service:
              name: "async-callback-service"
              description: 'async callback service'
              # logConfig配置文档:https://gitee.com/devsapp/fc/blob/main/docs/zh/yaml/service.md#logconfig
              logConfig:
                project: tgpu-prj-sh             # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的project
                logstore: tgpu-logstore-sh       # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的logstore
                enableRequestMetrics: true
                enableInstanceMetrics: true
                logBeginRule: DefaultRegex
            function:
              name: "async-callback-fail-func"
              description: 'async callback fail func'
              runtime: python3
              codeUri: ./code
              handler: index.handler
              memorySize: 128
              timeout: 60
    • 编辑index.py文件。示例如下:
      # -*- coding: utf-8 -*-
      import logging
      
      # To enable the initializer feature
      # please implement the initializer function as below:
      # def initializer(context):
      #   logger = logging.getLogger()
      #   logger.info('initializing')
      
      def handler(event, context):
        logger = logging.getLogger()
        logger.info('hello async callback fail')
        return 'hello async callback fail'
  4. 部署代码至函数计算
    s deploy
    您可以在函数计算控制台查看部署成功的函数。
  5. 本地调用调试函数。
    s invoke
    调用完成后,返回结果hello async callback fail

步骤三:部署GPU函数

  1. 创建项目目录。
    mkdir fc-gpu-async-job&&cd fc-gpu-async-job
  2. 按照以下目录结构创建文件并根据实际情况修改文件中的参数配置。
    目录结构如下所示。
    ├── fc-gpu-async-job
    ├── code
    │   ├── app.py
    │   └── Dockerfile
    └── s.yaml
    • 编辑s.yaml文件。示例如下:
      edition: 1.0.0
      name: gpu-container-demo
      # access是当前应用所需要的密钥信息配置:
      # 密钥配置请参见:https://www.serverless-devs.com/serverless-devs/command/config
      # 密钥使用顺序请参见:https://www.serverless-devs.com/serverless-devs/tool
      access: default
      vars:
        region: cn-shenzhen
      services:
        customContainer-demo:
          component: devsapp/fc
          props:
            region: ${vars.region}
            service:
              name: tgpu_basic_service
              internetAccess: true
              # logConfig配置文档:https://gitee.com/devsapp/fc/blob/main/docs/zh/yaml/service.md#logconfig
              logConfig:
                project: aliyun****          # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的project
                logstore: func****     # 建议配置,用于查看请求日志,需要在SLS日志服务中提前创建相应的logstore
                enableRequestMetrics: true
                enableInstanceMetrics: true
                logBeginRule: DefaultRegex
            function:
              name: tgpu_basic_func
              description: test gpu basic
              handler: not-used
              timeout: 600
              caPort: 9000
              # 业务可根据实际显存占用,选择合适的GPU实例规格;如下例子展示1/8 GPU虚拟化规格
              memorySize: 4096
              gpuMemorySize: 2048
              instanceType: g1
              instanceConcurrency: 1
              runtime: custom-container
              customContainerConfig:
                # 填写您的镜像信息。需要提前创建ACR个人版或企业版实例,并创建相应的命名空间与镜像仓库
                image: registry.cn-shenzhen.aliyuncs.com/my****/my****
                # 开启镜像加速,对于GB级别镜像有非常好的冷启动优化效果
                accelerationType: Default
              codeUri: ./code
              # 异步配置
              # 详细见:https://gitee.com/devsapp/fc/blob/main/docs/zh/yaml/function.md#asyncconfiguration
              asyncConfiguration:
                destination:           
                  # 填写您创建的失败回调函数的ARN
                  onFailure: "acs:fc:cn-shenzhen:164901546557****:services/async-callback-service.LATEST/functions/async-callback-fail-func"
                  # 填写您创建的成功回调函数的ARN
                  onSuccess: "acs:fc:cn-shenzhen:164901546557****:services/async-callback-service.LATEST/functions/async-callback-succ-func"
                statefulInvocation: true
            triggers:
              - name: httpTrigger
                type: http
                config:
                  authType: anonymous
                  methods:
                    - GET
    • 编辑Dockerfile文件。示例如下:
      FROM nvidia/cuda:11.0-base
      FROM ubuntu
      WORKDIR /usr/src/app
      RUN apt-get update
      RUN apt-get install -y python3
      COPY . .
      CMD [ "python3", "-u", "/usr/src/app/app.py" ]
      EXPOSE 9000
    • 编辑app.py文件。示例如下:
      # -*- coding: utf-8 -*-
      # python2 and python3
      
      from __future__ import print_function
      from http.server import HTTPServer, BaseHTTPRequestHandler
      import json
      import sys
      import logging
      import os
      import time
      
      host = ('0.0.0.0', 9000)
      
      class Resquest(BaseHTTPRequestHandler):
          def do_GET(self):
              print("simulate long execution scenario, sleep 10 seconds")
              time.sleep(10)
      
              print("show me GPU info")
              msg = os.popen("nvidia-smi -L").read()
              data = {'result': msg}
              self.send_response(200)
              self.send_header('Content-type', 'application/json')
              self.end_headers()
              self.wfile.write(json.dumps(data).encode())
      
      if __name__ == '__main__':
          server = HTTPServer(host, Resquest)
          print("Starting server, listen at: %s:%s" % host)
          server.serve_forever()
  3. 部署代码至函数计算
    s deploy
    您可以在函数计算控制台查看部署成功的GPU函数,以及该函数的异步配置。dg-gpu-async-result
  4. 本地调用调试函数。
    s invoke
    调用完成后,返回结果Hello, World!
  5. 提交异步任务。
    1. 查看GPU函数的镜像加速准备状态。
      建议镜像加速准备状态为可用后,再发起异步任务,否则可能会引起链路超时等异常问题。dg-gpu-iamge-state
    2. 登录函数计算控制台,找到已创建的GPU函数tgpu_basic_func,在异步任务列表页签,单击提交任务
    执行完成后,任务状态为执行成功。
    此时,您可以找到配置的成功回调函数async-callback-succ-func,依次选择调用日志 > 调用请求列表页签,然后找到本次异步请求结果行,查看调用结果是否为调用成功。dg-gpu-success-result