第 1 章 Serverless范式

第 1 章 Serverless范式

在阅读本书之前,你可能已经对Serverless有所耳闻,比如听说过Serverless范式、Serverless工程以及Serverless架构。如今,随着事件驱动的架构设计(又称Serverless架构)盛行,开发人员部署应用程序的方式已经发生了巨大的变化,在数据工程和Web开发领域尤甚。

在服务器工作负载的间隙,将闲置资源和服务器置于生产闲置状态的情况并不少见,但这会造成基础设施的极大浪费。如果工作负载之外的其他时间不需要闲置资源怎么办?如果可以在必要时创建资源并在工作完成后将资源销毁呢?

阅读本章内容之后,你将了解Serverless架构和函数即服务的工作原理,以及如何将它们构建到现有的软件架构中。你还将了解什么是微服务,并且能够判断Serverless和微服务是否适用于你的体系结构,并学会在主流的云平台(比如亚马逊的AWS以及微软的Azure)上使用Python构建Serverless应用程序。

本章包括以下内容:

  • 了解Serverless架构
  • 了解微服务
  • Serverless架构不仅仅是实时的
  • Serverless架构的优缺点

1.1 了解Serverless架构

Serverless架构或者Serverless工程的核心思想是函数即服务。从技术角度来讲,互联网上最准确的“Serverless计算”的定义如下:

“Serverless计算又称为函数即服务(FAAS),它是一种云计算和代码执行模型,其中云提供商管理函数的容器——平台即服务(PaaS)——的启动和停止。”

让我们仔细研究上述定义的每个部分,从而更好地理解Serverless计算的范式。先来了解“函数即服务”这个术语。它意味着任何Serverless模型都有一个在云平台上运行的函数。这些函数只不过是代码块,它们的执行取决于与之相关联的触发器。下图展示了AWS Lambda环境中的所有触发器。

接下来了解一下函数启动和停止的管理机制。只要有触发器触发了某个函数,云平台就会启动一个容器,用来执行该函数。一旦该函数执行成功并返回结果,或者运行超时,那么运行该函数的容器就将被云平台回收或者销毁。在高负载的情况下,或者当两个触发器之间几乎不存在时间间隔时,这种回收机制使得容器能够被重复利用。

再来看看上述“Serverless计算”定义的后半部分,即函数的容器。这意味着函数在容器中启动和执行。Docker公司将“容器”的概念发扬光大,它对“容器”的标准定义为:

“容器映像是一个轻量级、独立且可执行的软件包,其中包含了软件运行所需的一切:代码、运行时、系统工具、系统库、设置。”

容器的作用是将函数的代码、运行时环境等打包到单个部署包中,以实现无缝执行。部署包中包含了该函数的主代码文件,以及执行该函数所需的所有非标准库。部署包的创建过程与Python虚拟环境的创建过程非常相似。

因此,我们可以明确地指出,对于采用Serverless架构的应用程序,其服务器不会一直运行。其好处显而易见,那就是无须专门的运维团队成员来维护和管理服务器。节省出来的人力可以专注于其他事情,比如软件研发等。同时,这也为公司和个人节省了资源和成本。对于那些经常使用GPU实例应对高负载的机器学习和数据工程团队来说,好处就更加明显了。因此,按需运行的Serverless GPU实例无须开发人员或者运维团队全天候维护,从而能够节省一大笔资金。

1.2 了解微服务

与Serverless的概念类似,面向微服务的设计策略最近也非常流行。这种架构设计在Serverless的概念出现以前就已经存在很长时间了。就像我们试图通过互联网上的技术定义来理解Serverless架构一样,我们也应通过互联网上的技术定义来理解微服务。微服务的技术定义如下:

“微服务又称为微服务架构,它是一种架构风格,将应用程序构建为一组松耦合的服务,以实现业务功能。”

与Serverless架构一样,规划和设计微服务形式的架构同样有利有弊。我们要熟知微服务架构的优缺点,以便使用时能够扬长避短。在阐述微服务的缺点之前,先来看看它的优点。

微服务能够帮助软件团队保持敏捷和逐步改进。简单来说,由于各个服务之间彼此分离,因此升级和改进一项服务非常容易,并且不会导致其他服务崩溃。例如,在社交网络软件中,如果聊天和订阅功能都是微服务,那么当软件团队尝试升级或者修复聊天服务时,订阅服务完全不会受影响。然而,在大型整体式系统中,很难像微服务那样将功能独立开来。因此,在整体式架构中,即使是一个小组件的修复或者升级都会导致所有服务的停止,而修复所需的时间也往往超出预期。

整体式架构的代码量非常庞大,任何一个小故障都会影响整个系统的运转。微服务则对代码进行了精简和细分,从而极大地提升了开发人员的工作效率。开发人员可以在开销极小甚至为零并且不需要停机的情况下修复和改进服务。容器可以让我们更好地利用微服务,它提供了有效且完整的虚拟操作系统环境,能够隔离进程,并且提供底层硬件资源的专属访问权限。

