购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第1章

什么是Serverless

随着云计算的普及,在部署应用程序的时候,无须再关心物理意义上的服务器,也不用了解它们所处的机房情况,而只需要申请“虚拟机”即可。由于虚拟机隔离了物理层的设备,我们只需要选择机器配置即可。因此,这种以虚拟方式来提供的计算服务器被称为“云服务器”。

虽然“云服务器”背后实际上隐藏着一系列的计算资源,但在此我们仍然需要明确一个重要问题:我们需要多少计算资源。这里的计算资源,不仅包含了“云服务器”的数量,也包括其 CPU 的配置、内存的容量、存储空间的大小等。除此之外,在某些场景下,甚至还需要了解“云服务器”的节点选择(即应该在哪些国家的哪些城市进行部署),以满足我们对应用程序性能的苛刻要求。

但是,我们是否同时也考虑过,应用软件的本质是什么?在商业软件的生命周期中,什么才是我们应该关心的内容?我们为什么需要花费这么多的精力在这些非业务的技术细节上?是否有一种更简单的架构,能够帮助我们更聚焦于业务?伴随着这些问题,无服务器架构的计算资源交付模式应运而生。随着近几年容器化技术及配套的容器编排服务(以 Docker 和Kubernetes 为代表)的成熟,我们可以更容易地实现计算资源自动化的动态调度,从而取代了原有对计算资源的手工管理模式。同时随着各种中间件服务的成熟,我们可以更便捷地使用这些特定能力的计算服务(如数据库、缓存、消息队列等)。

Serverless,中文译为“无服务器的”;但这里所说的并不是真实意义上没有服务器的架构,而是针对开发者来说,无须关心服务器。这正如当今另一个流行的理念 NoOps 一样,NoOps 的意思并不是真的没有运维;而是通过自动化运维的理念来取代原有的手工运维模式,让开发者无须关心运维。从以前的专职运维工程师,变成了如今的自动化运维,一切由平台自行调度。在此,“Serverless”指的是,包括服务器的资源情况、部署情况、操作系统以及依赖软件等在内的所有细节,开发者均无须关注,这一切由平台完成,开发者只需要专注于业务实现。

那么,什么样的服务才是“Serverless”的呢?我们可以从“广义上的 Serverless”和“狭义上的 Serverless”这两个角度来讨论。正如上面所说,从广义上来说,我们认为 Serverless 是一种理念,即指对开发者来说,那些无须关心计算资源就可以直接使用的服务,都可以算作一种 Serverless 服务。而从狭义上来说,它指提供给开发者的标准化能力,即 FaaS 和 BaaS。关于 FaaS 和 BaaS,我们将在后续章节中讨论,本章先介绍作为一种理念被提出的 Serverless。

1.1 Serverless的价值

从广义上来说,针对非专业人员提供的计算资源服务,也可以被称为 Serverless 服务。比如用户只需要输入 URL 即可访问一个站点,后面的所有与计算资源相关的事项都完全由这个站点的维护者实现。无论是域名的解析,还是 HTTP 连接的建立,以及后续网页内容的生成和传输,用户都无须关心。并且,用户也不用关心这个站点背后服务的稳定性、可用性、延迟等技术内容。因此我们可以认为,这个站点对于访问的用户来说,是“Serverless”架构的。

从这种角度来看,我们所使用的各种服务,包括每天几乎都在使用的支付服务、电商服务、地图服务等,以及在上班路上看到的红绿灯、广告牌,因为我们都无须了解背后的服务器以及计算资源,所以基本都是 Serverless 服务。更进一步,如果站在普通用户的角度,整个互联网都应该是Serverless架构的。

而本书所讨论的 Serverless,其实与这一理念类似,只是它面向的对象变成了研发人员。作为开发者,我们在部署和发布应用程序时,需要关心服务器和计算资源的情况,这似乎是再正常不过的场景了。然而,之所以习以为常,我认为是我们长久以来所接触和使用服务器的方式所导致的。

在探讨 Serverless 价值之前,我们需要站在更高的层面思考一个问题:企业为什么需要研发人员?

一个企业的根本目标是赢利;而为了达到这一目标,企业需要能够给客户创造价值。互联网本身并非一个独立的实体行业(比如能源行业、医疗行业、教育行业),它通常是将 IT 作为一种能力或工具,赋予某一个或多个行业,以提升相应行业的生产力。比如 Microsoft 的Office,是通过提供通用的办公软件来提高企业的运转效率,从而降低人力成本的;阿里巴巴公司的淘宝网,是通过电子商务技术来提供商品的买卖平台,以达到降低商品交易成本目的的;腾讯公司的微信则通过即时通信服务,降低了人与人之间的沟通成本。它们有一个共同的特点,即都给自己的客户带来了价值。

