结合阿里云 FC 谈谈我对 FaaS 的理解

这是第 76 篇不掺水的原创,想获取更多原创好文,请搜索公众号关注咱们吧~ 本文首发于政采云前端博客: 结合阿里云 FC 谈谈我对 FaaS 的理解

进入主题以前,先从背景简述下最近前端界的热点词汇 Serverless,其实,Serverless 这个概念在其余领域已经提出来好久了。javascript

Serverless

概念

Serverless 直译为无服务器,表明一种无服务器架构(也被称为“无服务器计算”),并不表示不须要物理服务器,而是指不须要关注和管理服务器,直接使用服务便可,其实就是一种服务外包或者说服务托管,这些服务由第三方供应商提供。css

具体来讲,Serverless 就是指服务端逻辑由开发者实现,运行在无状态的计算容器中,由事件驱动,彻底被第三方管理,而业务层面的状态则记录在数据库或存储资源中。html

目前国内一些大型公司如阿里、腾讯、滴滴都已经将 Serverless 逐步在业务中落地(案例分享:2020.06.19 ServerlessDays · China Online)。前端

Serverless 与 FaaS 的联系

Serverless = FaaS+BaaS ,是目前界内比较公认的定义:vue

  • FaaS(Function as a Service):函数即服务java

    • 负责服务端业务逻辑场景,须要开发者本身实现,服务的粒度比微服务更小,小到以函数为单位
    • 事件驱动的 Serverless 服务,毫秒级弹性伸缩
    • 没法进行内存或数据共享,是无状态的
    • 无需运维,部署、运维等都由云平台提供
  • BaaS(Backend as Service):后端即服务node

    • 负责通用服务场景,不须要开发者本身开发,由云厂商提供,好比数据库、身份验证、消息队列、对象存储等服务
    • 有状态

笔者认为,单看 FaaS 或者 BaaS,都是一种 Serverless ,只是通常咱们完整的应用须要二者结合才能实现。nginx

好,下面正式介绍 FaaS。git

FaaS

做为一个前端,咱们平日里很难接触到服务器、运维方面的操做。假设如今给你一个任务,让你本身开发一个有先后端交互的应用,并从 0 到 1 进行部署,是否是以为光靠本身根本搞不定,这个任务有点难。github

传统应用的部署,咱们须要作不少工做:准备服务器、配置环境、购买域名、配置 nginx、……。应用发布以后,咱们还要考虑运维的问题,线上监控,扩缩容,容灾等等等等。

如今,咱们运用 FaaS 去开发部署的话,以上都不用考虑,只须要专一于业务逻辑开发便可,由于其它一切都托管给 FaaS 平台帮咱们处理了。

概念

FaaS 是无服务器计算的一种形式。经过 FaaS,能够快速构建任何类型的应用和服务,它具备开发敏捷特性、自动弹性伸缩能力、免运维和完善的监控设施。所以:

  • 开发者只需专一于业务逻辑开发,无需管理服务器、运行环境等 IT 基础设施
  • FaaS 平台会为咱们准备好计算资源,以 弹性、可靠的方式运行咱们的代码,实现毫秒级弹性伸缩,轻松应对峰值压力
  • 用户只需根据函数的实际执行时间按量付费

所以,相比传统开发模式,FaaS 大大提升了开发和交付效率,是将来云服务发展的大趋势。自 2014 年始,在 AWS Lambda 以后,Google、IBM、Microsoft、阿里、腾讯、华为等国内外云厂商相继推出云函数计算平台 FaaS。

快速建立 FaaS 应用

函数计算开发方式有不少种,好比:Fun 工具、函数计算 FC 平台、Serverless VScode、云开发平台。本文借助阿里云函数计算平台,经过其提供的模版快速建立、部署一个 Web 应用,向你们更清楚地展现 FaaS 是什么。

本文直接基于模版建立,用户也能够选择本身上传应用代码直接部署 Web 应用。

咱们选择有先后端交互、数据增删改查等行为的 Todo List 应用,它是一个先后端一体化(先后端代码共属一个项目中开发、调试、部署,高效且节省资源) FaaS 应用。