当然,微服务也有缺点,其中最主要的一点是,它依赖分布式系统。由于各个服务之间是相互独立的,所以架构师需要弄清楚各个服务之间的交互方式,从而构建出功能完整的产品。因此,服务之间的交互方式,以及它们之间数据的传输策略,都是架构师需要认真考虑的问题。分布式系统的主要问题,比如共识CAP定理维持共识的稳定性以及连接,都是工程师在构建微服务时需要处理的问题。确保和维护安全性也是分布式系统和微服务中的主要问题。你需要为每个微服务制定单独的安全模式和层级,还需要为服务之间的数据交互制定安全策略。

1.3 Serverless架构不仅仅是实时的

由于Serverless架构以函数即服务的形式运行,而函数由一组可用的触发器来触发,所以Serverless架构经常被用作实时系统。但是,单纯将Serverless架构看作实时系统是一种常见的误解,因为Serverless系统除了可用作实时系统之外,也适用于批处理架构。并不是所有的研发团队都需要使用或者拥有实时系统,因此学会将Serverless系统用作批处理架构会给研发团队带来更多的可能性。

可以通过如下方式将Serverless系统用作批处理架构:

  • 触发器的cron功能
  • 队列

首先来了解一下触发器的cron功能。我们可以在云平台的Serverless系统中设置监控器,将监控器设置为一个普通的cron任务,该监控器便会每隔几分钟或者几小时触发一次触发器。这有助于把Serverless配置为cron批处理任务。在AWS环境中,Lambda可以通过AWS CloudWatch作为cron触发,为此,可以手动输入时间间隔来设置cron任务的频率,也可以在cron格式中选择间隔。

还可以利用队列来构建Serverless批处理架构。让我们设置一个示例数据管道,以此来理解队列的概念。假设我们要构建一个系统来执行以下任务。

(1) 用户或者服务将一些数据发送到数据库或者更简单的数据存储系统中,例如AWS的S3。

(2) 一旦数据存储系统中的文件数量超过100,就执行一项任务。比如,对文件进行一些分析,例如计算文件的总页数。

该系统可以通过队列来实现。这个例子是一个相对简单的Serverless系统。它可以通过以下方式实现。

(1) 用户或者服务将数据上传或者发送到我们选好的数据存储系统中。

(2) 为这个任务配置一个队列。

(3) 为S3存储桶或者数据存储系统配置一个事件,这样,只要有数据进来,就向上一步配置的队列中发送消息。

(4) 设置监控系统以监控队列中的消息数量。建议你使用云提供商的监控系统,以便保持系统完全Serverless化。

(5) 为监控系统设置告警,并配置告警阈值。例如,一旦队列中的消息数量达到或者超过100就触发告警。

(6) 该告警可以扮演Lambda函数触发器的角色。Lambda函数首先接收队列消息,然后使用消息中的文件名来查询数据存储系统,以此对文件进行分析。

(7) 文件由Lambda函数分析之后,将被发送到另外一个数据存储系统中存放。

(8) 所有任务完成之后,运行Lambda函数的容器或者服务器将自动终止,因此整个传输流程完全Serverless化。

1.4 Serverless的优缺点

至此,我们已经对Serverless架构和流程有了大致的了解,知道了如何在现有架构中利用它们,还学会了如何使用微服务来简化架构以及提升开发人员的工作效率。本节将详细列举Serverless系统的优缺点,以便软件开发人员和架构师决定何时在现有系统中利用Serverless范式。

Serverless系统的优点如下。

  • 降低了运营成本:部署了Serverless系统,服务器就不再需要昼夜不停地运转,因此设备成本得以大幅缩减。当函数被触发时服务器才会启动,而当函数执行完毕时服务器会自动停止,因此用户只需为函数运行的时间段付费。
  • 减少了维护工作:鉴于以上情况,我们不再需要对服务器进行持续不断的监控和维护。由于函数和触发器高度自动化,因此Serverless系统几乎不需要维护。
  • 提升了开发效率:由于开发人员不需要操心服务器的维护工作以及宕机情况的发生,因而可以专注于提升软件质量的相关工作,例如扩展和设计功能。

本书后面的章节会展示Serverless系统如何改变软件的构建方式。本章旨在帮助架构师判断Serverless系统对于他们的架构来说是否是一个好的选择。接下来看看Serverless系统的缺点。

