业界前沿 Serverless 入门指导之无服务器架构

laofo · 发布于 2017年11月09日 · 71 次阅读
4

转自:https://time.geekbang.org/article/566

Serverless 一词最早在2012年出现,在2014年亚马逊推出了AWS Lambda 后才广为人知。随后几年,人们在越来越多的场合谈起它,越来越多的云厂商实现了它,它被认为是未来云计算发展的趋势。 为什么这么说?无服务器和无服务器架构究竟指的是什么?让这几篇文章来为你解惑。

无服务器架构(一) Mike Roberts

无服务器架构是指大量依赖第三方服务(也叫做后端即服务,即“BaaS”)或暂存容器中运行的自定义代码(函数即服务,即“FaaS”)的应用程序,AWS Lambda 是目前最著名的供应商。通过采用这样的方式并将大部分行为移至前端,这种架构使得应用程序内部不再需要具备传统的“始终运行”的服务器系统。取决于具体情况,尽管对供应商依赖增加了,并且(目前)配套服务还不成熟,但此类系统依然可以大幅降低运维成本和复杂度。

无服务器是软件架构世界中的热门话题。在这一领域我们已经看到很多书籍、开源框架、大量不同类型的供应商和产品,甚至专门的会议活动。但无服务器到底是什么,为什么值得(或不值得)考虑该技术?通过出版物的进化这篇文章,希望能针对这些问题向你提供一些启发。

首先我们要介绍无服务器到底是“什么”,在介绍这种技术的优势和劣势时我会尽量保持中立 – 下文将分别探讨这些问题。

无服务器是什么?

与软件行业很多其他趋势类似,关于“无服务器”到底是什么并没有一个清晰直观的看法,而涉及到两个截然不同但又相互重叠的领域后,问题就更突出了:

“无服务器”这个称呼最早被用于描述大量或完全依赖(“位于云中的”)第三方应用程序 / 服务管理服务器端逻辑和状态的应用程序。这些程序通常是使用可通过云访问的数据库(例如 Parse、Firebase)、身份验证服务(例如 Auth0、AWS Cognito)等庞大生态系统的“富客户端”应用程序(例如只包含一个页面的 Web 应用或移动应用)。这类服务以往也被叫做“(移动)后端即服务”,下文会将其简称为“BaaS”。 “无服务器”也可以指部分服务器端逻辑依然由应用程序开发者来编写的应用程序,但与传统架构的不同之处在于,这些逻辑运行在完全由第三方管理,由事件触发的无状态(Stateless)暂存(可能只存在于一次调用的过程中)计算容器内。(感谢 ThoughtWorks 在他们最近的 Tech Radar中对这种情况的定义。)这种做法可以看作“函数即服务/FaaS”。AWS Lambda是目前最流行的 FaaS 实现,但除此之外也有其他实现。下文将使用“FaaS”作为无服务器这种运用方式的简称。

“无服务器”的起源

“无服务器”这个词并不好理解,因为有很多应用程序的服务器硬件与进程运行在不同位置,但与传统方式的差异之处在于,构建和支持“无服务器”应用程序的组织并不需要考虑服务器或进程,这些东西可以外包给供应商。

这个词首次出现大概是在 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 服务进行集成时。这类功能的例子包括数据验证(防范仿冒客户端)以及计算密集型处理(例如图片或视频操作)等。

举几个例子 UI 驱动的应用程序 想象一个包含服务器端逻辑,面向客户端的传统三层系统。例如典型的电商应用(可以说在线宠物店吗?)

传统架构看起来类似下图,假设服务器端使用 Java 实现,并使用 HTML/Javascript 组件作为客户端:

这种架构下的客户端会显得相当笨重,系统中身份验证、页面导航、搜索、事务等大部分逻辑都是由服务器应用程序实现的。

如果使用无服务器架构,看起来将会是这样:

这是个大幅简化的视图,尽管如此其中也包含大量显著改动。请注意这并非为了向你推荐迁移时所要使用的架构,此处使用的这种架构仅仅为了介绍无服务器相关概念!