既然希望通过IT创造价值,那么必然需要研发人员开发相应的应用程序。也就是说,我们应当面向客户的痛点,结合业务的实际情况,开发出相应的IT工具来提高生产力。因此,我们可以认为IT企业之所以招聘研发人员,是为了开发出能够解决客户实际业务中所遇到的问题,从而提高客户生产力的应用软件。而应用软件的核心内容,是处理客户的业务逻辑,最终提高其生产力。

通过应用程序来处理业务逻辑,这似乎是没有争议的。然而问题在于,作为研发人员,当我们在发布和部署应用程序时,却需要关心那些与业务逻辑无关的内容,即服务器运维工作。这就像作为驾驶员需要关心内燃机原理一样不合理。但是要知道,在汽车被发明之前,我们是通过马车等来实现人员运输的。马车车夫除正常的驾驶外,通常还需要给马匹喂食、清洁,以及给它们配备马厩用于休息等一系列额外操作。对于马匹的管理知识,几乎成了马车车夫的必修课。而在内燃机发明之后,这些与实际使用无关的操作都被汽车厂商封装在了一个黑盒中,所有的维护工作都由汽车厂商或其他专业机构完成。内燃机的发明,大大减少了人员运输的附加成本。

目前研发人员仍然需要关注服务器及其计算资源的情况,但我认为这是暂时的,只是因为云计算的基础设施仍然不够完善。以计算机语言的发展举例,在计算机编程语言诞生之初,我们使用机器码的方式来告诉计算机我们期望执行的内容。而编写机器码时,需要从指令表中查到计算步骤对应的机器语言,再人工编码成对应的代码交给机器执行。后来,人们发现翻译这件事情很适合计算机自己完成,于是就有了汇编器。通过汇编器,我们只需要编写汇编语言,就能自动将其转换为机器码来执行。到了这个时候,人们不再需要学习机器码也能实现让计算机完成期望的指令了。随着计算机技术的发展,高级语言也随之诞生,我们无须关注底层汇编内容,通过更高级的指令即可生成汇编代码并执行,最终完成自己期望的计算操作。

与计算机语言的发展类似,以 IaaS 为代表的云计算技术的普及,让我们无须关注物理服务器。随着云计算技术的逐步发展,它将各种细节屏蔽在了黑盒之中,让我们在不用了解底层技术的情况下,就能够更轻松地达到目标。正如上面提到的,驾驶员的根本目标其实是将客户从 A 点送达 B 点。驾驶汽车前往只是一种手段;伴随无人驾驶技术的发展和推广,我们终将不再需要驾驶,就能实现根本目标。无论是内燃机、无人驾驶还是云计算,它们都是通过更便捷、更低成本的新技术来实现客户目标的。

而 Serverless 正是这样一种新技术。它帮助我们进一步屏蔽了服务器、操作系统、系统软件等概念,让我们无须关心服务器的负载情况、部署节点等技术细节,而能更聚焦于研发人员的本质工作:实现业务逻辑。

另外,Serverless 提出了按用量付费的理念,即当对应的任务被触发执行时,才会计费。这一模式使得我们无须为那些自己没有使用的计算资源买单,这能极大地降低服务器的成本。初创企业或个人开发者无须一开始就付出高昂的服务器费用,即可使其业务快速上线运行。

极低的运维成本和大幅下降的服务器费用,正是 Serverless 迅速被开发者接受并普及开来的原因。

1.2 Serverless是一种理念

在了解了为什么会出现 Serverless 技术及其背后的价值之后,我们再看看广义上Serverless 架构的特征是什么;同时我们将从前端研发的视角,讨论目前哪些服务可以被认为是Serverless 架构的。

针对一种服务,我们可以通过以下几个问题来判断它是否是 Serverless 架构的。如果对于你提供的这项服务,无法明确地回答下面几个问题,那么可以认为这项服务是 Serverless 架构的。这些问题如下:

◎ 我们有多少台机器?

◎ 这些机器部署在哪里?

◎ 机器运行的是什么操作系统?

◎ 机器上安装了哪些软件?

带着这些问题,让我们来看看下面这几个我们常用的产品和服务。

对于开发者来说,GitHub 是其再熟悉不过的代码托管产品了。GitHub 有一个众所周知的服务,即 GitHub Pages,如图1-1所示。通过 GitHub Pages,开发者可以直接将托管在 GitHub仓库中的代码文件部署为一个静态站点,同时系统将对这个站点分配一个域名,最终可以直接在浏览器中访问该站点。这是一个十分方便的服务。开发者无须自己申请服务器,也无须自己安装操作系统、软件,以及进行各种配置;只需要选择一个仓库,然后进行简单的设置,就可完成站点的部署和发布。

图1-1 基于 Serverless 理念的 GitHub Pages 服务

