#serverless
杨凯 中国工信出版集团
大纲
- 综述颠覆性影响、理解 sls 和目前技术的定位关系
- FaaS 是 Serverless 核心思想的实际应用技术
- BaaS 是 sls 的另一大分值体系
概述
#cloudnative 云原生被提到最多的概念就是 serverless 了
sls 的概念、sls 的开发理念、极低的运维成本、大幅下降的服务器费用
举例 github pages,开发者把文件部署为静态站点,分配域名、访问服务。屏蔽了很多细节。
举例 CDN,无需关注细节、节点,全球用户高速访问。
可以认为把计算资源作为服务的方式提供产品,复合 serverless 理念,屏蔽技术细节,对外提供服务。
CNCF 在 2018 年发布了 serverless 白皮书
sls 是指无论在应用的构建还是运行,都不用对服务器进行维护和管理
sls 计算平台应该包含一种或者两种能力 faas baas
接下来介绍,使用场景,优势劣势
faas 的优势:研发效率搞、部署成本低、运维成本低、学习成本低、服务器费用低、部署方案灵活、系统安全性高
劣势:平台学习成本高、调试成本高(运行时在云端,本地调试、日志查询困难)、冷启动、供应商锁定
使用场景:
- 函数本身无状态,和持久化服务器融合
- 函数独立工作,彼此大量函数联动计算费用会上升
- 自动伸缩
- 事件驱动,http、数据库修改、定时事件等
- 冷启动要求低的场景
faas 本身不支持 http 协议,所以需要通过 api gateway 对外提供 web api
sls 和服务端技术
单体应用 - 分层架构,UI 层、业务逻辑层 Business Logic Layer、数据访问层 Data Access Layer
三层架构的基础上,比如 企业应用架构模式、领域驱动设计两本书,进一步区分
- 应用层
- 领域层
- 持久层
- 基础设施层
还是分层的思路,对代码切分,达到关注点分离 Separation of concerns SOC 的目标。
我能不能抽离 登录、权限判断等逻辑,从而在不同业务之间进行复用
微服务 microservices 架构风格,从分布式架构演变而来。多个独立小型服务进行轻量 、可控的软件研发管理。服务之间通过 RPC 实现相互通信,这样各个服务就可以是哟给你不同的技术栈完成功能。
设计系统的架构受制于组织的沟通结构。康威定律。什么样的组织架构,就设计出什么样的架构。比如小公司,单体应用,规模扩大,新增人员需要重新熟悉整体内容,这是网状结构,彼此都需要同步信息,沟通成本指数级增加。
单体拆分为微服务,只关注自己的业务,屏蔽不必要的信息,降低沟通成本
容器化、云计算、noops- devops 的下一阶段,减少研发人在运维的投入,是一种理念。
sls 和前端技术
bff,后端服务于前端。在前端和后端之间做胶水层,做信息的聚合和裁剪。一个接口完成多个接口的操作。移出不需要的字段等。
这让接口更加灵活。沟通成本低。减少请求做性能优化、减少数据暴露做安全性
graphQL 在多语言的微服务架构下不容易应用,改造成本太高,目前没有太多跨语言。跨数据库统一实现聚合查询的能力。如果与 serverless 结合才有可能
FaaS 技术
事件驱动。是一种设计模型。
faas 函数同样是事件驱动,不同的 trigger 触发器作为事件源。比如 http 触发器
函数无状态足够简单。
创建函数。里面有很多技术细节,现在改版多次了已经。
- 运行时选择
- 默认的
- 自定义运行时,这种兼容性最高
- 自定义容器,比如 GPU 容器
- 基本信息,名称、区域、触发器事件和 http
- 代码上传
- 示例 demo
- zip 包压缩
- oss 上传
- 文件夹上传
- 规格设计
- cpu 0.05~16g
- 内存 128M ~ 32 G
- 临时硬盘 512M、10G
- 如果选择容器部署,还可以选择 GPU T4/A10 规格
- 实例并发度。同时处理多少个请求
- 超时时间 60s
- 时区
- 鉴权认证
- 签名
- jwt
2015 年,开源社区出现了 serverless framework,目标是成为 sls 的框架和生态系统,解决供应商锁定的问题。
编写细节忽略
7 函数生命周期
module.exports.handler = function (request, response, context) {
// code
(async () => {
response.setStatusCode(200);
response.setHeader('content-type', contentType);
response.send(fs.readFileSync(path))
})().catch(err => {
response.setStatusCode(500);
response.setHeader('content-type', 'text/plain');
response.send(err.message);
});
}
8 理解函数运行时
设计模式 23 种设计模式
消息队列,能解决高并发的问题,也能实现系统解耦。削峰填谷。保证信息按顺序接受。
突然想到 信息触发的方案,站内信、短信、微信推送等。
9 自建简易 FaaS
要保证各函数的安全性,避免互相打扰,隔离的关键技术是沙箱 Sandbox
- 使用 docker 隔离
- 使用进程隔离,不如 docker
使用 master 监听函数调用,启用子进程 child 执行函数。返回的结果通信给主进程。
这里使用 child_process.fork()
启动子进程实现隔离。
如果执行代码可以用 eval/Function 来比较,最佳的方案还是 node 的 new vm.Script(code)
方案
但 vm 也会有风险,举例 this.constructor.construcotr
原型链的设计,所以没有原型链就好了
const sandbox = Object.create(null)
vm.createContext(sandbox)
vm.runInContext(code,sanbox)
但是也不完美,社区中使用 vm2
,通过 proxy 特性进行封装,更加安全。
因此,运行时使用 vm2 和 child_process.fork 组合使用,可以实现隔离和用户代码执行。
实现 http 协议支持,可以使用 koa 来实现。动态下载函数并执行。。
简易版完成,但还需要考虑吞吐性能、安全稳定、开发效率。
每次执行都会创建 子进程来执行,这个进城的创建和销毁管理是性能开销,高并发时候过多的进城也可能导致崩溃,这就考虑 进程池了。
可以使用 cluster,对 child_process
的进一步抽象封装,用起来更好用。
使用 cluster 和 vm2 配合 koa 就能实现一个方案了。
问了 gpt, 可以考虑 generic-pool
:这个模块提供了一个通用的资源池,可以用于管理各种资源,包括进程。你可以使用它来创建一个进程池,从而避免频繁地启动和停止子进程。它提供了灵活的配置选项,允许你自定义池的大小、资源分配策略等。
用户代码如果用了死循环,就无法结束任务了。设定超时时间。 vm/vm2 都有 timeout 比如设置 5000ms
异步调用问题,默认的超时不起作用,可以考虑自行实现计时器
确保稳定性,资源限制。cpu、内存、磁盘的高强度使用。要限制资源,在 Linux 里有 CGroup 限制资源,docker 里也用到了这个能力。
介绍了一堆 CGroup 的概念,略过细节,通过命令就可以限制某个进程最多使用 20% 的 cpu 资源了。有点复杂,gpt 答的挺好
提高效率,内置前端常用服务。
- 简单的 kv 存储,使用 vm2 实现 get/set
当然,最好还是 redis
BaaS 技术
backend as a service。
![[Pasted image 20230923233047.png]]
后续提到了 firebase 一展示提供了很多开箱机用的基础服务,比如云数据库、云函数、auth、托管、存储等。
还有崩溃报告、性能监控、test lab、应用分发等功能。
还有拓展类的运营功能
- 应用内消息 in-app messaging
- 分析
- a/b testing
- cloud messaging 云消息,推送 IM 等
- remote config 配置中心
国内的 leancloud/bmob 等,整体完整性还有差距。
数据库设计原则部分。
比如 posts 和 comments 两张表查询,会有 select 1+n 的问题,也就是需要先查询 n 条记录找到信息,再查询 n 次对应的数据。sql 中使用 join 就行
举个例子,最近五条评论的内容,所属文章标题。
使用 sql 比较简单。如果提前设计成嵌入的方案就容易。如果已经变成引用的方案了,可能需要保留更多冗余内容。设定一个新集合,最新评论的集合,冗余字段。如果有读写问题,就可以改成缓存,一小时更新一次。这带来的问题是,删除时候需要同步删除多份。
如果使用内嵌,一次查询就可以了,而且查询性能好。对于嵌套的复杂数据就不好了。先把数据聚合再排序,实现也是放入内存中,大量数据可能就不好。
快速介绍了 CDN、对象存储等功能
用户鉴权介绍了 OneID 不流行的趋势,介绍了 OAuth 2.0
最终纳入了 IETF 组织,实现了标准化。
oauth2 里提供了四中授权模式
- 授权码 auth code,默认
- 简化模式
- 密码
- 客户端凭证
后面三种比较特殊,不用管
OAuth 解决的是授权,不是用户认证,引入了 OIDC - openID Connect
进一步拆分了 id token 和 access token
jwt 是 rfc 7519
对接第三方会比较费劲,就产生了 IDaaS 比如 auth0 网站和 authing 网站
- 身份认证 账户授权
- sso single sign in 一个应用登录,多个应用共享
- 对外提供 oauth2
- 统一发送邮件、短信重置密码
- 企业身份登录
- 两步验证
可以看看,有一些 user/rule/rules/hooks 等
没了。
总结展望
第二部分比较精彩,其他一般。