服务/函数

服务

一个应用能够拆分为多个服务。从资源使用维度出发,一个服务能够由多个函数组成。先建立服务,再建立函数。

能够看到 TodoList 应用部署成功后建立好的服务,咱们能够对该服务进行配置、删除、查看指标等操做,还能够对其下的函数进行配置、删除。

函数

函数是系统调度和运行的单位。函数必须从属于服务,同一个服务下能够有多个函数,同一个服务下的全部函数共享相同的设置,例如服务受权、日志配置,但彼此相互独立,互不影响。

函数代码

FaaS 对多种语言都有良好的支持性,好比阿里云支持 Node.js、Python、PHP、Java 等等,开发者可使用本身熟悉的语言,根据平台提供的函数接口形式编写代码。这也意味着,团队协做时,你们能够利用多种语言混合开发复杂应用。

点击代码执行,能够看到这里有一个在线编辑器,里面就是模板生成的代码,能够在此处进行运行、调试。该应用前端页面用 React 实现,后端服务基于 Node 的 Express 框架。

函数入口

template.yml是咱们的函数信息配置文件,告诉云厂商咱们的代码入口函数、触发器类型等操做。

函数入口为src/index.handler ,即src/index.js服务端代码文件中的 handler 方法,该文件代码以下:

const { Server } = require('@webserverless/fc-express')
const express = require('express');
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');

// initial todo list
let todos = [
  {
    id: '123',
    text: 'Go shopping',
    isCompleted: false,
  },
  {
    id: '213',
    text: 'Clean room',
    isCompleted: true,
  },
];


const staticBasePath = path.join('public', 'build');

const app = express();

// index.html
app.all("/", (req, resp) => {
  resp.setHeader('Content-Type', 'text/html');
  resp.send(fs.readFileSync('./public/build/index.html', 'utf8'));
});

// 静态资源文件:js、css、图片
// static js resources  
app.all('/*.js', (req, resp) => {
  const filePath = path.join(staticBasePath, req.path);
  resp.setHeader('Content-Type', 'text/javascript');
  resp.send(fs.readFileSync(filePath, 'utf8'));
});

// static css resources
app.all('/*.css', (req, resp) => {
  const filePath = path.join(staticBasePath, req.path);
  resp.setHeader('Content-Type', 'text/css');
  resp.send(fs.readFileSync(filePath, 'utf8'));
});

// static svg resources
app.all('/*.svg', (req, resp) => {
  const filePath = path.join(staticBasePath, req.path);
  resp.setHeader('Content-Type', 'image/svg+xml');
  resp.send(fs.readFileSync(filePath, 'utf8'));
});

// static png resources
app.all('/*.png', (req, resp) => {
  const filePath = path.join(staticBasePath, req.path);
  resp.setHeader('Content-Type', 'image/png');
  resp.send(fs.readFileSync(filePath, 'utf8'));
});

app.all('/manifest.json', (req, resp) => {
  const filePath = path.join(staticBasePath, req.path);
  resp.setHeader('Content-Type', 'application/json');
  resp.send(fs.readFileSync(filePath, 'utf8'));
});

// 增删改查对应的api接口
// list api
app.get('/api/listTodos', (req, resp) => {
  resp.send(JSON.stringify(todos));
});

// create api
app.get('/api/createTodo', (req, resp) => {
  const { todo: todoStr } = req.query;
  const todo = JSON.parse(todoStr);
  todos.push({
    id: todo.id,
    text: todo.text,
    isCompleted: todo.isCompleted,
  });
  resp.send(JSON.stringify(todos));
});

// update api
app.get('/api/updateTodo', (req, resp) => {
  const { todo: todoStr } = req.query;
  const targetTodo = JSON.parse(todoStr);
  const todo = todos.find((todo) => todo.id === targetTodo.id);
  if (todo) {
    todo.isCompleted = targetTodo.isCompleted;
    todo.text = targetTodo.text;
  }
  resp.send(JSON.stringify(todos));
});