Serverless系统的缺点如下。

  • 函数运行有时限:无论是AWS Lambda还是GCP云,其函数运行时长的上限都是5分钟,这使得计算密集型的任务变得难以运行。为了解决这个问题,可以用nohup模式来执行配置工具的脚本。相关内容将在本章后面详细介绍。然而,配置脚本、设置容器以及其他工作也必须在5分钟内完成。一旦超过5分钟的时限,容器便会自动终止。
  • 无法控制容器环境:开发人员无法控制用来执行函数的容器环境。操作系统、文件系统等均由云供应商一手掌控。比如,执行AWS Lambda函数的容器运行着亚马逊的Linux操作系统。
  • 缺乏对容器的监控:云提供商通过其内部监控工具为用户提供了基本的监控功能,除此之外,没有为执行Serverless函数的容器提供详细监控服务的其他机制。当扩展Serverless系统以适应分布式系统时,监控工作将变得更为艰难。
  • 无法控制安全性:由于缺乏对容器环境的监控,所以无法保证数据流的安全性。但是,容器可以在开发人员选择的VPC和子网中运行,这有助于解决该问题。

然而,Serverless系统可以扩展到执行大规模计算的分布式系统中,此时开发人员不必担心时限问题。正如前文提到的那样,后续章节将对此进行详细讨论。但是,为了直观地了解如何在单个整体式系统上选择Serverless系统来执行大规模计算,让我们看看在做这种架构决策时需要注意的重要事项。

将Serverless系统扩展到分布式系统时的注意事项如下。

  • 要想将Serverless系统扩展到Serverless的分布式系统,需要知道nohup的运行方法。它是一个允许程序和进程在后台运行的POSIX命令。
  • 正确记录nohup进程的日志,包括输出日志和错误日志。进程的所有信息都应记录在日志中。
  • 需要一个配置工具,例如AnsibleChef或者类似工具,用来创建一个master-worker架构,并在执行Serverless函数的容器中以nohup模式运行它。
  • 对于所有由配置工具的master服务器执行的任务,需要进行正确的监控并记录其日志,因为一旦所有设置执行完毕,就无法获取其日志了。
  • 使用云提供商的临时凭证工具来适当保证安全性。
  • 应确保系统正确关闭。所有的worker及master任务在执行完成之后应当立即自行终止。这一点非常重要,它是保证系统Serverless化的关键。
  • 通常,大多数环境中临时凭证的有效期为3600秒。因此,如果开发人员使用临时凭证执行任务的时间超过凭证的有效期,那么凭证就存在过期的风险。
  • 调试分布式Serverless系统是一项非常困难的任务,原因如下。
    • 监控和调试nohup进程非常困难。其调试方法有两种:一种是参考进程创建的日志文件,另一种是通过进程ID将nohup进程杀死,然后手动运行脚本进行调试。
    • 由于所有任务在配置工具中按顺序执行,因此任务实例存在被终止的风险,原因是开发人员在调试进程之前可能会忘记杀死nohup进程。
    • 因为这是一个分布式系统,所以毫无疑问,该架构在任何失败或者出错的情况都应当能够自我修复。一个示例场景是:一个worker任务在对一堆文件执行某种操作时发生了崩溃,导致所有文件都丢失了,而且没有办法恢复。
    • 另一个更严重的灾难场景是两个worker任务在操作文件时发生崩溃。在这种情况下,开发人员并不知道哪些文件已成功执行,哪些没有。
  • 确保所有worker任务获得相同数量的负载是一种很好的做法,这可以实现分布式系统的负载均衡,同时使得时间和资源得到很好的优化。

1.5 小结

在本章中,我们学习了什么是Serverless架构。最重要的是,本章帮助架构师判断Serverless能否为其团队或项目所用,以及如何从现有基础设施转换或者迁移到Serverless范式。我们还研究了微服务范式及其如何帮助实现轻量级和高度敏捷的架构,并且详细介绍了团队何时应该考虑采用微服务,以及何时可以将其现有的整体式服务迁移到或者分解为微服务。

紧接着,我们学习了在Serverless域中构建批处理架构的技术。一种最常见的误解是Serverless系统仅用于实时计算,然而,我们也学习了如何利用这些系统进行批处理计算,以及如何使用Serverless范式构建应用程序。我们详细分析了Serverless的优缺点,以便开发者做出更好的工程决策。

下一章将详细介绍AWS Lambda的工作原理,它是AWS云环境中Serverless工程的核心组件。我们将了解触发器以及AWS Lambda函数的运行方式,还将利用容器执行Serverless函数以及相关的计算任务。接下来将学习配置和测试Lambda函数,以此掌握相关最佳实践。此外还会学习Lambda函数的版本控制(它与代码的版本控制类似),然后为AWS Lambda创建部署包,以便开发人员可以轻松使用标准库以及第三方库。

目录

  • 版权声明
  • 前言
  • 第 1 章 Serverless范式
  • 第 2 章 在AWS中构建Serverless应用程序
  • 第 3 章 设置Serverless架构
  • 第 4 章 部署Serverless API
  • 第 5 章 日志与监控
  • 第 6 章 扩展Serverless架构
  • 第 7 章 AWS Lambda的安全性
  • 第 8 章 使用SAM部署Lambda函数
  • 第 9 章 微软Azure Functions简介