我们删掉了原始应用程序中的身份验证逻辑,并使用第三方 BaaS 服务代替。 作为 BaaS 的另一个例子,我们让客户端直接访问数据库子集(用于列出产品),而该数据库完全由第三方承载(例如使用 AWS Dynamo)。我们还为访问数据库的客户端提供了不同的安全配置文件,这样即可从任何服务器资源访问数据库。 上两点引出了非常重要的第三点:一些原本位于宠物店服务器上的逻辑,例如追踪用户会话,理解应用程序的 UX 结构(例如页面导航),从数据库读取并转换为可用视图等,现在被放入到客户端中。实际上客户端现在已经变成了一个单页应用程序(Single Page Application)。 我们希望将一些与 UX 有关的功能继续保留在服务器上,例如计算密集型功能或需要访问大量数据的功能。“搜索”就是个很好的例子。搜索功能无需使用持续运行的服务器,而是可以用一个能通过 API 网关(下文将详细介绍)响应 Http 请求的 FaaS 函数来实现。可以通过这样的客户端或服务器函数从同一个数据库中读取产品数据。由于原本的服务器是通过 Java 实现的,而 AWS Lambda(本例中使用的 FaaS 供应商)支持通过 Java 实现的函数,无须彻底重写即可将搜索功能的代码从宠物店服务器直接移至宠物店搜索函数。 最后还可以使用另一个 FaaS 函数取代原本的“购买”功能,但出于安全考虑依然将其保留在服务器端,而非在客户端重新实现。这也是一种 API 网关的前端。 消息驱动的应用程序 另一个例子是后端数据处理服务。假设编写的某个以用户为中心的应用程序需要快速响应 UI 请求,但你希望随后能记录发生的所有类型的操作。例如在线广告系统,用户点击广告后你希望非常快速地将用户重定向至目标广告,但为了向广告主收费,与此同时你还希望记录已发生点击这件事。(这并不是虚构的例子,我以前在Intent Media所属的团队就因为这个原因重新设计了自己的系统。) 传统方式下这种系统的架构可能是类似这样的:“广告服务器”会以同步的方式响应用户(由于只是例子,我们并不需要关心具体的交互),同时需要向渠道发布一条消息并由负责更新数据库的“点击处理器”应用程序以异步的方式处理,例如扣掉广告主的部分预算。

在无服务器的世界中,这个系统应该是这样的:

和上一个例子相比,本例中两种架构的差异很小。我们将需要长期运行的消费者应用程序替换为一个在供应商提供的事件驱动的上下文中运行的 FaaS函数。请注意该供应商同时提供了消息代理(Message Broker)和 FaaS 环境,这两个系统非常紧密地相互结合在一起。

通过实例化(Instantiating)函数代码的多个副本,FaaS 环境可以并行处理多个点击,这主要取决于最初流程的编写方式,同时这也是一个需要考虑的新概念。

理解“函数即服务”

