ServerLess介绍

过去是“构建一个框架运行在一台服务器上,对多个事件进行响应”,Serverless则变为“构建或使用一个微服务或微功能来响应一个事件”,做到当访问时,调入相关资源开始运行,运行完成后,卸载所有开销,真正做到按需按次计费。这是云计算向纵深发展的一种自然而然的过程。

Serverless是一种构建和管理基于微服务架构的完整流程,允许你在服务部署级别而不是服务器部署级别来管理你的应用部署。它与传统架构的不同之处在于,完全由第三方管理,由事件触发,存在于无状态(Stateless)、暂存(可能只存在于一次调用的过程中)计算容器内。构建无服务器应用程序意味着开发者可以专注在产品代码上,而无须管理和操作云端或本地的服务器或运行时。Serverless真正做到了部署应用无需涉及基础设施的建设,自动构建、部署和启动服务。

FaaS和BaaS

Serverless由开发者实现的服务端逻辑运行在无状态的计算容器中,它由事件触发, 完全被第三方管理,其业务层面的状态则被开发者使用的数据库和存储资源所记录。Serverless涵盖了很多技术,分为两类:FaaS和BaaS。

FaaS(Function as a Service,函数即服务)

FaaS意在无须自行管理服务器系统或自己的服务器应用程序,即可直接运行后端代码。其中所指的服务器应用程序,是该技术与容器和PaaS(平台即服务)等其他现代化架构最大的差异。

FaaS可以取代一些服务处理服务器(可能是物理计算机,但绝对需要运行某种应用程序),这样不仅不需要自行供应服务器,也不需要全时运行应用程序。

FaaS产品不要求必须使用特定框架或库进行开发。在语言和环境方面,FaaS函数就是常规的应用程序。例如AWS Lambda的函数可以通过Javascript、Python以及任何JVM语言(Java、Clojure、Scala)等实现。然而Lambda函数也可以执行任何捆绑有所需部署构件的进程,因此可以使用任何语言,只要能编译为Unix进程即可。FaaS函数在架构方面确实存在一定的局限,尤其是在状态和执行时间方面。

在迁往FaaS的过程中,唯一需要修改的代码是“主方法/启动”代码,其中可能需要删除顶级消息处理程序的相关代码(“消息监听器接口”的实现),但这可能只需要更改方法签名即可。在FaaS的世界中,代码的其余所有部分(例如向数据库执行写入的代码)无须任何变化。

相比传统系统,部署方法会有较大变化 – 将代码上传至FaaS供应商,其他事情均可由供应商完成。目前这种方式通常意味着需要上传代码的全新定义(例如上传zip或JAR文件),随后调用一个专有API发起更新过程。

FaaS中的函数可以通过供应商定义的事件类型触发。对于亚马逊AWS,此类触发事件可以包括S3(文件)更新、时间(计划任务),以及加入消息总线的消息(例如Kinesis)。通常你的函数需要通过参数指定自己需要绑定到的事件源。

大部分供应商还允许函数作为对传入Http请求的响应来触发,通常这类请求来自某种该类型的API网关(例如AWS API网关、Webtask)。

BaaS(Backend as a Service,后端即服务)

BaaS(Backend as a Service,后端即服务)是指我们不再编写或管理所有服务端组件,可以使用领域通用的远程组件(而不是进程内的库)来提供服务。理解BaaS,需要搞清楚它与PaaS的区别。

首先BaaS并非PaaS,它们的区别在于:PaaS需要参与应用的生命周期管理,BaaS则仅仅提供应用依赖的第三方服务。典型的PaaS平台需要提供手段让开发者部署和配置应用,例如自动将应用部署到Tomcat容器中,并管理应用的生命周期。BaaS不包含这些内容,BaaS只以API的方式提供应用依赖的后端服务,例如数据库和对象存储。BaaS可以是公共云服务商提供的,也可以是第三方厂商提供的。其次从功能上讲,BaaS可以看作PaaS的一个子集,即提供第三方依赖组件的部分。

BaaS服务还允许我们依赖其他人已经实现的应用逻辑。对于这点,认证就是一个很好的例子。很多应用都要自己编写实现注册、登录、密码管理等逻辑的代码,而对于不同的应用这些代码往往大同小异。完全可以把这些重复性的工作提取出来,再做成外部服务,而这正是Auth0和Amazon Cognito等产品的目标。它们能实现全面的认证和用户管理,开发团队再也不用自己编写或者管理实现这些功能的代码。

