@liuhui0803
2016-10-08T07:41:46.000000Z
字数 9946
阅读 2625
无服务器
DevOps
架构
云计算
摘要:
无服务器是软件架构世界中的热门话题。在这一领域我们已经看到很多书籍、开源框架、大量不同类型的供应商和产品,甚至专门的会议活动。但无服务器到底是什么,为什么值得(或不值得)考虑该技术?希望本文能为你提供一些启发。这是系列文章的第一篇,主要将介绍无服务器架构的概念。
正文:
无服务器架构是指大量依赖第三方服务(也叫做后端即服务,即“BaaS”)或暂存容器中运行的自定义代码(函数即服务,即“FaaS”)的应用程序,AWS Lambda是目前最著名的供应商。通过采用这样的方式并将大部分行为移至前端,这种架构使得应用程序内部不再需要具备传统的“始终运行”的服务器系统。取决于具体情况,尽管对供应商依赖增加了,并且(目前)配套服务还不成熟,但此类系统依然可以大幅降低运维成本和复杂度。
无服务器是软件架构世界中的热门话题。在这一领域我们已经看到很多书籍、开源框架、大量不同类型的供应商和产品,甚至专门的会议活动。但无服务器到底是什么,为什么值得(或不值得)考虑该技术?通过出版物的进化这篇文章,希望能针对这些问题向你提供一些启发。
首先我们要介绍无服务器到底是“什么”,在介绍这种技术的优势和劣势时我会尽量保持中立 – 下文将分别探讨这些问题。
与软件行业很多其他趋势类似,关于“无服务器”到底是什么并没有一个清晰直观的看法,而涉及到两个截然不同但又相互重叠的领域后,问题就更突出了:
“无服务器”的起源
“无服务器”这个词并不好理解,因为有很多应用程序的服务器硬件与进程运行在不同位置,但与传统方式的差异之处在于,构建和支持“无服务器”应用程序的组织并不需要考虑服务器或进程,这些东西可以外包给供应商。
这个词首次出现大概是在2012年,包含在Ken Fromm撰写的这篇文章中。Badri Janakiraman说他也在这段时间前后在持续集成和托管服务式的源代码控制系统领域听到过这个词,但并不是用来代表某个公司自己的服务器。这种用法侧重的是基础结构的开发,并未将其纳入具体产品。
当亚马逊于2014年发布AWS Lambda后,2015年这个词开始变得广为人知,亚马逊在2015年7月发布API网关后这个词也变得愈加热门。这里有一个例子,API网关公布后,Ant Stanley写了一篇有关无服务器的帖子。2015年10月,亚马逊的re:Invent大会中有一场名为“使用AWS Lambda搭建的无服务器公司”的讲话,其中介绍了PlayOn! Sports这家公司。2015年底,“Javascript Amazon Web Services(JAWS)”开源项目更名为无服务器框架(Serverless Framework),使得这一势头愈加热烈。
快进到今天(2016年中期),我们可以看到更多范例,例如最近举办的无服务器大会以及各种无服务器供应商,从产品描述到工作岗位介绍,都在广泛使用这个词。无论怎样,“无服务器”这个词成了“网红”。
本文将主要介绍上文提到的第二个领域,因为这个领域是最新出现的,与我们以往对技术架构的看法有更大不同,并且围绕无服务器这个词在这个领域有更多宣传炒作。
然而这些概念其实是相互关联,实际上甚至会逐渐会聚的。例如Auth0就是个很好的例子 – 这个技术最开始属于BaaS形式的“身份验证即服务”,但随着Auth0 Webtask的发布开始步入FaaS领域。
在很多情况下,当开发一款“BaaS形式”的应用程序时,尤其是在开发“富”Web应用而非移动应用时,可能依然需要一定数量的自定义服务器端功能。此时FaaS函数是一种很好的解决方案,尤其是需要在某种程度上与正在使用的某些BaaS服务进行集成时。这类功能的例子包括数据验证(防范仿冒客户端)以及计算密集型处理(例如图片或视频操作)等。
想象一个包含服务器端逻辑,面向客户端的传统三层系统。例如典型的电商应用(可以说在线宠物店吗?)
传统架构看起来类似下图,假设服务器端使用Java实现,并使用HTML/Javascript组件作为客户端:
这种架构下的客户端会显得相当笨重,系统中身份验证、页面导航、搜索、事务等大部分逻辑都是由服务器应用程序实现的。
如果使用无服务器架构,看起来将会是这样:
这是个大幅简化的视图,尽管如此其中也包含大量显著改动。请注意这并非为了向你推荐迁移时所要使用的架构,此处使用的这种架构仅仅为了介绍无服务器相关概念!
另一个例子是后端数据处理服务。假设编写的某个以用户为中心的应用程序需要快速响应UI请求,但你希望随后能记录发生的所有类型的操作。例如在线广告系统,用户点击广告后你希望非常快速地将用户重定向至目标广告,但为了向广告主收费,与此同时你还希望记录已发生点击这件事。(这并不是虚构的例子,我以前在Intent Media所属的团队就因为这个原因重新设计了自己的系统。)
传统方式下这种系统的架构可能是类似这样的:“广告服务器”会以同步的方式响应用户(由于只是例子,我们并不需要关心具体的交互),同时需要向渠道发布一条消息并由负责更新数据库的“点击处理器”应用程序以异步的方式处理,例如扣掉广告主的部分预算。
在无服务器的世界中,这个系统应该是这样的:
和上一个例子相比,本例中两种架构的差异很小。我们将需要长期运行的消费者应用程序替换为一个在供应商提供的事件驱动的上下文中运行的FaaS*函数*。请注意该供应商同时提供了消息代理(Message Broker)和FaaS环境,这两个系统非常紧密地相互结合在一起。
通过实例化(Instantiating)函数代码的多个副本,FaaS环境可以并行处理多个点击,这主要取决于最初流程的编写方式,同时这也是一个需要考虑的新概念。
上文已多次提到FaaS这种想法,但还需要深入考虑一下这到底是什么意思。为此我们一起看看亚马逊Lambda产品的公开描述。我将这些描述划分成几点,下文将分别展开介绍。
AWS Lambda可供你在无须供应或管理服务器的情况下运行自己的代码。(1) ... 借助Lambda,你可以为几乎任何类型的应用程序或后端服务运行所需代码 (2) - 所有环境完全无须管理,只需要上传自己的代码,Lambda将自动完成运行代码所需的一切条件 (3) 并可进行伸缩 (4) 你的代码将实现高可用。你可以将代码设置为通过其他AWS服务自动触发运行 (5) 或直接从任何Web或移动应用内部调用 (6)。
在本地(机器/实例范围内)状态方面FaaS函数会遇到很多局限。简而言之你需要假设对于函数的任何调用,你所创建的任何进程内或主机状态均无法被任何后续调用所使用。包括内存(RAM)中的状态以及写入本地磁盘的状态。换句话说,从部署单位的角度来看,FaaS函数是无状态的。
虽然影响因素还有很多,但这会对应用程序架构产生巨大影响。“十二要素应用(Twelve-Factor App)”这一概念也存在完全相同的局限。
考虑到这种局限,备选方案有哪些?通常这意味着FaaS函数可能是天然无状态的,例如只是单纯对输入内容提供功能的转换,或者可以使用数据库、跨应用程序缓存(例如Redis)或网络文件存储(例如S3)跨越不同请求存储状态,以进一步将其作为其他请求的输入。
FaaS函数通常会对每次调用可以执行的时间长度有所限制。目前AWS Lambda函数只能运行不超过5分钟,超过这一时间将被终止。
这意味着如果不进行重构,某些类型的“长寿”任务不适合使用FaaS函数,例如可能需要创建多个相互协调的FaaS函数,而在传统环境中只需要用一个“长寿”的任务同时负责协调和执行。
目前来说,FaaS函数需要等待多长时间才能响应请求,这取决于多种因素,具体时间可能介于10毫秒到2分钟之间。听起来很糟糕,但我们一起用AWS Lambda作为例子更深入地看看这个问题。
如果函数使用Javascript或Python实现并且不大(例如不到五百行代码),那么运行该函数的开销通常绝对不会超过10-100毫秒。更大的函数偶尔可能需要更长时间。
如果你的Lambda函数是通过JVM实现的,由于JVM需要逐渐启动,响应时间偶尔可能会显得较长(例如超过10秒)。然而只有在下列情况下才会存在这样的问题:
通过用没什么技术含量的手段每5分钟Ping一下函数,使其保活,前一种问题在某些情况下可以避免。
是否需要担心这些问题,主要取决于应用程序的类型和流量模式。我以前加入的一个团队使用Java实现了异步消息处理Lambda应用,该应用每天需要处理数以百亿计的消息,他们就不需要担心启动延迟的问题。话虽如此,如果你要编写一个低延迟的交易应用程序,无论使用什么语言实现,现阶段可能都不会想使用FaaS系统。
无论是否觉得自己的应用会遇到这样的问题,你都需要使用类似生产环境的负载进行测试,看看能获得怎样的性能。如果你的用例目前还无法支持,也许可以过几个月再试试,因为目前FaaS供应商都在努力对这一领域进行完善。
上文还提到过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对于工具开发的重视远远超过开发者UX的完善。Tomasz Janczuk在最近举办的无服务器大会上也很好地阐述了自己对相关工具的重视。
总的来说,无服务器应用的调试和监控都很麻烦,我们也会在下文详细介绍这个问题。
无服务器FaaS应用程序的主要收益之一在于可以透明地实现生产运行时供应,因此目前开源对这一方式的意义并不像对于Docker和容器等技术的意义那么大。未来我们可能会看到一些主流的FaaS/API网关平台可以支持在“本地”,或开发者的工作站上运行。IBM OpenWhisk就是此类实现的一个例子,我们很期待看到类似这样的实现最终能获得更大范围的采用。
尽管除了运行时实现,已经有开源的工具和框架可以为定义、部署、运行提供帮助。例如无服务器框架使得API网关+Lambda的使用过程变得比AWS更简单,虽然这种方式大量依赖Javascript,但如果你要编写JS API网关应用,绝对值得一试。
另一个例子是Apex,这个项目可以“更轻松地构建、部署和管理AWS Lambda函数”。Apex尤其有趣的一点在于,该技术可供你用亚马逊不直接支持的语言开发Lambda函数,例如Go语言。
至此本文已经介绍了“无服务器”是好几个不同概念的结合,例如“后端即服务”和“函数即服务”,并且还对第二个概念进行了详细的介绍。
在开始介绍这一技术最重要的收益和不足之处前,我还想进一步谈谈这一概念的定义,至少要讨论一下无服务器“不是”什么。我曾发现很多人(包括我自己以前)对这些概念感到困惑,因此有必要进行澄清。
考虑到无服务器FaaS函数其实非常类似于12要素应用,那么无服务器是否像Heroku一样仅仅是另一种类型的“平台即服务”(PaaS)?引用Adrian Cockcroft的观点作为答案吧。
“如果你的PaaS可以非常高效地在20毫秒内启动实例,并将该实例运行0.5秒,那就将其称之为‘无服务器’吧。 —— @adrianco”
换句话说,大部分PaaS应用程序并不适合针对每个请求让整个应用程序上线并下线,而FaaS平台就是为实现这一做法而生的。
但那又怎样,如果我精通12要素应用的开发,具体如何写代码其实也没什么不同?没错,但应用的运维方式会有翻天覆地的变化。我们都是精通DevOps的工程师,对运维和开发的重视程度是相同的,对吧!
FaaS和PaaS在运维方面的最大差异在于伸缩。大部分PaaS依然需要考虑伸缩,例如对于Heroku,到底需要运行几个Dyno?但FaaS应用程序完全无须考虑这些问题。就算配置PaaS应用程序进行自动伸缩,但也无法在特定请求层面上做到这一点(除非具备非常有针对性的流量塑形配置文件),因此在成本方面FaaS应用程序效率更高。
尽管能获得这样的收益,又为什么还要继续使用PaaS?原因有很多,工具和API网关的成熟度可能是其中最重要的。另外12要素应用在PaaS中的实现为了进行优化可能需要使用应用内只读缓存,FaaS函数还无法支持这种技术。
使用无服务器FaaS的另一个原因在于避免在操作系统层面或更底层的层面管理计算过程。平台即服务(例如Heroku)也能实现这一点,但上文已经介绍过PaaS与无服务器FaaS的差异。容器是另一种流行的过程抽象方式,例如Docker已成为此类技术最明显的例子。我们还发现诸如Mesos和Kubernetes等容器承载系统正在开始普及,这些技术可以将特定应用程序从操作系统级别的部署中抽象出来。另外还有云端承载的容器平台,例如Amazon ECS和Google Container Engine,这些技术与无服务器FaaS类似,可以让用户完全无须管理自己的服务器系统。那么容器技术的发展势头这么迅猛,还需要考虑无服务器FaaS吗?
我对于PaaS的主要观点依然适用于容器技术,对于无服务器FaaS来说,伸缩是自动实现的,是透明的,是非常细化的。容器平台目前还无法满足这些特征。
另外我想说的是,虽然过去几年来容器技术的流行度与日俱增,但这个技术依然尚未成熟。这不是说无服务器FaaS更成熟,只不过无论如何你只能在各种都不完善的技术中做出选择。
不过也要承认,随着时间流逝,这些争议终将消失。虽然容器平台目前还做不到无服务器FaaS那样程度的无需管理、自动伸缩等特性,但我们也注意到诸如Kubernetes的“Horizontal Pod Autoscaling”等技术正在继续向着这个目标努力。我认为这些功能会逐渐包含某些非常智能的流量模式分析,以及与负载更为密切相关的衡量指标。并且Kubernetes的快速演化也许很快就能为我们提供一个极为简单稳定的平台。
考虑到无服务器FaaS和托管式容器在管理和伸缩方面的差距,选择的余地也将缩小,可能只需要考虑应用程序的风格和类型。例如对于事件驱动的应用,并且每个应用程序组件只需要处理少数类型的事件,此时FaaS将是最佳选择;对于包含很多入口点,由同步请求驱动的组件,则更适合使用容器。我预计5年内很多应用程序和团队将同时使用这两种架构,很期待尽快看到这样的使用模式日益涌现。
无服务器并不是指‘无须运维’,取决于你在无服务器的道路上能走多远,可能是指“无须内部系统管理员”。这方面需要考虑两个重要问题。
首先,“运维”不光是服务器本身的管理,还意味着监控、安全、网络,以及大部分情况下必不可少的生产调试和系统伸缩。无服务器应用中依然存在这些问题,需要制定相应的策略。某些情况下无服务器世界中的运维可能更难,主要因为这还是一种比较新的技术。
其次,就算系统本身的管理工作也是存在的,只不过将其外包给了无服务器技术供应商。这不是什么坏事,很多东西都被我们外包了。但取决于你希望实现的精确程度,这种做法是好是坏还有待商榷,无论哪种方式,在某种程度上这样的抽象都有可能渗漏,你必须意识到依然是由人类系统管理员在为你的应用程序提供支持。
Charity Majors在最近举办的无服务器大会上针对这个话题做了一次非常棒的演讲,建议当本次演讲发布到网上后大家都能去看看。在这之前你可以阅读她写的这篇以及这篇文章。
我发现无服务器FaaS还有着“存储过程即服务”的特征。我觉得这一特征主要源自很多FaaS函数(包括我在本文中用到的那些)都是围绕数据库访问编写的小规模代码片段。如果我们对FaaS的全部应用仅限于此,那么这名字还是很贴切的,但由于这只是FaaS各种能力中的一部分,对FaaS的这种看法实际上是一种无效的约束。
“我担心如果无服务器服务终将变成类似存储过程的技术,一个原本挺好的想法可能很快欠下一大堆技术债。 —— @skamille”
话虽如此,依然有必要考虑FaaS是否会遇到一些与存储过程相同的问题,例如在上述引用的推文中Camille提到的有关技术债的担忧。使用存储过程的过程中我们学到了很多经验,有必要在FaaS的世界中仔细反省一下这些问题,看看是否会出现类似的情况。存储过程所面临的一些问题包括:
并非所有存储过程的实现都会遇到上述问题,但我以前的工作中都遇到过。FaaS是否也存在此类问题:
目前我所接触过的FaaS实现都无须担心(1),这一条可以划掉了。
对于(2),由于需要面对的“仅仅是代码”,单元测试过程将与其他任何代码一样易行。集成测试则是另一个截然不同(并且非常合理)的问题,下文将详细介绍。
对于(3),需要再次重申,由于FaaS函数面对的“仅仅是代码”,因此版本控制很好实现。但在应用程序打包方面目前还没有出现较为成熟的模式。上文提到的无服务器框架提供了自己的打包模式,AWS也于2016年5月在无服务器大会上宣布自己也会开发一种打包技术(“Flourish”),但目前这依然是一个值得我们关注的问题。
本文作者:Mike Roberts,阅读英文原文:Serverless Architectures