除了 GitHub Pages,另一个前端研发人员非常熟悉的服务是 CDN (Content Delivery Network,内容分发网络)。无论是 HTML、CSS 还是 JS 文件,我们都通过 CDN 进行分发。同样,它也是一个易于使用的服务。当我们把静态资源文件,通过云计算供应商的控制台或命令行工具上传后,这些文件将被自动分发到全球各个 CDN 节点。我们无须关心 CDN 的技术细节,如全球有多少个节点、这些节点是如何分布的,等等;我们只需要告诉 CDN 服务我们需要分发的文件即可,之后这些文件将被分发到它们应当被分发至的机房,以实现提高用户访问速度的目的。

基于上面的这两个例子可以看出,凡是将计算资源以服务的方式来提供的产品,都可以认为是符合 Serverless 理念的。因为它们将真正的技术细节屏蔽在这些服务内部,所以开发者无须知道这些计算资源是如何提供的。除了静态站点托管以及 CDN 服务,在以阿里云为代表的云计算供应商那里,还有更多的服务以这种形式提供。比如,用于保存大量文件的 OSS(Object Storage Service,对象存储服务)、用于存储数据的 RDS(Relational Database Service,关系型数据库服务)、用于协调多个服务的消息机制 MQS(Message Queue Service,消息队列服务)等都属于某种意义上的 Serverless 服务。不过这些服务均用于特定场景的技术产品,往往作为系统架构中的一环来使用。那么,有没有一种更通用的提供计算资源的 Serverless 服务呢?

Google 在 2008 年推出了 GAE(Google App Engine)产品,它是一个用于托管 Web 应用程序的平台。GAE 不像普通的虚拟机服务(如 AWS 的 EC2 或阿里云的 ECS),它对运行在上面的 Web 应用程序代码增加了诸多限制和要求。和虚拟机服务相比,其主要包括以下几个方面的不同:

◎ 仅支持特定的几种语言,包括 Python、Java、PHP 和 Go。

◎ 运行环境的类库使用会受到限制,仅允许使用在白名单中的类库。

◎ 只能提供 Web 服务,该服务只能被 HTTP 请求触发。

◎ 对于托管 Web 应用的服务器,开发者对其文件系统只有读取权限,不能写入或者修改文件。

Google App Engine(GAE)通过上述这些限制,使得用户的 Web 应用程序可以运行在统一的应用框架中。这种应用程序与应用框架以约定的方式实现解耦的设计,使平台可以实现一些在虚拟机服务场景下无法实现的能力。这里面最为主要的能力为自动扩容/缩容,此外,还提供了统一的日志监控和异常处理等功能。图 1-2 即展示了一个基于 GAE 的 Web 应用架构示例。

图1-2 基于 GAE 的 Web 应用架构示例

在这之前,对于这种提供给非特定场景的通用技术产品,要实现自动扩容/缩容是十分困难的;因为不同的 Web 应用可能使用的是不同的语言、不同的 Web 框架,还会依赖不同的第三方类库或软件。而 GAE 通过约定的方式,将这些不同点全部统一起来维护,从而抹平了不同 Web 应用程序之间的差异,使得一种能够在所有 Web 应用程序中通用的自动扩容/缩容能力得以实现。

这种通过交出一些权利(如选择操作系统、开发语言、应用框架的自由),得到某种保护(如应用稳定性的保障)的模式,在其他领域也是十分常见的。正如《社会契约论》的作者卢梭对权利的描述:“人们应当建立一种相互间的承诺,它要求我们每个人都需要将一部分权利交给主权者,从而使自己的其他权利得到更好的保护。”这就是社会契约的基本原则。

站在应用研发和部署的角度,我们一直在这条道路上不断深入,这可以被称为“云计算的契约”:从物理机到虚拟机,我们交出了选择机器配置的权利,得到了更易于迁移和维护的统一虚拟机;再从虚拟机到容器,我们交出了控制操作系统的权利,得到了更轻量化、更省资源的 Linux 容器。同样在 GAE 中,我们交出了选择语言、应用框架的权利,得到了更稳定的、更易于水平伸缩的应用容器。我们只需要遵照它所提供的框架编写和部署 Web 应用程序,就能更轻松地保障应用程序的稳定性,无须担心因流量的激增而导致服务不可用;同时,自动部署的监控系统也能使程序出现异常时立即收到通知。

我们不断地交出设备控制权,将注意力聚焦于业务。那些与业务无关的技术细节都由云计算供应商进行封装,这就是云计算的本质。而 GAE 的出现则弥补了通用型 Web 计算服务的空缺,开发者只需要根据自己的业务需求开发并部署应用代码即可。