// remove api
app.get('/api/removeTodo', (req, resp) => {
  const { id } = req.query
  // TODO: Implement methods to filter todos, filtering out item with the same id
  // todos = todos.filter();
  const todosIndex = todos.findIndex((todo) => todo.id === id);
  if (todosIndex !== -1) {
    todos.splice(todosIndex, 1);
  } 
  resp.send(JSON.stringify(todos));
});

const server = new Server(app);

// 向外暴露了 http触发器入口
// http trigger entry
module.exports.handler = function(req, res, context) {
  server.httpProxy(req, res, context);
};

能够看到,咱们不须要本身起服务,FaaS 平台会为咱们管理。这个文件,有两个重要的部分:

  • 1.函数入口 handler,也是 HTTP 触发器入口,下文会详细介绍
// http trigger entry
module.exports.handler = function(req, res, context) {
  server.httpProxy(req, res, context);
};
  • 2.Web Service 和 api,经过路由调用相应的服务,好比请求路径为"/"时,会返回 Web 应用的 html 页面;请求"/api/*"时,调用接口返回数据

触发器

前面说过,FaaS 是一种事件驱动的计算模型,即函数的执行是由事件驱动的,没有事件触发,函数就不运行。与传统开发模式不一样,函数不须要本身启动一个服务去监听数据,而是经过绑定一个(或者多个)触发器。

触发器就是触发函数执行的方式,咱们须要为函数建立指定的触发器。

FaaS 应用的触发器有多种(不一样云厂商的触发器会有所区别),但基本都支持 HTTP、对象存储、定时任务、消息队列等触发器,其中 HTTP 触发器是最多见的。

以阿里云函数计算为例,介绍几个表明类型:

触发器类型

名称 描述
HTTP 触发器 1.HTTP 触发器经过发送 HTTP 请求触发函数执行,主要适用于快速构建 Web 服务等场
2.HTTP 触发器支持 HEAD、POST、PUT、GET 和 DELETE 方式触发函数
3.能够经过绑定自定义域名为 HTTP 函数映射不一样的 HTTP 访问路径
4.开发人员能够快速使用 HTTP 触发器搭建 Web service和 API
OSS 触发器(对象存储) 1.OSS 事件能触发相关函数执行,实现对 OSS 中的数据进行自定义处理
日志服务触发器 1.当日志服务定时获取更新的数据时,经过日志服务触发器,触发函数消费增量的日志数据,并完成对数据的自定义加工
定时触发器 1.在指定的时间点自动触发函数执行
API 网关触发器 1.API 网关做为事件源,当有请求到达后端服务设置为函数计算的 API 网关时,API 网关会触发函数的执行。函数计算会将执行结果返回给 API 网关
2.与 HTTP 触发器相似,可应用于搭建 Web 应用。相较于 HTTP 触发器,您可使用 API 网关进行 IP 白名单或黑名单设置等高级操做

开发者在调试时,若是不配置触发器,也可使用控制台、命令行工具 或者 SDK 等方式直接调用函数执行。

咱们点开 TodoList 的触发器,能够看到建立的 HTTP 触发器,WEB 用户经过 HTTP 请求便可触发函数的执行。

注意这里的提示语:打开连接,会下载一个 html 附件,这时咱们打开,由于找不到静态资源文件,应用不能正常运行。

能够点击自定义域名去用平台为咱们建立的临时域名打开:

能够看到,页面和功能都正常了。咱们查看、新增、更新、删除,在控制台里能够看到发起的请求和返回结果

HTTP 触发器

该应用 HTTP 触发器的入口函数形式以下:

// http trigger entry
module.exports.handler = function(req, res, context) {
  server.httpProxy(req, res, context);
};

配置 HTTP 触发器的函数能够经过 HTTP 请求被触发执行。此时函数能够看作一个 Web Server,对 HTTP 请求进行处理,并将处理结果返回给调用端

访问 html 页面、请求静态资源文件,以及请求接口,都是经过 http 请求去触发相应函数的执行。

能够在这里进行调试:

FaaS 框架