腾讯云SCF介绍

腾讯云的ServerLess(云函数)写起来,和 AWS 的 serverless 是差不多一样的,因为腾讯云的serverless开发上很大程度的借鉴了AWS的云函数,所以本文将会以腾讯云的 SCF 进行演示开发

image-20211209124332792

参考文献

腾讯云SCF:https://cloud.tencent.com/product/scf
Go开发serverless参考文档:https://cloud.tencent.com/document/product/583/18032
Api网关触发:https://cloud.tencent.com/document/product/583/12513
本文代码下载:https://github.com/mailjobblog/dev_go/tree/master/211209-serverless

配置及开发步骤

函数创建

点击 “新建” 后,我这里选择了 “自定义创建” 即为空白模版(当然你也可以选择用模版创建)。
函数类型:我这里选择 ”事件函数“ ,因为待会我的目标是使用 api 调用云函数,如果你想托管静态网站的话,可以选择 ”Web函数“。
函数名称:根据业务需求可以自定义。
运行环境:你打算用什么语言开发就选择什么语言,这里我选择用 Go 语言开发。

image-20211209124641948

image-20211209124855304

函数创建完成后,我们现在腾讯云给的demo函数,然后根据自己的需求开发。

image-20211209125445981

下载后,我们可以看到,是这样的一份代码。

package main

import (
    "context"
    "fmt"
    "github.com/tencentyun/scf-go-lib/cloudfunction"
)

type DefineEvent struct {
    // test event define
    Key1 string `json:"key1"`
    Key2 string `json:"key2"`
}

func hello(ctx context.Context, event DefineEvent) (string, error) {
    fmt.Println("key1:", event.Key1)
    fmt.Println("key2:", event.Key2)
    return fmt.Sprintf("Hello %s!", event.Key1), nil
}

func main() {
    // Make the handler available for Remote Procedure Call by Cloud Function
    cloudfunction.Start(hello)
}

业务开发演示

对于下载的代码,我们进行一番改写,需求则是对于给定的数字,x和y,进行求和运算,并发挥计算结果。

package main

import (
    "context"
    "github.com/tencentyun/scf-go-lib/cloudfunction"
    "strconv"
)

func main() {
    // Make the handler available for Remote Procedure Call by Cloud Function
    // 调用 serverless 函数
    cloudfunction.Start(hello)
}

// serverless 函数
// 入参1:go语言内置的context,用于上下文
// 入参2:腾讯serverless传递的参数会放在这个里面
func hello(ctx context.Context, event DefineEvent) (ResultDiy, error) {
    // 接收传递的参数
    x := event.QueryString.X
    y := event.QueryString.Y

    // 业务实现
    s := strJoin(x,y)

    result := ResultDiy{
        ErrorCode: 200,
        String:  s,
    }

    return result, nil
}

// DefineEvent 入参2定义
// 该参数的定义,需要遵循腾讯serverless给的规范进行定义
// api网关触发集成概述:https://cloud.tencent.com/document/product/583/12513
type DefineEvent struct {
    QueryString struct {
        X string `json:"x"`
        Y string `json:"y"`
    } `json:"queryString"`
    HttpMethod string `json:"httpMethod"`
}

// ResultDiy 定义返回的内容
type ResultDiy struct {
    ErrorCode int64 `json:"errorCode"`
    String string `json:"string"`
}

// 模拟实体业务
func strJoin(x,y string)  string {
    length := strconv.Itoa(len(x + y))
    return length + "_" + x + "_" + y
}

参照腾讯文档,进行编译打包

GOOS=linux GOARCH=amd64 go build -o main main.go
zip main.zip main

上传与部署

image-20211209131910091

函数触发配置

使用 api 对刚刚写的云函数进行触发

首先,创建触发器

image-20211209132232279

Tips

触发方式:可以根据自己的需求选择,这里我选择 api 请求触发。
Api服务:即为api网关配置。
集成响应:这里我们选择不启用集成响应。意味着你可以自定义响应内容。否则你需要按照文档,返回对应的数据格式。

Api网关配置

因为刚刚选择“不集成响应”,所以我们需要在网关中指定返回的数据格式

在 Api网关 中,我们可以看到,刚刚自动生成的 api 服务。

image-20211209134403601

然后编辑api,选择返回的数据格式为json。

image-20211209134553236

测试Api触发

然后回到 “触发管理” 中,复制api访问路径。

image

请求测试

image-20211209135838664