然而,GAE 仅仅是 Serverless 服务的雏形。虽然从广义上来讲,上面这些服务都属于Serverless 理念的范畴,但当时并没有明确的定义。云计算供应商只是将“屏蔽技术细节,让开发者开箱即用”作为一种云计算产品的理念来践行。

那么我们今天所说的 Serverless 一词是在何时被提出的呢?

1.3 Serverless一词的诞生

Serverless的核心特性是按用量付费(Pay As You Go)和弹性计算(Elastic Compute)。而其中按用量付费的理念,最早可追溯到 2006 年发布的 Zimki 平台(目前已关闭)。Zimki 平台提供了编写能够运行在服务端(即后端)的 JavaScript 脚本的能力,并且实现了按用量付费的计费模式。而 Serverless 一词的首次提出,则是在 2012 年 Ken Fromm 发表的一篇名为 Why The Future Of Software And Apps Is Serverless 的文章中。在该文章的开篇,是这样描述云计算未来的:

虽然云计算已经十分普及,但我们仍然围绕着“服务器”在工作。不过,这种情况不会持续太久,随着 Serverless 的流行,我们将进入云应用的时代,它将对软件和应用程序的创建与部署产生重大的影响。

云计算的核心方向在于帮助研发人员隔离物理机房、物理机等基础设施的建设;对于具体的计算资源,研发人员仍然需要关心服务器的数量和配置等信息,并根据负载情况确定何时进行扩容。而在这篇文章中,Ken Fromm 提出云计算不应该继续围绕服务器设计,部署在云上的应用应该是 Serverless 架构的,这将完全改变应用程序的创建和分发模式。

该文章使用了一种比较生动的比喻来描述计算资源的产生过程。它以电力生产方式的变化进行类比。早期通过作坊式小型水车发电供能的方式,与工业时代通过火力发电厂燃煤发电,再通过电线将电力传输到千家万户的方式相比,后者大大降低了电力的生产成本。我们通过墙上的插座,即可使灯、电视、电钻等设备获得所需要的电力。同样,如果云计算服务能通过弹性计算的方式,使得我们的应用所需要的计算资源可以像电力的来源一样:按需使用、随用随取,那么研发人员就无须根据当前或预期的负载情况来配置他们的服务器资源,这将大大降低开发者的使用和运维成本。

虽然 Serverless 一词最早是在该文中被提出的,但它真正变得广为人知,主要应该归功于2014 年 Amazon 推出的 AWS Lambda 服务。Amazon AWS Lambda 通过触发器的机制,确保当有请求进入时,立即启动对应的服务进行响应,而无须在服务器上持续运行应用程序以等待相应的 HTTP 请求。同时,它还提供了比 GAE 更加细粒度的控制能力:函数。与应用程序不同的是,应用程序往往会提供一系列的相关服务;但函数只实现一个单一的功能,这一点让它能够更灵活地对服务实例进行扩容或缩容。也就是说,当这个服务没有被请求时,云计算上并没有这个函数的实例。一旦请求发出,调度平台将以毫秒级的服务实例化一个服务并完成响应。请求处理完成后,调度服务又将自动回收这个实例。最终,我们只需要按函数的执行时间进行付费即可。

Amazon AWS Lambda 虽然是最早上线的这种服务,但其并不是唯一的。目前各大云计算供应商都推出了自己的计算服务,这里面主要包括 Google Cloud Functions、Microsoft Azure Functions、IBM OpenWhisk 以及阿里云 Function Compute等。

“Serverless”一词虽然一直被提及,但各云计算供应商却没有达成统一的认识,这导致不同的云计算供应商提供的 Serverless 服务各有差异。那么 Serverless 的定义有被大家所认可的一个标准吗?如果有,它又是由谁,在什么时候提出的呢?

1.4 CNCF Serverless白皮书

在介绍 Serverless 白皮书之前,先介绍一下 CNCF(Cloud Native Computing Foundation,云原生计算基金会)。

在 2014 年,Google 开源了一个在公司内部用于容器编排的项目——代号 Seven。并且在随后的 2015 年,Google 采用 Go 语言对该项目进行了重构,同时给它起了一个更正式的名称,这就是现在大名鼎鼎的 Kubernetes。

随着Kubernetes 1.0 版的发布,谷歌与 Linux 基金会合作成立了 CNCF 这一技术虚拟小组,并将 Kubernetes 作为该小组的第一个技术产品进行支持。

最初云原生(Cloud Native)技术主要包含微服务、容器及容器编排三大能力;但随着云计算的发展,CNCF 于 2018 年重新定义了云原生技术。目前其官方描述如下:

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。

这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使得工程师能够轻松地对系统做出频繁和可预测的重大变更。

云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,以推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。

