Faas,又一个未来?

经同事独家授权,原创发表此文

作者说明:

**苗立尧 **
易宝支付运维工程师,热爱Kubernetes,对容器生态圈具有浓厚兴趣
个人公众号:容器时代


前言

云计算时代出现了大量XaaS形式的概念,从IaaS、PaaS、SaaS到容器云引领的CaaS,再到火热的微服务架构,以及现在越来越多被谈起的Serverless和FaaS,我们正在经历⼀一个技术飞速变革的时代。

一、什么是Faas

云计算时代出现了大量XaaS形式的概念,从IaaS(Infrastructure as a Service)、PaaS(Platform as a Service)、SaaS(Software as a Service)到容器云引领的CaaS(Containers as a Service),再到火热的微服务架构,它们都在试着将各种软、硬件资源等抽象为一种服务提供给开发者使用,让他们不再担心基础设施、资源需求、中间件等等,在减轻心智负担的同时更好地专注于业务。FaaS是Functions as a Service的简称,它往往和无服务架构(Serverless Architecture)一同被提起。

Serverless的概念刚刚出现在HackerNews时并不为大众所接受。后来随着微服务和事件驱动架构的发展才慢慢引起关注。Serverless并不是说没有服务器参与,它通过将复杂的服务器架构透明化,使开发者专注于“要做什么”,从而强调了减少开发者对服务器等计算资源的关注、工作粒度从服务器切换到任务的思想。2006年第一个支持“随用随付”的代码执行平台Zimki问世。2014年亚马逊AWS推出了Lambda成为最主要的无服务架构的代表。接着Google、IBM和Microsoft也纷纷推出了各自支持Serverless的平台。

微服务架构近年来是一个非常火爆的话题,大大小小的公司都开始逐步分拆原来的单体应用,试着转换到由各个模块服务组合成大型的复杂应用。Serverless可以看作是比微服务架构更细粒度的架构模式,即FaaS。Lambda也是FaaS的典型代表,它允许用户仅仅上传代码而无需提供和管理服务器,由它负责代码的执行、高可用扩展,支持从别的AWS服务或其他Web应用直接调用等。以电子商务应用为例,微服务中可以将浏览商品、添加购物车、下单、支付、查看物流等拆分为解耦的微服务。在FaaS里,它可以拆分到用户的所有CRUD操作代码。当发生“下单”事件时,将触发相应的Functions,交由Lambda执行。人们在越来越多的场景里将Serverless和FaaS等同起来。

这里写图片描述

假设现在有下面的JavaScript代码:

module.exports = function(context, callback) { callback(200, "Hello, world!
"); }

显然它是一个函数,通过FaaS的方式,我们可以通过访问一个URL的方式调用这个函数。

$ curl -XGET localhost:8080 
Hello, world!

FaaS拥有下面的特点:

1、FaaS里的应用逻辑单元都可以看作是一个函数,开发人员只关注如何实现这些逻辑,而不用提前考虑性能优化,让工作聚焦在这个函数里,而非应用整体。

2、FaaS是无状态的,天生满足云原生(Cloud Native App)应用该满足的12因子(12 Factors)中对状态的要求。无状态意味着本地内存、磁盘里的数据无法被后续的操作所使用。大部分的状态需要依赖于外部存储,比如数据库、网络存储等。

3、FaaS的函数应当可以快速启动执行,并拥有短暂的生命周期。函数在有限的时间里启动并处理任务,并在返回执行结果后终止。如果它执行时间超过了某个阈值,也应该被终止。

4、FaaS函数启动延时受很多因素的干扰。以AWS Lambda为例,如果采用了JS或Python实现了函数,它的启动时间一般不会超过10~100毫秒。但如果是实现在JVM上的函数,当遇到突发的大流量或者调用间隔过长的情况,启动时间会显著变长。

5、FaaS需要借助于API Gateway将请求的路由和对应的处理函数进行映射,并将响应结果代理返回给调用方。

比如对于一个简单的3层Web应用,在这里后端系统实现了大部分业务逻辑:认证、搜索、事务等,它的架构如下:

这里写图片描述

如果采用Serverless架构,将认证、数据库等采用第三方的服务,从原来的单体后端里分拆出来(可能需要在原来的客户端里加入一些业务逻辑)。对于大部分的任务,通过函数的形式进行执行,而不再使用一直在线的服务器进行支持,如此一来它的架构看起来就清晰多了:


这里写图片描述

这样的拆分除了让各个组件(函数)间充分解耦,每个都很好地实现了单一职责原则(SRP, Single Responsibility Principle)以外,它的好处还有:

  • 减少开支
    通过购买共享的基础设施,同时减少了花费在运维上的人力成本,最终减少了开支。
  • 减轻负担
    不再需要重复造轮子,需要什么功能直接集成调用即可,也无需考虑整体的性能,只专注于业务代码的实现。
  • 易于扩展
    云上提供了自动的弹性扩展,用了多少计算资源,就购买多少,完全按需付费。
  • 简化管理
    自动化的弹性扩展、减少了打包和部署的复杂度、可以快速推向市场,这些都让管理变得简单高效。
  • 环保计算
    即使在云的环境上,仍习惯于购买多余的服务器,最终导致空闲。Serverless杜绝了这种情况。

在Martin Flower的专栏文章Serverless Architectures曾这样定义Serverless架构:

"Serverless architectures refer to applications that significantly depend on third-party services(AKA Backend as a Service or "BaaS") or on custom code that is run ephmemeral containers (Function as a Service or "FaaS")"

正如前面提到了FaaS的每个函数都拥有快速启动和短暂生命周期的特性,让容器作为任务函数运行的基本单位,是不是非常适合FaaS的场景?同样,作为最热门的容器编排工具的Kubernetes又该怎样应对FaaS呢?

二、Kubernetes 与 FaaS

Fission是一款基于Kubernetes的FaaS框架。通过Fission可以轻而易举地将函数发布成HTTP服务。它通过读取用户的源代码,抽象出容器镜像并执行。同时它帮助减轻了Kubernetes的学习负担,开发者无需了解太多K8s也可以搭建出实用的服务。Fission目前主要支持NodeJS和Python,预支持C# .NET,对Golang的支持也在进行中。Fission可以与HTTP路由、Kubernetes Events和其他的事件触发器结合,所有这些函数都只有在运行的时候才会消耗CPU和内存。

Kubernetes提供了强大的弹性编排系统,并且拥有易于理解的后端API和不断发展壮大的社区。所以Fission将容器编排功能交给了K8s,让自己专注于FaaS的特性。

这里写图片描述

对于FaaS来说,它最重要的两个特性是将函数转换为服务,同时管理服务的生命周期。有很多办法可以实现这两个特性,但需要考虑一些问题,比如“框架运行在源码级?还是Docker镜像?”,“第一次运行的负载多少能接受”,不同的选择会影响到平台的扩展性、易用性、资源使用以及性能等问题。

为了使Fission足够易用,它选择在源码级工作。用户不再参与镜像构建、推仓库、镜像认证、镜像版本等过程。但源码级的接口不允许用户打包二进制依赖。Fission采用的方式是在镜像内部放置动态的函数加载工具,让用户可以在源码层操作,同时在需要的时候可以定制镜像。这些镜像在Fission里叫做“环境镜像”,它包含了特定语言的运行时、一组常用的依赖和函数的动态加载工具。如果这些依赖已经足够满足需求,就直接使用这个镜像,否则的话需要重新导入依赖并构建镜像。环境镜像是Fission中唯一与语言相关的部分。可以把它看做是框架里其余部分的统一接口。所以Fission可以更加容易扩展(这看起来就像VFS一样)。

FaaS优化了函数运行时的资源使用,它的目标是在运行的时候才消费资源。但在冷启动的时候可能会有些资源使用过载,比如对于用户登录的过程,无论多等几秒都是不可接受的。为了改变这个问题,Fission维持了一个面向任何环境容器池。当有函数进来时,Fission无需启动新容器,直接从池里取一个,将函数拷贝到容器里,执行动态加载,并将请求路由到对应的实例。

这里写图片描述

除了安装在本地的Fission主程序外,Fission-bundle设计为一组微服务构成:

  • Controller: 记录了函数、HTTP路由、事件触发器和环境镜像
  • Pool Manager: 管理环境容器,加载函数到容器,函数实例空闲时杀掉
  • Router: 接受HTTP请求,并路由到对应的函数实例,必要的话从Pool Manager中请求容器实例

在Kubernetes上,这些组件都以Deployment的方式运行,并对外暴露Service。除了这三个Fission特有的组件外,还用了Etcd作为资源和映射的存储,同样也以Deployment的方式启动。Controller支持Fission的API,其他的组件监视controller的更新。Router暴露为K8s里的LoadBalancer或NodePort类型的服务(这取决于K8s集群放在哪里)。

目前,Fission将一个函数映射为一个容器,对于自动扩展为多个实例的特性在后续版本里。以及重用函数Pods来支持多个函数也在计划中(在这种情况下隔离不是必须的)。Fission文档简单介绍了它的工作原理:

"当Router收到外部请求,它先去缓存Cache里查看是否在请求一个已经存在的服务。如果没有,要访问请求映射的服务函数,需要向Pool Manager申请一个容器实例执行函数。Pool Manager拥有一个空闲Pod池。它选择一个Pod,并把函数加载到里面(通过向容器里的Sidecar发送请求实现),并且把Pod的地址返回给Router。Router将外部请求代理转发到该Pod,并将响应结果返回。Pod会被缓存起来以应对后续的请求。如果空闲了几分钟,它就会被杀死"

对于较小的REST API来说,Fission是个很好的选择,通过实现webhooks,可以为Slack或其他服务编写chatbots。

Fission同时还支持根据Kubernetes的Watch机制来出发函数的执行。例如你可以设置一个函数来watch某个命名空间下所有满足某个标签的pod,这个函数将得到序列化的对象和这个上下文的Watch Event类型(added/removed/updated)。又如通过设置事件处理函数可以将它应用于简单的监控,指定当任意一个服务添加到集群时向Slack发送一条消息。当然也有更复杂的应用,例如编写一个watching Kubernetes第三方资源(Third Party Resource)的自定义controller。

在Fission的官网上有个入门的使用示例:

$ cat hello.js
module.exports = function(context, callback) {
    callback(200, "Hello, world!\n");
}

# Upload your function code to fission
$ fission function create --name hello --env nodejs --code hello.js

# Map GET /hello to your new function
$ fission route create --method GET --url /hello --function hello

# Run the function.  This takes about 100msec the first time.
$ curl http://$FISSION_ROUTER/hello
Hello, world! 

如果是第一次运行,需要先准备NodeJS的运行环境:

# Add the stock NodeJS env to your Fission deployment
$ fission env create --name nodejs --image fission/node-env

通过阅读Fission的源码,可以很清晰地看到它的执行过程:

1. fission env create --name nodejs --image fission/node-env
这里写图片描述
2. fission function create --name hello --env nodejs --code hello.js
这里写图片描述

同样,由fission主程序执行命令function和子命令create,通过--name参数指定函数名为hello,--env参数确定环境,--code参数确定要执行的函数代码。通过POST向/v1/functions发出请求,携带函数信息的JSON。controller拿到JSON后进行函数资源的存储。首先将拿到UUID,然后写到文件名为该UUID的文件里。接着向ETCD的API发送HTTP请求,在file/name路径下有序存放UUID。最后类似上面env命令,将UUID和序列化后的JSON数据写到ETCD里。

3. fission route create --method GET --url /hello --function hello
这里写图片描述

fission通过参数--method指定请求所需方法为GET,--url指定API路由为hello,--function指定对应执行的函数为hello。通过POST向/v1/triggers/http发出请求,将路由和函数的映射关系信息发送到controller。controller会在已有的trigger列表里进行重名检查,如果不重复,才会获取UUID并将序列化后的JSON数据写到etcd里。

前面的都是由本地的fission程序完成的。我们已经预先创建了fission-bundle的Deployment和Service。它创建了名为fission的命名空间,并在里面启动4个Deployment,分别是controller, router, poolMgr, etcd,并创建NodePort类型的Service: controller和router,分别监听端口31313和31314。同时创建另一个名为fission-function的命名空间用来运行执行函数的Pod.

router使用Cache维护着一份function到service的映射,同时还有trigger集合(有个goroutine通过controller保持对这个trigger集合的更新),在启动时按照添加trigger里的url和针对对应函数的handler初始化路由。

4. curl http://$FISSION_ROUTER/hello

当执行该curl时,请求发送至router容器。收到请求后会转发到两个对应的handler。一个是用户定义的面向外部的,一个是内部的。实际上它们执行的是同一个handler。任何handler都会先根据funtion名去Cache里查找对应的service名。如果没有命中,将通过poolmgr为函数创建新的Service,并把记录添加到Cache。然后生成一个反向代理,接收外部请求,然后转发至Kubernetes Service。

Poolmgr在创建新的service时,会根据env创建Pod pool(初始大小为3个副本的deployment),然后从中随机选择一个Ready的Pod。接着为此建立对应的Service。

这里写图片描述

Fission是一个开源项目,由Platform 9和社区进行开发。社区正在努力让Kubernetes上的FaaS更加易用和轻松集成。在未来几个月将添加单元测试、与Git集成、函数监控和日志聚合等特性,同时也会跟其他的Events进行集成,对了,还有为更多的语言创建环境。在今年1月份,Fission发布了alpha版。

三、后记

容器技术的出现改变了软件交付的思维,微服务和Serverless虽然没有减少软件生命周期中的环节,但确实改变了下游软件部署和维护的理念,提高了软件开发人员的效率。FaaS是未来的一种可能的走势,但一定不会是最终的未来。总有一天FaaS又会被其他技术所代替。生活在这个信息爆炸、技术飞速更迭的时代很烦恼也很幸福。这就是我们所在的时代,我们正在亲身经历着未来。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 写这篇文章主要是为了今后毕业论文素材上的整理,同时对docker进行巩固温习。大纲: docker简介docker...
    胡图仙人阅读 7,394评论 2 96
  • 看到的一篇关于FaaS介绍(典型代表,AWS的Lambda), 感觉很不错 转载自 http://blog.csd...
    曹盛泽阅读 3,154评论 1 4
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,478评论 25 707
  • 这是本地一家课外培训中心,小学至高中语,数,外课程涵盖其中,最大特色奥数,全市孩子百分之四十到这里学习,从普通班,...
    兰馨儿的简单阅读 208评论 0 1