在当前的软件架构领域,Serverless是一个非常热的话题。在市场上,你已经可以看到很多的相关书籍,开源的开发框架,相关的产品,甚至有关于这个话题的Conference会议。但是为什么Serverless这么热呢?希望这篇文章能够给你一些有用的信息。 开篇我们将先说明Serverless的概念,在后续的章节中我将尽量保持中立来分析Serverless的优势和劣势。 什么是Serverless?就像其他的软件领域一样,对于Serverless本身并没有一个清晰的定义,Serverless实际上可以表示2个不同但是有所重叠的领域:
在后续的章节中我将重点讨论第二种Serverless架构,因为1)这种结构是一种全新的架构;2)它改变了我们对技术架构的认识;3)这种结构是目前一种流行的架构。 |
然而这些理念都是相关的,并且事实上,正在慢慢融合。其中一个好的例子——Auth0,开始的时候,它是一个BaaS,但是随着Auth0 Webtask的到来,慢慢地变成了FaaS。 此外有很多案例,在开发BaaS型的应用时,特别是开发基于网页的应用而不是移动端应用时,你很可能需要一些传统服务器端的功能。FaaS是一个解决此类问题的好方案,如果他们是继承于你正使用的BaaS服务就更是如此了。这些功能的例子有数据校验(识别冒充的客户端)、计算机密集计算(比如图像和视频处理)。 一些例子UI-驱动型应用 让我们从服务端逻辑上来探讨下一个3层的客户端导向系统。常见的电子商务应用时一个好的例子(请容许我拿一个网上宠物店来当例子)。 一般的,这个架构会像下面的图这样,然后比如说服务端是用java写的,客户端由js或者html写的。
这个架构下,客户端会十分的傻,因为大多数的逻辑处理比如系统认证、页面迁移、搜索、交易都是由服务端应用处理的。在无服务器化的架构下,可见下图所示的样子:
|
这是一个十分简化的视图,但即便如此,这里还是有许多有意义的变化。请注意这不是一个架构迁移的推荐,我仅仅是想通过这个来揭示一些无服务器化的概念! 1.我们将原来应用的认证逻辑系统删除了,替换成一个第三方的BaaS服务。 2.使用另一个BaaS服务,我们将允许服务端直接连接到我们的数据子库,这个数据子库完全由第三方所有(比如AWS Dynamo)。我们从而可以有一种和其他服务器访问数据库资源方法的迥然不同安全机制。 3.前面两点意味着更重要的第三点——之前在宠物店服务器端的逻辑结构现在存在于客户端,比如记录用户会话,理解UX的应用框架(比如页面导航),从数据库读取数据然后将其转换成一个可用的视图等等。客户端事实上已经变成了一个单页面应用。 4.有一些UX相关的功能,我们希望留在服务器中,比如,如果是密集计算或者需要连接到大量的数据的情况,像搜索就是这样的例子。考虑到搜索的特点,与其部署一个一直运行的服务端,不如部署一个FaaS的服务,通过API网关(后面再介绍)来相应http请求。从而客户端和服务器从同一个数据库中读取产品数据。由于初始的服务端是由java开发的,并且AWS Lambda(FaaS的开发者)支持java,所以我们可以将服务端的搜索代码迁移到宠物商店的搜索函数中,从而不用重新代码。 5.最后我们可以使用另外的FaaS函数替换我们的购买功能,因为安全考虑,存放在服务端还不如放在客户端。同样是由API网关做前端。 消息导向的应用 另一个不同的例子是一个后端数据计算服务。比如你正在写一个用户为中心的应用,需要快速响应UI请求,但是你又需要捕获发生的所有不同类型的活动。让我们来思考下在线广告系统,当一个用户点击一个广告时,你需要快速的导向到广告,但是同时你又需要将这个点击计数,从而向广告商收费。 |
传统架构将如下图所示,“Ad Server”将以同步的方式响应用户的请求(这里我们将忽略如何响应用户请求的细节,因为这不是重点),同时“Ad Server”将发送一个消息给一个消息系统,这个消息将被一个叫做“Click Processor”的组件异步处理。“Click Processor”将把处理后的信息写入后端数据库。
当我们切换到Serverless环境的时候,系统架构将如下图所示:
和第一个例子比较,这个例子的架构有点小小的不同。在这个例子中,我们把原先架构中的一个需要一直运行的组件“Click Processor”,替换成了一个事件驱动的FaaS函数。这个函数将运行在某个供应商提供的环境中(比如AWS),这个环境将同时提供提供消息系统和FaaS运行环境,而且供应商将保证消息系统和FaaS运行环境紧密集成在一起。 FaaS运行环境根据进入消息系统的消息数量,可能启动多个函数的运行实例对消息进行并发处理,因此和原先的架构相比,在新的架构下,我们需要认真考虑如何才能实现消息的并发处理(并应该让消息之间存在相关性)。 |
解读 FaaS我们已经多次提到FaaS这个理念,但是却没有深入研究它到底意味着什么,现在是时候了。首先让我们来看看Amazon的Lambda的描述。我在里面加了一些注释,在后面会详细介绍。 AWS Lambda lets you run code without provisioning or managing servers. (1) ... With Lambda, you can run code for virtually any type of application or backend service (2) - all with zero administration. Just upload your code and Lambda takes care of everything required to run (3) and scale (4) your code with high availability. You can set up your code to automatically trigger from other AWS services (5) or call it directly from any web or mobile app (6). 1. 从根本上来说,FaaS就是在不运行你的服务系统或者服务应用的情况下,运行后端代码。其中服务应用,就是FaaS和现在的流行架构比如容器和PaaS的主要区别。我们回到之前的点击系统的例子,其中FaaS的作用是代替服务器的计算点击量的功能,这个过程中,我们能够发现没有用到指定的服务端,也没有使一个应用一直运行着。 2.FaaS并不需要特定的框架或者库,从编程语言和环境角度来看更像是一个普通应用。例如AWS Lambda功能可以采用JavaScript、Python和任何其他JVM语言(Java、Clojure、Scala等)来实现。Lambda功能可以运行任何其他绑定部署的代码,因此可以用任何可以编译成Unix进程的语言(后面看Apex的例子)。FaaS功能也有一些值得注意的架构上的限制,特别当面对状态或者执行区间的问题,后面我们会提到。再次回到上面说的点击系统,转到FaaS架构唯一需要更改的代码就是‘main method/startup’代码,这个在示例中被删除了,开始来代码应该是在顶层消息处理器中(the ‘message listener interface’实现),但却只是在方法签名的一个小小改变。所有其他代码(例如写入数据库的代码)在FaaS里面都和原来一样。 3.因此我们没有服务端应用需要部署,这和传统模式迥然不同,我们只需要上传代码到FaaS的供应商,然后它把剩下所有事搞定。意思就是说我们只需要上传一个更新包(zip或者jar格式),然后调用一个特定的API来初始化这次更新就可以了。 |
4.同层间的扩展由供应商自动且弹性地完成。如果你的系统需要并行处理100个请求,供应商将会帮你处理这个问题,无需在你这边做任何额外设置。"计算容器"在执行完你的代码之后会自动销毁。再次回到我们的点击处理器。假如某天用户点击量是平时的10倍,我们的点击处理程序能扛得住吗?我们代码能不能同时处理各种各样的消息?即使我们做得到,一个应用实例足够承担负载吗?我们是否能够自动扩展从而跑各种各样的进程,还是需要手动重新设置呢?使用FaaS,我们需要事先写好并发的函数,但是从这开始,FaaS供应商将自动解决所有一切。 5.FaaS中的函数由供应商定义的事件类型触发。对于Amazon AWS,这些触发包括 S3(文件)更新,时间(调度任务)和添加到消息总线上的消息(例如kinesis)。代码一般都会提供事件源所需的参数。点击案例中,已经假定我们使用 了支持FaaS的消息代理。如果还没有的话,就需要一个,对消息生产者也有同样的要求。 6.大多数供应商也允许功能作为一个http请求的响应而触发,常见于一些API网关(比如AWS API Gateway,Webtask)。我们已经将这个用在我们的宠物商店例子中的搜索和购买功能里。 状 态 FaaS功能如果使用本地(机器或者实例绑定)状态的话有严格的限制。简单说需要假设任何进程间或者主机状态对子进程都不可见,包括在RAM和写到本地盘上的状态。换句话说,从一个部署单元的角度来看FaaS功能是无状态的。这一点对应用架构来说影响很大,无独有偶,‘12-Factor App’概念对架构也有细致的限制。 那么这个限制应该如何解决呢?一般来说FaaS功能要么是自然无状态,也就是提供纯功能调用,要么会使用数据库,一个交叉应用的cache(比如Redis),或者共享文件系统(比如S3)来存放请求的状态或者提供处理请求所需的更多输入信息。 |
执行持续时间 FaaS功能普遍是通过每个进程所允许运行的时间来做限制的。目前AWS Lambda功能不允许运行超过五分钟,一旦超过就会被终止。 这就意味着一些需要一直开着的任务在不重新布置架构的情况下不适合FaaS的功能,比如你需要创建几种不同的FaaS功能协调器,而在传统环境下,你只需要用一个的持续时间较长的任务就能够同时兼顾协调和执行了。 启动延迟 目前FaaS函数响应一个请求的时间取决于很多因素,一般是在10ms到2分钟之间。这听起来有点不妙,让我们来拿AWS Lambda作为例子来具体说说。 如果你的功能是由js或者python开发的并且代码量也不大(比如小于1000行),那么运行时间不会超过10到100毫秒。但是复杂一点的功能可能就要久一点的时间了。 如果你的Lambda功能运行在JVM上,当JVM启动时,你可能会碰到很长的响应时间(比如大于10秒)。然而这只会经常发生在以下几种情况下:
前者在特定情形下可以比较粗糙地通过每5分钟向你的程序发送一个请求来保持连接。 这些问题需要考虑吗?这取决于你的应用的类型和访问模式。我之前的团队用Java开发过一个异步消息处理Lambda应用,每天处理上亿条消息,而且没有启动延迟问题。也就是说不管采用什么开发语言,如果你想写一个低延时交易应用,现在可能并不适合采用FaaS架构。 不论你是否觉得你的应用有没有这样的问题,你都应该用生产类负载测试工具来试试你的应用表现如何。如果表现不太好的话,过几个月再来试试,因为这段时间是FaaS供应商们发展的黄金时间段。 |
API 网关
我们之前在讲FaaS时曾提到过API网关。API网关是一个http服务器,它定义了路由和终端,并且每一条路由都连接了一个FaaS功能。当API网管接收了一个请求后,它选择和请求相匹配的路由,然后调用相关的FaaS功能。一般情况下API网关支持http请求参数到Faas功能参数的映射。API网关将FaaS功能调用的结果转化成一个http响应,然后再传递给原始调用者。 Amazon Web Services 有他们自己的API网关,其他供应商也提供类似的功能。 除了单纯地路由请求之外,API网关也能做认证,输入验证,响应代码映射等。你敏锐的直觉可能依然会疑惑这到底是不是一个好的想法,如果是的话,我们等下将更深入地研究下。 API网关+FaaS的一个应用场景就是用无服务器化方式创建http前端微服务,充分利用扩展,管理和其它与FaaS功能有关的其它优点。 目前API网关开发工具并不太成熟,因此定义API网关应用的时候,最好不是非常核心的引用。 工具 上面对API网关工具不成熟的评论是从无服务化的FaaS的大体上来讲的。也有一些例外,一个例子是Auth0 Webtask,它将很大程度的优先权放到了工具开发上面。Tomasz Janczuk在最近的无服务化论坛上给了一个很好的示范。 调试和监视在无服务化app中是十分复杂的,我们将会在本文后面的部分来深入讲解。 |
开 源 FaaS模式的无服务器化应用的一个主要优点是产品配置执行的透明化,所以开源并不像它最开始定义的那样了,比如Docker和其他容器。未来我们可能看到一种受欢迎的运行在本地部署开发平台或者开发者工作站上的FaaS/API网关平台实现。IBM 的OpenWhisk 就是其中的一个实现例子,不管是看到这个例子还是其他例子采用这种方法,都将是十分有趣的一件事情。 除了实时运行之外,还有现成的开源工具及架构来方便定义、部署和实时帮助。例如无服务器架构使得同时使用API网关和Lambda比使用AWS提供的首要原则更有意义。如果你正在写js的API网关应用的话,这肯定会很值得看看。 另一个例子是Apex。这是一个着力于”更方便建立、部署和管理AWS Lambda 函数”的项目。Apex特别有趣的一点是,即便你使用Amazon支持的语言,也能对Lambda函数进行开发。 |
什么是无服务器化?本文讲到现在,已经定义了无服务器化就是 BaaS以及FaaS等一组理念的集合。同时也深入介绍了后者的功能。 在我们开始讲到最关键的优缺点之前,我想先多花几分钟来对无服务器化进行定义,或者起码定义一下什么不是无服务器化。我曾看到一些人(包括之前的我自己)对这个定义搞不太明白,所以我觉得还是很有必要弄清楚一点的。 和PaaS对比 考虑到FaaS模式的无服务器化和12-Factor应用非常相似,难道它和Heroku一样实际上是PaaS的另一种形式吗?再次我引用 Adrian Cockcroft的一句话。 “如果你的PaaS能够有效地在20毫秒内启动一个要跑半秒的实例,那么就可以称之为无服务器化。“ 换句话说,许多PaaS应用不会每次请求来了启动,请求结束则关闭,但是FaaS却是这样做的。 好了,但那又如何呢,如果我是一个厉害的12-Factor 应用开发者,在开发上并不会有什么不同吧?确实,但是当你运维方法还是有很大区别的。因为一个好的DevOps-savvy工程师在开发时会同时考虑到开发和运维,对吧? |
FaaS和PaaS在运维上最大的不同是可扩展性。大多数的PaaS仍然要考虑到规模,比如Heroku要考虑到你要运行多少Dynos。而对于FaaS来说,这是完全透明的。即使你将你的PaaS设置为自动扩展,你也做不到请求级别的(除非负载情况很特殊),所以使用FaaS在投入上来看也是最有效的。 考虑到这个优点,为什么还要用PaaS呢?因为仍然还有一些缺陷,但是工具和API网关的不成熟很可能是最大的缺陷。另外,为了优化,12-Factor 应用在PaaS中的实现可能会用到app内部只读cache,这是FaaS里面没有的。 #NoOps 无服务器化不意味着“不用维护”,应该是说“没有内部系统管理员”,而且还取决于你系统要跑多久。有两个重要因素要考虑到。 首先,‘Ops’不仅仅是代表服务器维护,它至少还应包括监视、部署、安全、网络还有产品调试和系统扩展。这些问题依然存在于无服务器化的应用中,仍然需要有方法来解决这个问题。在某些方面来说,因为一切都是新的,无服务器化世界中的Ops将会更难。 第二,即使服务器维护依然存在,你也只是外包给了无服务器化。这也不是什么坏事,我们本身也外包很多东西。是好事还是坏事,取决于你要做什么,并且任一种方法都有可能出现问题,你需要知道是有人在某个地方支持你的应用。 Charity Majors 在最近的无服务化论坛上对这个主题有过一个精彩的发言,我建议有空可以去网上看看。然后你可以再读一下她的 write-up here and here。 |
存储过程即服务 I wonder if serverless services will become a thing like stored procedures, a good idea that quickly turns into massive technical debt -- Camille Fournier 我曾看到另一个观点是说无服务化的FaaS就是“存储过程即服务”。我认为这是因为很多FaaS功能(包括我在本文中用到的)的例子都是一些小段代码,这些代码都绑定了一个通向数据库的路径,所以才会这么说。如果这就是全部我们能对FaaS的应用的话,那么上述观点还说得通,但是事实上那只是部分FaaS的功能而已,将FaaS那样概括是具有很大局限性的。 也就是说,值得商讨下是否FaaS具有和存储过程一样的问题,包括Camille在提到的技术债务考虑。在FaaS的情况下,使用存储进程方面还有很多值得再次商榷的点。以下是几个存储过程方式的问题: 1.经常需要特定的供应商语言,或者至少是特定的供应商架构或者语言扩展; 2.很难测试,因为他们需要在有数据库的情况才能执行; 3.首个应用的版本控制和处理会十分复杂。 注意不是所有的这些都会应用到所有的存储过程实现中,但是他们确实是我所遇到过的问题。让我们来看看是否FaaS也有类似 的问题: 首先以我的经历来讲,第一点严格的来说不是FaaS实现要考虑的问题,所以这里我们暂且不予考虑。 对于第二点,由于我们正在处理的“只是代码”单元测试,所以测试绝对和任何其他代码一样容易。集成测试是另一个不同(且合法)的问题,我们后面会讨论到。 对于第三点,还是因为FaaS功能都只是代码,版本控制没有问题。但是对于应用打包,就没有比较成熟的方法了。我之前提到的无服务架构确实提供了他自己的方式,并且AWS宣布在最近2016年5月的无服务论坛上,他们正尝试解决打包的问题,但是现在这是另一个需要考虑的问题。 |
本文转自:开源中国社区 [http://www.oschina.net]
本文标题:无服务器架构
本文地址:http://www.oschina.net/translate/serverless-architecture
参与翻译:txmnyzz, HAILINCAI