随后,云原生技术以前所未有的速度席卷了整个云计算产业。目前全球主要的云计算供应商,包括 Amazon、Google、Microsoft、阿里巴巴、华为等在内的数百家公司已加入了该组织。该组织的主要职责是推广标准化的云原生技术。

CNCF 作为一个对云计算供应商中立的基金会,一直致力于相关开源技术的应用和推广,借此让研发人员能更便捷、高效地构建出优秀的产品。本书的重点虽不在于探讨云原生(Cloud Native)技术,但作为研发人员,我们应当关注云计算的趋势,理解云原生技术的相关设计理念及开源项目。CNCF 目前已包含 1000 余个开源项目,除 Kubernetes 外,里面不乏 Prometheus、gRPC 这样的明星项目。

而本书的主题 Serverless,则是云原生下的一个重要方向。因此,CNCF 在 2018 年发布了 Serverless 白皮书,探讨了关于 Serverless 的理念、定义及其价值。它做出了如下描述:

Serverless指的是无论在应用的构建环节还是运行环节,都无须对服务器进行维护和管理。

从 CNCF 对 Serverless 的描述可以看出,它与我们上面讲到的理念基本一致,即Serverless 指的是构建和运行应用程序,无须通过人工的方式来管理服务器。但如果仅仅是这样的,那么这和我们上面提到的 Serverless 并没有太大区别,它仍然只是一种理念。CNCF 在白皮书里紧接着对 Serverless 所应该提供的能力,进行了更进一步的阐述。

Serverless 计算平台应该包含以下一种或者两种能力:

(1)函数即服务(FaaS,Functions as a Service),提供基于事件驱动的计算服务。开发者以函数片段的方式来管理应用代码,这些函数通过事件或 HTTP请求来触发。和传统应用相比,其以更细粒度的函数方式来进行部署,这样计算资源就可以实现更精细的调度和管理,且这些操作都将自动化完成,无须开发者参与。

(2)后端即服务(BaaS,Backend as a Service),指的是可以用来替换应用程序中的一些核心能力,且直接通过 API 的方式提供的第三方服务。由于这些服务自身实现了自动扩容/缩容的能力,因此开发者无须了解与服务器相关的信息。

在这里,CNCF 对 Serverless 应该具备的能力进行了清晰的定义。作为 Serverless 平台,至少需要提供 FaaS 和 BaaS 这两种能力中的一种。

关于什么是FaaS和BaaS,以及作为前端人员如何利用它们提高生产力,则是本书接下来的两个部分将要介绍的重点内容。本章先介绍一些基础知识,以便让大家对此有一个初步的认识。

FaaS(Functions as a Service),译为“函数即服务”。它基于事件驱动的理念,提供了让开发者以函数为基本粒度的代码,且具有像HTTP或其他事件一样被触发并被执行的能力。开发者只需编写业务代码,无须关注服务器资源。这样一来,它完全改变了云计算资源的交付和计费模式,从以往租一台虚拟机来实现通用计算的包月付费,变为了按调度消耗计费。这降低了运维成本,也大幅度降低了服务器的租赁费用。不仅如此,应用的发布效率也得到了提升。以往我们购买虚拟机后,需要选择操作系统,安装对应的软件,还需要考虑集群的负载容量和负载均衡等问题;而在 FaaS 下面,它们都将由云计算供应商的调度系统自动完成。

BaaS(Backend as a Service),译为“后端即服务”,指的是一些通过 API 的方式提供的第三方服务,这些第三方服务通常是我们使用的各个中间件服务,比如数据库、缓存、消息队列等,并且这些第三方服务的可用性由它们的提供者自行管理,使用它们的开发者无须关心这些服务背后的部署情况。也就是说,开发者无须了解这些服务在哪里、如何分布,也无须事先预估自己的使用量,这些都将由该服务的提供者动态调配和调度。

通过上述 FaaS 和 BaaS 的定义,我们能将前面提到的各种 Serverless 服务进行一个大致分类:

◎ FaaS(Functions as a Service,函数即服务):

—Amazon AWS Lambda

—Google Cloud Functions

—Microsoft Azure Functions

—IBM OpenWhisk

—阿里云 Function Compute

◎ BaaS(Backend as a Service,后端即服务):

—GitHub Pages

—CDN(Content Delivery Network,内容分发网络)

—OSS(Object Storage Service,对象存储服务)

—RDS(Relational Database Service,关系型数据库服务)

—MQS(Message Queue Service,消息队列服务)