上文已多次提到 FaaS 这种想法,但还需要深入考虑一下这到底是什么意思。为此我们一起看看亚马逊 Lambda 产品的公开描述。我将这些描述划分成几点,下文将分别展开介绍。

  1. AWS Lambda 可供你在无须供应或管理服务器的情况下运行自己的代码。(1) ... 借助 Lambda,你可以为几乎任何类型的应用程序或后端服务运行所需代码 (2) - 所有环境完全无须管理,只需要上传自己的代码,Lambda 将自动完成运行代码所需的一切条件 (3) 并可进行伸缩 (4) 你的代码将实现高可用。你可以将代码设置为通过其他 AWS 服务自动触发运行 (5) 或直接从任何 Web 或移动应用内部调用 (6)。

  2. 从本质上来说,FaaS 意在无须自行管理服务器系统或自己的服务器应用程序,即可直接运行后端代码。其中所指的 -服务器应用程序 - 是该技术与容器和 PaaS(平台即服务)等其他现代化架构最大的差异。 回想上文列举的点击处理系统那个例子,可以用 FaaS 取代点击处理服务器(可能是物理计算机,但绝对需要运行某种应用程序),这样不仅不需要自行供应服务器,也不需要全时运行应用程序。

  3. FaaS 产品不要求必须使用特定框架或库进行开发。在语言和环境方面,FaaS 函数就是常规的应用程序。例如 AWS Lambda 的函数可以通过‘一等公民’Javascript、Python 以及任何 JVM 语言(Java、Clojure、Scala)等实现。然而 Lambda 函数也可以执行任何捆绑有所需部署构件的进程,因此可以使用任何语言,只要能编译为 Unix 进程即可(参阅下文的 Apex)。FaaS 函数在架构方面确实存在一定的局限,尤其是在状态和执行时间方面,这些会在下文详细介绍。 再次回想上文提到的点击处理范例,在迁往 FaaS 的过程中,唯一需要修改的代码是“主方法 / 启动”代码,其中可能需要删除顶级消息处理程序的相关代码(“消息监听器接口”的实现),但这可能只需要更改方法签名即可。在 FaaS 的世界中,代码的其余所有部分(例如向数据库执行写入的代码)无须任何变化。

  4. 由于无须运行任何服务器应用程序,相比传统系统,部署方法会有较大变化 –将代码上传至 FaaS 供应商,其他事情均可由供应商完成。目前这种方式通常意味着需要上传代码的全新定义(例如上传 zip 或 JAR 文件),随后调用一个专有 API 发起更新过程。

  5. 横向伸缩过程是完全自动化且有弹性的,由供应商负责管理。如果系统需要并行处理 100 个请求,你自己无须任何额外配置,供应商可全部搞定。负责执行你的函数的‘计算容器’只会短暂存在,FaaS 供应商将完全根据运行时需求自动供应和撤销。 继续回到点击处理器那个例子。假设某天运气好,客户的广告点击量是平时的 10 倍。点击处理应用程序能否顺利处理?例如我们的代码能否同时处理多条消息?就算能处理,只使用一个应用程序实例是否足以应对激增的负载?如果可以运行多个进程,是否要自动伸缩,或者需要手工修改配置?如果使用 FaaS,需要在编写函数的过程中就考虑到这些问题,但随后将由 FaaS 供应商自动完成伸缩相关的任务。 FaaS 中的函数可以通过供应商定义的事件类型触发。对于亚马逊 AWS,此类触发事件可以包括 S3(文件)更新、时间(计划任务),以及加入消息总线的消息(例如Kinesis)。通常你的函数需要通过参数指定自己需要绑定到的事件源。对于点击处理程序,我们假设已经使用了可被 FaaS 支持的消息代理。如果不支持,则需要换为使用可支持的,并且也可能需要更改消息的创建方。

  6. 大部分供应商还允许函数作为对传入 Http 请求的响应来触发,通常这类请求来自某种该类型的 API 网关(例如AWS API 网关、Webtask)。我们在宠物店例子中为“搜索”和“下单”函数使用了这种触发方式。

状态

在本地(机器 / 实例范围内)状态方面 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 秒)。然而只有在下列情况下才会存在这样的问题:

不同调用之间偶尔需要以超过 10 分钟的间隔处理函数处理事件。 流量突然激增,例如通常每秒只需处理 10 个请求,但突然在不到 10 秒内需要每秒处理 100 个请求。

通过用没什么技术含量的手段每 5 分钟 Ping 一下函数,使其保活,前一种问题在某些情况下可以避免。

是否需要担心这些问题,主要取决于应用程序的类型和流量模式。我以前加入的一个团队使用 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对于工具开发的重视远远超过开发者 UX 的完善。Tomasz Janczuk在最近举办的无服务器大会上也很好地阐述了自己对相关工具的重视。

总的来说,无服务器应用的调试和监控都很麻烦,我们也会在下文详细介绍这个问题。

开源

无服务器 FaaS 应用程序的主要收益之一在于可以透明地实现生产运行时供应,因此目前开源对这一方式的意义并不像对于 Docker 和容器等技术的意义那么大。未来我们可能会看到一些主流的 FaaS/API 网关平台可以支持在“本地”,或开发者的工作站上运行。IBM OpenWhisk就是此类实现的一个例子,我们很期待看到类似这样的实现最终能获得更大范围的采用。

尽管除了运行时实现,已经有开源的工具和框架可以为定义、部署、运行提供帮助。例如无服务器框架使得 API 网关 +Lambda 的使用过程变得比 AWS 更简单,虽然这种方式大量依赖 Javascript,但如果你要编写 JS API 网关应用,绝对值得一试。