目前市面上已经有一些较为成熟的开源 FaaS 框架,好比 OpenFaaS、funktion、Kubeless、Fission等等,本文向你们介绍阿里云今年正式发布的Midway FaaS框架,它是用于构建 Node.js 云函数的 Serverless 框架,它提供了函数的本地开发、调用、测试整个链路。它能够开发新的 Serveless 应用,也提供方案将传统应用迁移至各云厂商的云函数。阿里内部已经使用一年多了。

咱们能够运用脚手架@midwayjs/faas-cli提供的能力在本地快速建立、调试、mock、部署一个 FaaS 应用。Serverless 有一个很大的弊端,就是和云服务商平台强绑定,可是Midway Serverles 是防平台锁定的,它能一套代码可以运行在不一样的平台和运行时之上,Midaway faas的部署能够跨云厂商,默认部署到阿里云FC,咱们也能够修改部署到其它平台,如腾讯云SCF、AWS Lambda。

Midway FaaS 体系也与云工做台进行告终合,使用了和本地一样的能力,这里选择登陆阿里云开发平台,用示例库模版再次建立一个 TodoList 应用进行演示,只不过这个是用 Midway FaaS 构建的。

代码目录结构能够简单抽取为:

|-- src
|        |-- apis //函数代码
|                |--    config //针对不一样环境建立配置文件
|                |--    configuration.ts //扩展能力配置
|                |--    index.ts // 函数代码入口文件,里面包括多个函数
|        |-- components // 前端组件
|        |-- index.tsx // 前端页面入口文件(该应用前端基于React,如果Vue,则是App.vue)
|-- f.yml // 函数信息配置文件

f.yml配置文件

service: serverless-hello-world

// 服务提供商
provider:
  name: aliyun
  runtime: nodejs10 //运行时环境及版本信息

