函数计算支持HTTP触发器,配置HTTP触发器的函数可以通过gRPC请求被触发执行。此时函数可以看做一个gRPC Server,处理gRPC请求并将处理结果返回给调用端。本文介绍如何在函数计算控制台配置HTTP触发器并使用gRPC请求触发函数。

使用说明

调用方式

  • 域名:支持使用子域名fcapp.run或自定义域名调用gRPC函数,不支持使用旧域名fc.aliyuncs.com调用gRPC函数。
    说明 如果需要使用自定义域名,自定义域名需要配置请求路径与函数的映射关系。建议您将请求的路径配置为/*,可以让所有gRPC请求都转发到对应的gRPC函数中,gRPC函数会将请求路由到客户端定义的gRPC方法。
  • 端口:gRPC请求端口为8089

传输安全性

  • 为保证gRPC请求的安全性,函数计算线上环境仅支持使用TLS协议的客户端。否则,请求会报错rpc error: code = Unavailable desc = connection closed before server preface received
  • 自定义域名支持使用自定义HTTPS证书,gRPC服务端不需要定义TLS证书验证,函数计算网关层会进行TLS验证。

请求超时控制

gRPC请求的最长超时时间不得超过函数的执行超时时间执行超时时间默认为60秒,最长为86400秒。

请求并发度控制

gRPC请求受函数计算并发度的控制。一个gRPC请求被视为占用一个并发度。gRPC的协议基于HTTP/2,在函数计算中,对于一个函数实例而言,分配到这个函数实例的gRPC请求会复用同一条HTTP/2连接,则这条HTTP/2连接上的并发流就等于实例的并发度。您可以设置函数的单实例并发度来控制一个实例上的并发流数量。具体操作,请参见设置实例并发度

负载均衡

函数计算支持将gRPC请求分发到不同的实例上,自动为gRPC请求做负载均衡。

计费方式

gRPC有以下四种请求类型:
  • 普通gRPC请求
  • 客户端流式请求
  • 服务端流式请求
  • 双向流式请求
不同请求类型对应的计费方式不同,具体如下:
  • 普通gRPC请求:计费方式与使用HTTP的计费方式完全一致。
    • 对于并发度设置为1的函数,计费时间从gRPC连接建立开始到gRPC连接断开结束。
    • 对于并发度大于1的函数,实例的计费时间从收到第一个gRPC连接建立开始,到最后一个gRPC连接断开结束。一个实例中多个连接同时存在期间,不会被重复计费。
      如下图所示,一个函数的并发度设置为2,第一个请求到达的时间为T1,结束时间为T3,第二个请求到达时间为T2,结束时间为T4,计费时间为T4-T1,其中T2到T3这段时间只会被计费一次,不会被重复计费。websocket-billing
  • 客户端流式、服务端流式和双向流式请求:实例的计费从第一个gRPC连接开始,到最后一个gRPC连接断开结束。

准备工作

准备gRPC函数代码

您可以自己编写代码,也可以在安装并配置Serverless Devs工具后执行s init fc-custom-golang-grpc,下载一套完整的使用Golang语言,在函数计算运行gRPC服务的示例代码。完整的代码目录结构如下所示,其中./greeter_client目录为客户端代码,./code目录为服务端代码。

fc-custom-golang-grpc
├── build-image
│   └── Dockerfile
├── certificate
├── code
│   ├── bootstrap
│   └── main.go
├── go.mod
├── greeter_client
│   ├── main
│   └── main.go
├── Makefile
├── privatekey
├── proto
│   ├── helloworld_grpc.pb.go
│   ├── helloworld.pb.go
│   └── helloworld.proto
├── readme.md
├── s_en.yaml
└── s.yaml

准备ZIP代码包

在项目目录fc-custom-golang-grpc,执行make deploy,会在./code目录下生成二进制文件bootstrap,将其打包为bootstrap.zip

安装依赖

在项目目录fc-custom-golang-grpc,执行go mod vendor安装运行gRPC客户端需要的依赖。

使用控制台部署函数

前提条件

创建服务

操作步骤

  1. 登录函数计算控制台,在左侧导航栏,单击服务及函数
  2. 在顶部菜单栏,选择地域,然后在服务列表页面,单击目标服务。
  3. 函数管理页面,单击创建函数
  4. 创建函数页面,选择使用自定义运行时创建方式,设置相关参数,然后单击创建
    需要设置的参数说明如下,其余参数保持默认值即可。更多参数信息,请参见创建函数
    • 函数名称:设置您要创建的函数名称,例如grpc-demo
    • 请求处理程序类型:选择处理 HTTP 请求
    • 运行环境:选择Debian 9
    • 代码上传方式:选择通过 ZIP 包上传代码
    • 代码包:选择并上传您已打包的bootstrap.zip文件。
    • 启动命令:如不填写,默认执行./bootstrap
    • 监听端口:监听端口与服务端监听的端口保持一致,本文示例值为8089
  5. 在函数详情页面,单击触发器管理页签,查看触发器的公网访问地址。
    grpc-demo
  6. 执行以下命令调用gRPC客户端,发起gRPC调用,测试函数的正确性。
    go run ./greeter_client -addr  grpc-demo-service-*********.cn-qingdao.fcapp.run:8089
说明 您也可以为您创建的gRPC函数配置自定义域名,并使用自定义域名调用该函数。

使用Serverless Devs工具部署函数

前提条件

操作步骤

  1. 执行以下命令,初始化项目。
    s init fc-custom-golang-grpc -d fc-custom-golang-grpc
  2. 执行以下命令,进入项目目录fc-custom-golang-grpc
    cd fc-custom-golang-grpc
  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: "ap-south-1" # 您要部署的函数所在的地域
      service:
        name: "grpc-demo"  # 您要部署的函数所在的服务名称
        description: 'hello world by serverless devs'
        internetAccess: true
    
    services:
      helloworld: # 您自定义的业务名称或模块名称
        # 如果只想针对helloworld下面的业务进行相关操作,可以在命令行中加上helloworld,例如,只对helloworld进行构建:s helloworld build
        # 如果不带有helloworld,而是直接执行s build,工具则会对当前Yaml下,所有和helloworld平级的业务模块(如有其他平级的模块,例如下面注释的next-function),按照一定顺序进行build操作
        component: fc
        actions: # 自定义执行逻辑,关于actions的使用,可以参考:https://www.serverless-devs.com/serverless-devs/yaml
          pre-deploy: # 在deploy之前运行
            - run: make build
              path: ./
        #        - component: fc build --use-docker --dockerfile ./code/Dockerfile  # 要运行的组件,格式为【component: 组件名 命令 参数】(可以通过s cli registry search --type Component 获取组件列表)
        #        - run: docker build xxx          # 要执行的系统命令,类似于一种钩子的形式
        #          path: ./src                    # 执行系统命令/钩子的路径
        #        - plugin: myplugin               # 运行的插件(可以通过s cli registry search --type Plugin获取插件列表)
        #          args:                          # 插件的参数信息
        #            testKey: testValue
        #      post-deploy: # 在deploy之后运行
        #        - component: fc versions publish # 要运行的命令行
        props:
          region: ${vars.region}
          service: ${vars.service}
          #        logConfig:
          #          project: mypro-dev
          #          logstore: function-log
          function:
            name: "golang-grpc"  # 您要部署的函数名称
            description: 'hello world by serverless devs'
            timeout: 30
            memorySize: 512
            runtime: custom
            codeUri: ./code
            instanceConcurrency: 3
            caPort: 8089
          triggers:
            - name: http2Trigger
              type: http
              config:
                authType: anonymous
                # HTTP触发器的触发方式配置,必须配置POST方式
                methods: 
                  - GET
                  - POST
    #      customDomains:
    #        - domainName: auto
    #          protocol: HTTP,HTTPS
    #          routeConfigs:
    #            - path: /*
    #              serviceName: "grpc-demo"
    #              functionName: "golang-grpc"
    #          certConfig:
    #            certName: certtest
    #            certificate: ./certificate
    #            privateKey: ./privatekey
  4. 执行s deploy -y部署函数。
    执行完成后,函数将部署至函数计算。此外,函数计算会生成一个可直接访问的URL地址,您可以使用该URL地址调用函数进行测试。
  5. 执行以下命令,安装运行gRPC客户端所需的依赖。
    go mod vendor
  6. 执行以下命令,调用gRPC客户端,发起gRPC调用,测试函数的正确性。
    使用HTTP函数触发器的公网访问地址,示例如下:
    go run ./greeter_client -addr golang-grpc-grpc-demo-torcawakky.cn-qingdao.fcapp.run

更多示例

Custom RuntimeCustom Container
GolangGolang
Python

常见问题

函数错误

客户端报错rpc error: code = Internal desc = server closed the stream without sending trailers,表示函数计算服务端提前异常关闭gRPC请求。这种错误属于函数错误,例如函数超时、函数进程异常退出或函数出现内存溢出OOM错误等。您可以从函数日志中查询具体的错误原因并排查处理。更多信息,请参见查看调用日志

gRPC请求未使用TLS协议客户端

需使用TLS协议客户端调用gRPC请求,否则会报错rpc error: code = Internal desc = server closed the stream without sending trailers。例如,Golang语言可以使用如下示例代码:
var opts []grpc.DialOption
    cred := credentials.NewTLS(&tls.Config{
        InsecureSkipVerify: false,
    })
    opts = append(opts, grpc.WithTransportCredentials(cred))
    conn, err := grpc.Dial(*addr, opts...)

InsecureSkipVerify的值可以设置为true,即跳过TLS证书验证,或者设置为false,即不跳过TLS证书验证。

更多信息

除了函数计算控制台,您还可通过SDK配置触发器。具体操作,请参见SDK参考(2021-04-16推荐)

如需修改或删除触发器,具体操作,请参见触发器管理