自定义函数运行时
函数运行时是函数执行的载体,通过加载函数代码来调用函数,跟函数实现的语言强相关。比如python代码需要使用python runtime来调用。这里就涉及到多种语言的问题,为了统一调用接口和协议,我们最终选择了GRPC,借助其强大的跨语言IDL和高性能RPC通讯能力,打造可灵活扩展的函数计算框架。
协议约定
GRPC的消息和服务定义如下,开发者可直接用于生成各自编程语言的消息和服务实现,GRPC使用方法可参考make pb
命令,也可参考GRPC官网的文档。
syntax = "proto3";
package runtime;
// The runtime definition.
service Runtime {
// Handle handles request
rpc Handle (Message) returns (Message) {} // 消息处理接口
}
// The request message.
message Message {
uint32 QOS = 1; // MQTT消息的QOS
string Topic = 2; // MQTT消息的主题
bytes Payload = 3; // MQTT消息的内容
string FunctionName = 11; // 被调用的函数名
string FunctionInvokeID = 12; // 函数调用ID
}
注意:Docker容器模式下,函数实例的资源限制不要低于50M内存,20个线程。
配置约定
函数配置的所有定义如下。对于自定义函数runtime,只需关注Function.Handler和Function.CodeDir的定义和使用,其他配置都是函数计算框架使用的配置。
// Runtime runtime config
type Runtime struct {
// 模块哦诶只
Module `yaml:",inline" json:",inline"`
// 服务配置
Server RuntimeServer `yaml:"server" json:"server"`
//
Function Function `yaml:"function" json:"function"`
}
// RuntimeServer function runtime server config
type RuntimeServer struct {
Address string `yaml:"address" json:"address" validate:"nonzero"`
Timeout time.Duration `yaml:"timeout" json:"timeout" default:"30s"`
Message struct {
Length Length `yaml:"length" json:"length" default:"{\"max\":4194304}"`
} `yaml:"message" json:"message"`
}
// Function function config
type Function struct {
// 函数ID,目前用于映射函数代码所在的目录
ID string `yaml:"id" json:"id" validate:"regexp=^[a-zA-Z0-9_-]{1\\,140}$"`
// 函数名,函数调用使用的名称
Name string `yaml:"name" json:"name" validate:"regexp=^[a-zA-Z0-9_-]{1\\,140}$"`
// 函数执行的入口
Handler string `yaml:"handler" json:"handler" validate:"nonzero"`
// 函数代码所在目录
CodeDir string `yaml:"codedir" json:"codedir"`
// 实例配置
Instance Instance `yaml:"instance" json:"instance"`
// 函数runtime,docker容器模式下是函数runtime的镜像,native进程模式下是函数runtime的可执行程序路径
Entry string `yaml:"entry" json:"entry"`
// 函数runtime启动进程时传入的环境变量
Env map[string]string `yaml:"env" json:"env"`
}
// Instance instance config for function runtime module
type Instance struct {
// 最少实例数
Min int `yaml:"min" json:"min" default:"0" validate:"min=0, max=100"`
// 最多实例数
Max int `yaml:"max" json:"max" default:"1" validate:"min=1, max=100"`
// 实例最大空闲时间
IdleTime time.Duration `yaml:"idletime" json:"idletime" default:"10m"`
// 实例调用超时时间
Timeout time.Duration `yaml:"timeout" json:"timeout" default:"5m"`
// 实例的资源配置
Resources Resources `yaml:",inline" json:",inline"`
// 消息最大长度限制
Message struct {
Length Length `yaml:"length" json:"length" default:"{\"max\":4194304}"`
} `yaml:"message" json:"message"`
}
启动约定
函数runtime实际上也是一种模块,只是比较特殊,是被函数计算模块在运行过程中按需启动的模块,归为临时模块。其启动方式和普通模块启动的方式基本一致,只不过临时模块没有固定路径,不支持从配置文件中加载配置。因此约定通过传参的方式传入配置信息,使用JSON格式,比如-c "{\"name\":\"sayhi\", …}"。
函数runtime启动并加载配置后,首先根据Server配置初始化GRPC server,然后根据Function的配置加载函数代码入口,等待函数计算模块来调用,最后注意监听SIGTERM信号来优雅退出。完整的实现过程可参考python27 runtime。
最后更新于 2018-12-28 10:23:09
原文: https://openedge.tech/docs/customize/How-to-develop-a-customize-runtime-for-function