需要指出的是,这里面并没有包含 GAE(Google App Engine)。这是因为 GAE 其实是一种“Applicationless”,从本质上来说它是一个 PaaS(Platform as a Service)。关于什么是 PaaS,我们将在之后的章节中详细介绍,这里只需要知道它与上面定义的 FaaS 不是同一种类型即可。在 FaaS 中的重要理念是按调用付费,而 GAE 仍然是按实例包月计费的模式。在 GAE 中,开发者对服务的运行实例是有感知的,开发者知道当它的应用发布、部署之后,会有一个服务实例启动,等待处理 HTTP 请求。这样一来,就需要这个应用的进程长期地占用服务器资源。而 FaaS 通过毫秒级的自动扩容/缩容能力,使得在没有请求时就没有对应的服务进程,从而实现不消耗服务器资源的目的。因此,GAE 并不是 Serverless服务。

1.5 Serverless与前端架构

那么,Serverless 和前端到底有什么关系呢?对前端架构有什么影响呢?在本节中,我们将以前端架构演进为主线,讨论 Serverless 对前端架构所产生的意义、影响,以及 Serverless 自身的价值。

前端架构从出现到现在的演化大致可以分为以下6个阶段,即静态内容展示、可交互页面、Web 2.0、单页面应用、前后端分离和基于 Serverless 的前后端分离。

1.静态内容展示

实际上,我们目前所使用的 HTML,最早是由欧洲核能研究组织(CERN)的蒂姆·伯纳斯-李(Timothy John Berners-Lee)所提出的。

在 1990 年底,他在互联网的基础上提出了万维网(WWW,World Wide Web)的概念,并介绍了万维网应该包含的三大核心功能,即我们现在所使用的 URI、HTML 和 HTTP。虽然在那个时候人们可以在互联网上浏览网页,但其实网页只能通过终端,以命令行的形式进行访问。这对用户来说操作极为不便,因此当时的 Web 站点也主要针对具有相关学术背景的专业人士。在随后的 1993 年,Mosaic 公司(1年后其更名为网景公司,即 Netscape)的第一个图形化Web浏览器 Mosaic(Firefox 的前身)发布。图形化浏览器的诞生,让普通用户也可以轻松地浏览网页。

这一时期的站点均以静态内容展示为主,其中主要是文字展示,图片使用得较少。同时,服务端一般使用 CGI 完成开发,前端只需要编写简单的 HTML 页面即可。此时的 Web 用户以大学的科研人员为主。

2.可交互页面

在 1995 年,刚加入网景公司(Netscape)不久的布兰登·艾克(Brendan Eich)就接受了一项互联网技术中影响最深远的任务之一,即实现一种可以嵌入网页运行的脚本语言。之所以要实现该能力,是因为网景公司发现,当用户填写一个网页表单之后,需要提交并回传整个表单内容,系统才能确认用户是否正确填写。这对当时的带宽来说是一笔不小的流量开销,可能用户需要等待十余秒才能看到验证结果,并且这一过程在一次成功的提交过程中,通常需要反复出现多次。所以,网景公司希望能通过客户端(前端)脚本,让用户在发送请求之前就在客户端中完成对表单内容的检查,以最终提高用户体验和使用效率。

布兰登·艾克在接到任务一个月后,就完成了这门语言的设计工作,并且仅仅花费 10 天时间,就实现了它。其接下来一年的工作,则是把该语言的运行环境集成到了网景(Netscape)浏览器。在这之后,网页便具备了动态运行脚本的能力,而这门语言,即 JavaScript。

同时,在服务端领域先后诞生了ASP、PHP、JSP 三大技术。与原来的 CGI 相比,JavaScript可以更加容易地编写动态网站,结合前端 JavaScript 脚本的能力,成为复杂客户端的 Web 应用。因此,交互方式开始逐渐被探索和挖掘。随着互动能力的增强,论坛(BBS)也开始流行起来。不过在接下来的几年中,Web 应用似乎走上了一条曲折的道路:前端能力的增强导致出现了各种各样的复杂特效,国内前端社区一度充斥着“JavaScript 文字滚动特效”之类的教程;而对真正为用户带来效率提升的交互研究并不多见。然而,更曲折的则是 IE 6 成为主流浏览器之后。由于 IE 6 与 W3C 标准相比,存在不少设计缺陷,加之IE自身缓慢的版本迭代,因此在当时这给前端研发工作带来了大量的额外成本。这一局面持续到了 2006 年的 IE 7 和2009 年的 IE 8 发布后,才稍有缓解。

3.Web 2.0

1998 年,Ajax(Asynchronous JavaScript and XML,异步的 JavaScript 与 XML)技术被提出。在这之前,服务端处理的每一个用户请求都需要在浏览器中重新刷新并加载网页,无论是用户体验还是使用效率都不理想。并且,即使只需要修改页面中的部分内容,也需要重新加载整个页面,这进一步地消耗了服务端的计算资源。而 Ajax 的提出解决了这些问题。它使得网页局部刷新成为可能。但是,Ajax 的真正大规模普及则是到了 2004 年。

