辛宝的玄酒清谈!
2477 words
12 minutes
book已读完-前端 Serverless 面向全栈的无服务器架构实战

#serverless

image.png

杨凯 中国工信出版集团

大纲#

  • 综述颠覆性影响、理解 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 等

没了。

总结展望#

第二部分比较精彩,其他一般。

book已读完-前端 Serverless 面向全栈的无服务器架构实战
https://ijust.cc/posts/book-serverless-full-stack-infra/
Author
辛宝 Otto
Published at
2023-09-23