// 函数具体信息(包括函数入口、触发器等等)
functions:
  render:
    handler: render.handler 
    events:
      - apigw:
          path: /*
  list:
    handler: todo.list 
    events:
      - apigw:
          path: /api/list
  update:
    handler: todo.update
    events:
      - apigw:
          path: /api/update
  remove:
    handler: todo.remove
    events:
      - apigw:
          path: /api/remove
  add:
    handler: todo.add
    events:
      - apigw:
          path: /api/add
          
// 构建的配置信息
package:
  include:
    - build //打包目录
  artifact: code.zip //打包名称

函数代码中一个函数对应一个 api 接口:

安装依赖后,咱们npm run dev,阿里云为咱们建立了一个临时域名用于调试:

能够看到请求的这些资源和接口数据:

一键部署,很是方便。

收费标准

传统应用咱们的服务是一直占用资源的,而 FaaS 在资源空闲时不收费,按需付费,能够大大节省开支。

收费标准:

  • 调用函数次数
  • 函数运行时间

由于每个月都有免费额度,因此在我的平常使用时基本不须要付费。

(PS:但仍是要特别注意,部署的应用不用时必定要及时下线,不然可能会收取费用,还有开通的服务、功能也必定要仔细留意一下收费标准,好比可能想解决冷启动的问题,会开通预留实例功能,若是咱们不用的话,必定要注意手动释放,不然即便它没有执行任何请求,也会从启动开始不断收费,费用可不小)

冷启动

再说说 FaaS 目前备受关注的一个问题——冷启动

FaaS 中的函数首次调用更新函数或长时间未调用时从新调用函数时,平台会初始化一个函数实例,这个过程就是冷启动,平均耗时在几百毫秒。

延迟问题

FaaS 由于冷启动,不能当即调用函数,调用延迟会给应用性能带来影响,针对冷启动的延迟问题,各大云服务商很是关注,正在想办法不断优化。

与冷启动相呼应的是热启动,热启动指函数调用时不用从新建立新的函数实例,而是直接复用以前的函数实例。由于 FaaS 函数若在一段时间内没有被事件触发运行,云服务商就会回收运行函数的容器资源,销毁函数实例,因此,在未被回收的这段时间内再次调用函数就是热启动;销毁后,从新建立就是冷启动。

延迟缘由

冷启动具体作了哪些操做呢?以阿里云为例,大体包括了调度实例、下载解压代码、启动容器、启动运行时,这一过程结束后,函数才开始执行。因此冷启动的启动消耗时间受到不少因素的影响:

  • 编程语言

    有专门研究对比,不一样语言的冷启动时间不一样

  • 代码大小

​ 这个过程在冷启动过程当中相对比较耗时,可能几十毫秒,也可能几秒,看代码体积大小

  • 容器建立

    这个过程的耗时取决于云服务商

  • 配置等

如何优化

各大云厂商都已经有了一些优化方案的最佳实践,须要开发者和云厂商共同努力:

  • 减小代码体积:

    • 开发者能够经过精简代码,删除无用依赖,加速下载函数代码过程
    • 好比腾讯云对代码作了两级的缓存,能够有效下降下载代码时间
  • 资源复用,缩短函数执行时间
  • 选择冷启动时间较少的语言
  • 选择合适的内存:函数内存越大,冷启动表现越优
  • 避免没必要要的配置
  • 下降冷启动频率

    • 使用定时触发器定时访问函数,这样能够防止函数实例一段时间没被使用被销毁
    • 使用 initializer 函数入口,函数计算会异步调用初始化接口,消除初始化用户代码的时间
  • 预留实例

执行时长

FaaS 还有一个局限性,就是平台会限制函数的执行时间,超出时间后执行代码的进程会被强行销毁,因此 FaaS 不适合长时间运行的应用。例如 AWS Lambda 函数不容许运行超过 15 分钟(之前只有 5 分钟),若是超过就会中断。使用时,应该根据本身的预期执行时间来设置超时值,防止函数的运行时间超出预期,而且建议调用函数的 client 端的 timeout 要稍稍大于函数设置的 timeout,这样才能防止执行环境不会意外退出。

FaaS 工做流程

相信你们读到这里,应该差很少能够明白 FaaS 的工做流程了,咱们总结一下:

  • 开发者编写函数代码,能够在线编辑或者本地上传,完成后,FaaS 平台为咱们部署应用,建立函数服务
  • 客户端经过设置的触发器,通知函数服务
  • 若存在函数实例,则直接在该执行环境中调用函数;没有,则先通过冷启动(调度实例、下载代码、启动实例、启动运行时),再执行函数
  • 函数根据用户请求量动态扩容响应请求,将内容返回给用户。函数执行完后,若一段时间内无事件触发,函数实例就会被销毁,FaaS 应用快速缩容到 0

对前端的影响

Serverless 如今这么热,它对前端到底有什么影响呢?

整个实践下来发现,FaaS 帮咱们前端扩展了能力边界,做为前端,咱们本身一我的也能快速完成先后端开发以及部署工做,彻底不用关心服务器以及运维方面咱们不擅长的问题。前端也有机会参与服务端业务逻辑开发,更深刻业务,创造更大的价值。

结语

本文结合阿里云 FC、Midway FaaS 框架快速建立 FaaS 应用的实践,向你们展现了什么是 FaaS,FaaS 的工做流程,优缺点,展示了 FaaS 颠覆传统开发模式的魅力。如今 FaaS 的应用场景很是普遍,Web 应用及小程序等移动应用、AI 及机器学习、物联网、实时数据处理等等。Serverless 时代,生产效率大大提升,每一个人都有更多机会创造无限可能,让咱们一块儿为将来加油!

参考文章

Serverless Handbook——无服务架构实践手册

阿里云函数计算使用文档

Midway Serverless 使用文档

腾讯云函数计算冷启动优化实践

Serverless Architectures(译文)—(Martin Fowler)

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 40 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在平常的业务对接以外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推进并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

若是你想改变一直被事折腾,但愿开始能折腾事;若是你想改变一直被告诫须要多些想法,却无从破局;若是你想改变你有能力去作成那个结果,却不须要你;若是你想改变你想作成的事须要一个团队去支撑,但没你带人的位置;若是你想改变既定的节奏,将会是“5 年工做时间 3 年工做经验”;若是你想改变原本悟性不错,但老是有那一层窗户纸的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但愿参与到随着业务腾飞的过程,亲手推进一个有着深刻的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我以为咱们该聊聊。任什么时候间,等着你写点什么,发给 ZooTeam@cai-inc.com

相关文章
相关标签/搜索