2004 年底,Google 的邮箱服务 Gmail 进行了一次大型改版,通过大量使用 Ajax 技术,网页的可交互性和内容动态性跨跃了一个大台阶。自此之后,由 Gmail 所带来的交互理念几乎改变了整个行业网页制作的方式。除了 Gmail,一同大量使用 Ajax 技术的 Google 服务还包括 Google Map、Google Group 等。

2006 年 jQuery 诞生。jQuery 为操作浏览器的 DOM(Document Object Model,文档对象模型)提供了非常强大且易用的 API,同时抹平了不同浏览器之间的差异;因此,其成为使用最广泛的函数库。它的诞生让网页开发的难度大大降低,使得 JavaScript 真正地开始流行起来。在 jQuery 的鼎盛时期,全球有超过一半的站点均依赖 jQuery 库。

在通过 Ajax 提高用户体验和通过 jQuery 降低开发难度的共同促进下,Web 站点开始变得丰富起来,基于浏览器的Web应用也进入了以社交网络应用为代表的 Web 2.0 时代。同时,一些大型互联网产品公司开始分化出专职从事 Web 应用开发的工作岗位,即前端研发工程师。

于是,前后端研发的协作与分工开始了。这时,我们通常有两种研发协作模式。

一种模式是让前端研发人员根据设计师的视觉稿开发对应的静态站点,通常我们将该静态站点称为高仿真实现。然后,将这些静态页面交由服务端研发人员改写为动态页面(如 JSP)。我们将这种协作模式称为套模板。它的优势是前端无须了解任何后端实现,只需要交付仿真的静态页面即可;但缺点是其功能变更或扩展困难。当项目上线后,若有新的研发需求,由于原有页面代码已经与服务端代码融合,因此,服务端(即后端)将很难再根据前端研发提供新版静态页面,并将其替换到已有的代码中。故此,在迭代过程中如何进行同步,以及后期若发现 UI (User Interface,用户界面)上的问题,应该由谁负责,等等,这些问题都是无法避免的。

另一种模式则是让前端研发搭建后端运行环境。在这种协作模式中,由于前端可以直接运行最终的交付应用,因此解决了上述产品功能迭代困难的问题。但同样,它的问题在于将不必要的内容(即后端研发框架)暴露给了前端,前端研发人员不得不学习后端应用的研发、调试方式。若后端存在多个团队以及多种技术框架,则前端研发人员必须支付一笔不小的学习成本。

无论采用哪种模式,前后端(Frontend/Backend)的分工都是十分模糊的(见图1-3)。

图1-3 模糊的前后端协作模式

4.单页面应用

随着 Web 应用和前端技术的发展,SPA(Single Page Application,单页面应用)概念被提出。伴随这个概念的,还有数十个相关前端框架。其中,最早的是以 MVC(Model View Controller)模式为代表的框架 Backbone,以及基于 MVVM(Model View ViewModel)模式的 Knockout.js;随后 Google 在 2009 年推出了 Angular 框架,并且将其称为 MVW 模式(Model View Whatever)。

如图 1-4 所示,在该背景下,原来通过服务端渲染的页面开始向前端迁移。由于 Web 应用体验的大幅改善,页面逻辑以及路由也从服务端转移到了前端。这时,前后端协作的模式发生了变化。前端的所有逻辑都将打包成一个 JS Bundle,因此我们只需要后端提供一个入口文件(即 index.html),即可加载整个应用。这时后端只需要提供 Web API,即可完成数据的交换。当前端发布时,只需要在入口文件中,修改 JS Bundle 的版本号即可。前端负责整个 View 层开发,包括与 API 的对接。这样一来,一些业务逻辑变得既可以在服务端编写,也可以在前端编写。

图1-4 基于 MVC 的前后端协作模式

尽管如此,虽然研发环境相互已经没有了依赖,但前后端的职责仍然难以划分。

5.前后端分离

在 Angular 发布的同一年(2009 年),Node.js 也随之登台。Node.js 的出现带来的第一个好处是前端工程化的成熟,前端构建工具开始百花齐放。这时的前端已经不再是一个简单编写几行 JavaScript 即可完成的事情。专职前端研发人员开始在各个公司中普及,前后端协作问题也在这时进一步地加剧。

随着 Node.js 的成熟,在 2015 年,基于 BFF(Backend For Frontend,服务于前端的后端)的架构理念被提出。关于 BFF 的更多内容,后面会详细介绍。我们在这里只需要了解,BFF 架构通过在 UI 和服务端之间加入中间层,解决了前后端职责难以划分的问题即可。

如图 1-5 所示,由于前端逻辑的复杂性不断增加,增加了专门用于处理用户界面逻辑的服务层;同时后端逻辑也完成下沉,基于微服务架构的后端服务逐渐成型。通过基于 Node.js 的BFF 层,前后端形成了比较清晰的分工。