另一个例子是Apex,这个项目可以“更轻松地构建、部署和管理 AWS Lambda 函数”。Apex 尤其有趣的一点在于,该技术可供你用亚马逊不直接支持的语言开发 Lambda 函数,例如 Go 语言。

无服务器不是什么? 至此本文已经介绍了“无服务器”是好几个不同概念的结合,例如“后端即服务”和“函数即服务”,并且还对第二个概念进行了详细的介绍。

在开始介绍这一技术最重要的收益和不足之处前,我还想进一步谈谈这一概念的定义,至少要讨论一下无服务器“不是”什么。我曾发现很多人(包括我自己以前)对这些概念感到困惑,因此有必要进行澄清。

与 PaaS 相比 考虑到无服务器 FaaS 函数其实非常类似于 12 要素应用,那么无服务器是否像 Heroku 一样仅仅是另一种类型的“平台即服务”(PaaS)?引用 Adrian Cockcroft 的观点作为答案吧。

image

“如果你的 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 年内很多应用程序和团队将同时使用这两种架构,很期待尽快看到这样的使用模式日益涌现。

#NoOps

无服务器并不是指‘无须运维’,取决于你在无服务器的道路上能走多远,可能是指“无须内部系统管理员”。这方面需要考虑两个重要问题。

首先,“运维”不光是服务器本身的管理,还意味着监控、安全、网络,以及大部分情况下必不可少的生产调试和系统伸缩。无服务器应用中依然存在这些问题,需要制定相应的策略。某些情况下无服务器世界中的运维可能更难,主要因为这还是一种比较新的技术。

其次,就算系统本身的管理工作也是存在的,只不过将其外包给了无服务器技术供应商。这不是什么坏事,很多东西都被我们外包了。但取决于你希望实现的精确程度,这种做法是好是坏还有待商榷,无论哪种方式,在某种程度上这样的抽象都有可能渗漏,你必须意识到依然是由人类系统管理员在为你的应用程序提供支持。

Charity Majors在最近举办的无服务器大会上针对这个话题做了一次非常棒的演讲,建议当本次演讲发布到网上后大家都能去看看。在这之前你可以阅读她写的这篇以及这篇文章。

###存储过程即服务 我发现无服务器 FaaS 还有着“存储过程即服务”的特征。我觉得这一特征主要源自很多 FaaS 函数(包括我在本文中用到的那些)都是围绕数据库访问编写的小规模代码片段。如果我们对 FaaS 的全部应用仅限于此,那么这名字还是很贴切的,但由于这只是 FaaS 各种能力中的一部分,对 FaaS 的这种看法实际上是一种无效的约束。

“我担心如果无服务器服务终将变成类似存储过程的技术,一个原本挺好的想法可能很快欠下一大堆技术债。 —— @skamille

话虽如此,依然有必要考虑 FaaS 是否会遇到一些与存储过程相同的问题,例如在上述引用的推文中 Camille 提到的有关技术债的担忧。使用存储过程的过程中我们学到了很多经验,有必要在 FaaS 的世界中仔细反省一下这些问题,看看是否会出现类似的情况。存储过程所面临的一些问题包括:

通常需要供应商明确指定的语言,或至少需要供应商针对某一语言指定的框架 / 扩展。 由于需要在数据库的上下文情境中执行因此难以进行测试。 很难像对待“一等公民应用程序”那样实现版本控制 / 处理。 并非所有存储过程的实现都会遇到上述问题,但我以前的工作中都遇到过。FaaS 是否也存在此类问题:

目前我所接触过的 FaaS 实现都无须担心(1),这一条可以划掉了。

对于(2),由于需要面对的“仅仅是代码”,单元测试过程将与其他任何代码一样易行。集成测试则是另一个截然不同(并且非常合理)的问题,下文将详细介绍。

对于(3),需要再次重申,由于 FaaS 函数面对的“仅仅是代码”,因此版本控制很好实现。但在应用程序打包方面目前还没有出现较为成熟的模式。上文提到的无服务器框架提供了自己的打包模式,AWS 也于 2016 年 5 月在无服务器大会上宣布自己也会开发一种打包技术(“Flourish”),但目前这依然是一个值得我们关注的问题。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册