这里写目录标题
cloudfunction和lambda分别是gcp和aws的serverless产品,因为两者都使用过,就写一下使用感想。
serverless是什么
serverless是公有云厂商提供的一种faas产品,开发者只需要提供函数function,就可以使得这个函数拥有对外服务的能力。gcp/aws/tencent/ali cloud都有提供对应的解决方案。
cloudfunction和lambda使用上有差异,下面主要讨论cloudfunction
cloudfunction目前支持的数据源有:http/pubsub/cloud storrage, 常用的是http与pubsub(pubsub是gcp的mq产品,类似kafka)
传统web开发
我们先换个角度来看,如果我们按传统的开发方式一个http的应用,部署一个应用,在公网可以访问的,一般需要几个组件
首先要有dns解析,流量才能找到对应的host,然后是网关,网关会配置路由把流量导入backend app。
要在生产环境使用,就会遇到一些很经典的问题,它来了
网关
- 是高可用的吗?
- 足够弹性吗?
- 能扛多大流量?
- 可以自动扩容吗?
backend
- 是高可用的吗?
- 足够弹性吗?
- 能扛多大流量?
- 可以自动扩容吗?
- 版本管理以及回滚方便吗?
如果使用cloudfunction,上面这些疑问都不是问题,因为cloudfunction天然具备这些特性
cloudfunction
作为gcp的产品,cloudfunction支持语言还是比较多的。有些公有云厂商只支持脚本类语言(nodejs/php),编译类语言现在还未支持,相对而言,但是gcp支持的语言数量还是有优势的。使用了cloudfunction,应用天然就具备了以下特性
- 部署版本管理
- 流量入口
- 弹性扩容
- 较为完善的监控指标
- log&log metrics支持
支持的开发语言
- go1.13+
- java11
- nodejs 8/10
- python3.7/3.8
helloworld
下面以golang为例,写一个helloworld应用
// Package p contains an HTTP Cloud Function.
package p
import (
"encoding/json"
"fmt"
"html"
"net/http"
)
// HelloWorld prints the JSON encoded "message" field in the body
// of the request or "Hello, World!" if there isn't one.
func HelloWorld(w http.ResponseWriter, r *http.Request) {
var d struct {
Message string `json:"message"`
}
if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
fmt.Fprint(w, "Hello World!")
return
}
if d.Message == "" {
fmt.Fprint(w, "Hello World!")
return
}
fmt.Fprint(w, html.EscapeString(d.Message))
}
可以发现,对于go应用开发,基本是没有sdk入侵的(实际上是有一层sdk包装的,也就是main函数的入口部分,不过对于业务开发并不可见)。
到这一步,就可以提交代码完成部署了,暴露公网访问权限,就可以通过api访问你的serverless api应用。
参数传递
serverless本身是无状态的,如果需要处理参数传递的场景,一般有两种办法:
- 把配置文件上传,也就是从文件系统读取,只需要确认路径即可
- 通过环境变量
serverless的缺点
上面有提及serverless的优点,接下来讨论一下serverless的缺点,或者说是不适用的场景。
收费模式&成本
serverless与传统的web server部署方式不太一样,可以认为是一个api请求,就拉起一个实例(cloudfunction里面叫instance,lambda里面叫concurrency),不同的实例之间没有共享数据。而且,serverless基本都是后付费模式,账单会有延迟,所以如果没有靠谱的使用量监控措施,就要小心延迟账单的问题,否则用到破产了也不知道咋回事。
那么收费相关的因素有几个:
- api请求数量,这个通常没有办法优化
- 单个api请求的处理时间,耗时api要慎重上线。一般耗时
- 单个api 吐log规模,每个请求都会吐log,log存储也是有成本的,乱打log容易破产。常见的处理方法是控制优先级,优先级基本可以过滤很多无用的log。对于一些debug属性的,也可以考虑抽样打log,在一定调用量的前提下,也能看出一些问题。
- 是否设置最大实例数(如果没有设置,被恶意访问的话,成本蹭的一下就上去了,而且账单延迟的特性会可能会让你破产而且你还不知道)
涉及db存储类应用
慎用,serverless应用连db的连接数就是个炸弹,链接无法管理释放。
配置读取
目前可用的只有配置文件、环境变量,或者从其它api应用读取
有状态应用
解决不了
总结
看完上述内容,应该知道,serverless真正合适的场景,
- 无状态应用,不直接操作db类
- 处理逻辑越简单越好
- 需要弹性抗流量
目前我这也并未大规模使用serverless,只在部分很简单的场景才会用到。其实还有很多细节没处理好,包括:
- go/java这种编译类语言,部署时间较长(可能要几分钟),紧急升级的时候就太慢了。
- serverless这类服务的代码repository管理,也是个头痛的问题,因为serverless功能一般不会做太复杂,代码量相对精简,一般都会集中在几个repository管理,ci/cd要做相应的支撑。