图1-5 基于 BFF 与微服务的前后端架构

6.基于 Serverless 的前后端分离

从上面的介绍中我们可以看出,由于增加了基于 Node.js 实现的 BFF 服务层,前端研发人员开始需要关注服务器的系统稳定性、可扩展性等指标,同时需要排查如内存溢出等各种异常问题。这些工作给前端研发人员带来了一定的挑战。可喜的是,随着 DevOps 配套工具的成熟,前端研发人员可以比较容易地实现日志监控、异常排查等一系列服务器运维操作了。

虽然各种云计算工具一定程度上解决了 Node.js 的运维问题,稳定性得到了保障;但在BFF 架构的真实实践中,除了稳定性,我们还遇到了其他棘手的问题:部署成本和服务器成本的增加。

随着业务的发展,由于每一个终端应用都会有对应的 BFF 层存在,因此会存在数十个 BFF应用。而这些 BFF 层需要独立的容器实例(即 Docker)进行部署,我们需要构建容器镜像(Docker Image)、编译应用程序代码、进行分批发布和灰度上线、观察线上流量等一系列流程,才能将服务正式发布到线上。由于我们的发布每周都会进行数次,而上面这一系列发布流程,每次都需要消耗数十分钟的时间,因此,仅仅是发布操作,就消耗了我们大量的研发时间。

出于服务稳定性的考虑,我们采用一个机房多个实例和多机房部署的策略。因此,我们的每个应用都至少应该部署4个实例(即至少2个机房,每个机房至少2个实例)。这将让容器实例的数量大幅增加。然而,BFF 层的流量实际上长期处于较低水平,这使得这些容器的平均CPU 利用率甚至不足 1%。也就是说,我们将浪费 99%的计算资源。

如图 1-6 所示,如果能够通过 Serverless 实现 BFF 架构,让前端研发人员仅编写和部署函数(这取代了原来容器实例的方式),则结合我们前面提到的 Serverless 特性,当没有请求时,基于云原生技术的弹性计算能力,这些函数的实例将自动缩容。这样一来,基于Serverless的BFF不仅降低了前端在服务器运维上的成本,还能够快速地完成函数的部署。更重要的是,通过按需计费的方式,Serverless彻底解决了计算资源浪费而最终造成的服务器费用问题。

图1-6 基于 Serverless 的 BFF 架构

1.6 从前端到全栈

通过了解前端架构的演化,我们可以看出 Serverless 技术对当前前端 BFF 架构所产生的意义、影响,以及 Serverless 自身的价值。Serverless 技术补上了前端研发人员的短板。通过它,在有效降低成本的同时,服务器的运维难度也大幅降低。

前端研发工程师这一岗位的出现,正是由于前端工程化复杂度不断上升造成的。而Serverless则降低了后端研发的难度,使得前端研发工程师能够更容易地编写服务端应用,让从前端研发工程师到全栈研发工程师的转变更加轻松。

实际上,能同时开发前端与后端的“全栈工程师”并不是一个新的概念;因为最初并没有前端研发工程师这一岗位,所有的工作都由研发工程师完成,所以这更像一种回归。Serverless 技术则是这个转变过程的催化剂,它通过云原生技术,使得前端研发工程师能够更容易地掌握服务端的研发能力。由于减少了前后端人员之间不必要的沟通,因此从前端研发工程师到全栈研发工程师的转变能显著地提升研发效率。而后端研发工程师将下沉到基础设施层,将原有的业务拼装逻辑交由全栈工程师完成,自身去实现更加底层化的通用业务封装。这就是我们时常提到的“大中台,小前台”战略。

我认为,伴随着前端架构的演进和前后端协作模式的变化,前端将逐渐负责更多的上层业务逻辑,而不像以前那样只是简单地编写页面代码。因此,对业务流程的深入理解和全局把控,将是前端研发人员所面临的一种新的挑战,也是他们今后的努力方向。

而 Serverless 技术是前端研发人员应当首先掌握的技术,掌握这种技术也是他们通往全栈工程师的一条捷径。

本章小结

在本章中,我们从 Serverless 的起源谈起,介绍了其基本理念以及 CNCF Serverless 白皮书对它的定义,从广义定义和标准定义这两个角度阐述了什么是 Serverless。随后我们结合前端架构的演进,探讨了为什么在基于 BFF 前后端分离的技术上,前端应该使用 Serverless 架构,以及它的价值和意义。

第2章将介绍 Serverless 的优势/劣势和典型应用场景,以便于我们知道应该在什么时候应用 Serverless 架构。 o8UvlAU3AH2wcwVb/94eYFk83EOqQebOmcnT9qxNX0pLlsLVoCtSiYfrKJFWgnOD

点击中间区域
呼出菜单
上一章
目录
下一章
×