暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

微服务之部署

Halugin 2021-09-11
1818

微服务之部署

部署单进程单体应用程序是一个相当简单的过程,微服务部署具有相互依赖和丰富的技术选择。本文将介绍一些与部署相关的核心原则,同时展示不同的工具如何帮助将这些原则付诸实践。

让我们先看下从系统架构的逻辑视图转向真实的物理部拓扑的过程。

逻辑视图-物理拓扑

我们前面讨论微服务时,是从逻辑意义上而不是物理意义上讨论的,我们可以讨论Invoice
微服务如何与Order
微服务通信,如图1所示,而不需要实际查看这些服务如何部署的物理拓扑,架构的逻辑视图通常会抽象出底层的物理部署问题。

图1

当涉及到在真实的基础设施上实际运行微服务时,这种微服务的逻辑视图可能隐藏了大量的复杂性。让我们看看什么样的细节可能被这样的图表所隐藏。

多实例

当考虑这两个微服务的部署拓扑时(如图2所示),并不像一件事与另一件事对话那么简单。首先,我们很可能会有每个服务的多个实例,拥有一个服务的多个实例允许你处理更多的负载,还可以提高系统的健壮性,可以更容易地容忍单个实例的故障。因此,我们可能有一个或多个Invoice
实例与一个或多个Order
实例通信。如何处理这些实例之间的通信将取决与通信机制的性质,如果我们假设在这种情况下使用某种形式的基于http的API,一个负载均衡器足以处理请求路由到不同的实例,如图2:

图2

需要的实例数量取决于应用程序的性质—-需要评估所需的冗余、预期的负载级别等,以得出一个可行的数量。还需要考虑这些实例将在哪里运行,如果出于健壮性原因而使用多个服务实例,则可能希望确保这些实例运行在不同底层硬件上。进一步说,可能需要不仅要在多台机器上部署不同的实例,还要在不同的数据中心上部署不同的实例,以防止整个数据中心不可用,如图3的部署拓扑:

图3

当涉及到托管虚拟机之类的东西时,AWS、Azure、阿里和Google都不会为单个机器提供SLA,也不会为单个可用区(对这些提供商来说,可用区相当于数据中心)提供SLA。实际上,这意味着部署的任何解决方案都应该分布在多个可用性区域。

数据库

我们希望微服务隐藏其内部状态管理,因为微服务用于管理状态的任何数据库都被认为隐藏在微服务内部。

但当考虑有多个微服务实例时,是如何工作的呢?每个微服务实例都应该有自己的数据库吗?在大多数情况下,如果转到Order
服务的任何实例,希望能够获得关于相同订单的信息,因此,在相同逻辑服务的不同实例之间,需要某种程度的共享,如图4所示:

图4

当跨多个不同的微服务共享数据库时,与访问和操作状态相关的逻辑会跨不同的微服务传播,这里,数据是由同一微服务的不同实例共享的,访问和操作状态的逻辑仍然保存在一个逻辑微服务中。

数据库部署和扩展

就像微服务一样,目前为止主要讨论的是逻辑意义上的数据库,如图3中,忽略了对底层数据库冗余或可伸缩需求的关注。

一般来说,由于许多原因,物理数据库部署可能驻留在多台机器上。一个常见的示例是在主节点和一个或多个只读的节点(这些节点通常称为读副本)之间分配读和写负载。如果我们为Order
服务实现这个想法,示例如图5所示:

图5

所有只读流量都流向一个读副本节点,可以通过添加额外的读节点来进一步扩展读流量。由于关系型数据库的工作方式,通过添加额外的机器(通常需要分片模型,这增加了额外的复杂性)来扩展写操作更加困难,因此将只读流量移动到这些读副本通常可以释放写节点上的更多容量,以实现更大的伸缩。

相同的数据库基础设施可以支持多个逻辑上独立的数据库。因此,Invoice
Order
的数据库可能都由相同的底层数据库引擎和硬件提供,如图6所示。这允许你将硬件池用于多个微服务,它可以降低成本,还可以帮助减少数据库本身的管理工作。

图6

需要注意的是,尽管这两个数据库可能从相同的硬件和数据库引擎运行,但它们在逻辑上仍然是独立的数据库。它们不能互相干涉,需要考虑的一件事情是,如果这个共享数据库基础设施失败,可能会影响多个微服务,这可能会造成灾难性的影响。

运行在公共云提供商上的团队更有可能在每个微服务的基础上提供专用的数据库基础设施,如图7所示。供应和管理这种基础设施的成本要低得多,例如,AWS的关系型数据库服务(RDS)可以自动处理备份、升级和多可用区故障转移等问题,其他公共云提供商也提供了类似的产品。这使得为你的微服务提供更独立的基础设施更加划算,使每个微服务所有者拥有更多的控制权,而不必依赖于共享服务。

图7

环境

当部署软件时,它在一个环境中运行。每个环境通常用于不同的目的,可能拥有的环境的确切数量将根据开发软件的方式以及将软件部署到最终用户的方式而有很大差异。有些环境有生产数据,而有些环境没有。有些环境可能包含所有服务,其他的可能只有少量的服务。

通常情况下,我们的软件是经过许多预生产环境的,每个预生产环境都有一定的用途,允许软件被开发,并准备好进行生产测试。从开发人员本地机器到持续集成服务器、集成测试环境,以及其他环境。在图8中,可以看到MusicCorp的Catalog
微服务的管道,微服务在最终进入生产环境之前会经历不同的环境,在生产环境中用户将会使用新软件。

图8

微服务运行的第一个环境是开发人员处理代码的地方—-可能是他们的本地机器。提交代码后,CI流程开始进行快速测试,测试阶段都部署到CI环境中。如果测试通过,微服务将被部署到生产前环境中,以允许手动验证。如果手动验证通过,那么微服务将被部署到生产环境中。

理想情况下,这个过程中的每个环境都是生产环境的副本,然而,在实际中,通常负担补齐运行整个生产环境的多个副本,因为成本非常高。

我们还希望在这个过程中尽早调整环境,以实现快速反馈。尽早知道软件是否可以正常工作是至关重要的,这样就可以在需要的时候快速修复问题。越早知道软件有问题,修复它的速度就越快,中断的影响就越低。

Catalog
服务为例,查看下不同的环境。在图9中,本地开发人员笔记本电脑将我们的服务部署为一个在本地运行的实例。该软件的构建速度很快,它作为一个单独的实例部署,运行在与我们生产中期望的硬件完全不同。在CI环境中,我们部署服务的两个副本以进行测试,确保负载均衡逻辑正常工作。将这两个实例部署到同一台机器上—-这降低了成本,是部署变得更快,并且提供足够快的反馈。

图9

最后,在生产环境中,我们的微服务部署为四个实例,分布在四台机器上,而这四台机器又分布在两个不同的数据中心上。

一个逻辑微服务可以部署到多个环境中,从一个环境到下一个环境,每个微服务的实例数量可以根据每个环境的需求而变化。

微服务部署原则

对于如何部署微服务,有许多的选择,在这一领域确立一些核心原则是很重要的,以下介绍一些核心理念:

  • Isolated execution

    以独立的方式运行微服务实例,以便它们拥有自己的计算资源,并且它们的执行不会影响其他微服务实例。

  • Focus on automation

    随着微服务数量的增加,自动化变得越来越重要。重点是选择能够实现高度自动化的技术,并将自动化作为企业文化的核心部分。

  • Infrastructure as code

    表示基础设施的配置,以简化自动化并促进信息共享。将此代码存储在源代码控制中,以便重新创建环境。

  • Zero-downtime deployment

    进一步提高独立部署能力,确保部署微服务的新版本不会给服务用户(无论是人工用户还是其他微服务)带来任何停机时间。

  • Desired state management

    使用一个将微服务维持在已定义状态的平台,如果在发生中断或流量增加时需要启动新的实例。

Isolated Execution

你可能会想把所有的微服务实例放在一台机器上(可以是一台物理机器,也可以是一台VM),如图10所示,尤其是在微服务实施的早期。纯粹从主机管理的角度来看,这个模型更简单。在一个团队管理基础设施而另一个团队管理软件的世界中,基础设施团队的工作负载通常取决与它必须管理的主机数量。如果将更多的服务打包到单个主机上,那么主机管理工作负载不会随着服务数量的增加而增加。

图10

不过,这种模式存在一定的问题。首先,它会使监控变得更加困难,例如,当跟踪CPU时,是否需要跟踪一个独立于其他服务的CPU?或者是否关心整个主机的CPU?如果一个服务的负载很大,它最终会减少系统其他部分可用的资源。

服务的部署也可能更加复杂,因为确保一个部署不影响另一个部署会带来额外的麻烦。例如,如果每个微服务有不同的(潜在的矛盾的)依赖关系,需要安装在共享主机上,如何使微服务正常工作?

这个模型也会抑制团队的自主性,如果不同团队的服务安装在同一个主机上,那么由谁来为他们的服务配置主机?很可能,这最终会交由一个专门的团队来处理,这就意味着需要更多的协调才能部署服务。

从根本上说,在同一台机器(虚拟的或物理的)上运行大量的微服务实例,最终会严重破坏微服务作为整体独立部署的关键原则之一。因此,我们希望隔离地运行微服务实例,如图11所示。

图11

每个微服务实例都有自己的独立执行环境。它可以安装自己的依赖项,并拥有自己的一组隔离资源。

围绕部署和主机管理的许多工作实践都是为了优化资源的稀缺性。在过去,如果想要另一台机器来实现隔离,唯一的选择是购买或租用另一台物理机器。这通常需要很长的前置时间,并导致长期的成本输出。一般情况下,客户每两到三年才提供新的服务器是很常见的,而试图在这些时间线之外获得额外的机器是很困难的。但是按需计算平台已经大大降低了计算资源的成本,虚拟化技术的改进意味着更大的灵活性,甚至对于内部托管的基础设施也是如此。

随着容器化技术的发展,我们有了比以往更多的选择来提供独立的执行环境。如图12所示,一般来说,独立的物理机器为我们的服务提供的最好的隔离,但成本最高;容器化弱化了隔离性,但往往节约了大量的成本,且部署更快。

图12

如果将微服务部署在共有平台上,如AWS、ECS,平台会提供这种隔离,根据平台本身的性质,微服务实例最终运行在容器或专用VM中。

Focus on Automation

随着添加的微服务越来越多,需要处理的部件也越来越多—-需要配置的流程越来越多,需要监控的实例也越来越多。如果主要以人工方式管理操作流程,就意味着更多的服务将需要越来越多的人来处理。

此时,需要关注自动化,选择允许以自动方式完成任务的工具和技术,理想的情况下是将基础设置作为代码来使用。

随着微服务数量的增加,自动化变得越来越重要,此时应该认真考虑允许高度自动化的技术,并将自动化作为企业文化的核心部分。

自动化也是确保开发人员仍然保持高效的方法。为开发人员提供自服务—-提供单个服务或服务组的能力是使他们的工作更轻松的关键。

能够实现自动化的选择技术始于用于管理主机的工具。例如,编写一行代码来启动或关闭虚拟机、自动部署你所编写的软件、可以在没有人工干预的情况下部署数据库更改。如果你想要控制微服务体系结构的复杂性,那么自动化文化是关键。

Infrastructure as Code (IAC)

进一步考虑自动化的概念,基础设施即代码(IAC)是一种通过使用机器可读代码配置基础设施的概念。可以在chef或puppet文件中定义服务配置,或者编写一些bash脚本进行设置,但是无论最终使用什么工具,系统都可以通过使用源代码进入已知状态。可以说,IAC的概念可以被认为是实现自动化的一种方式。作为代码的基础设施将软件开发的概念引入了操作领域。通过通过代码定义我们的基础设施,可以对该配置进行版本控制、测试。

从理论上讲,可以使用任何编程语言将基础架构的思想应用于代码,但是在这个领域中有一些专业工具,如Puppet、Chef、Ansible等。这些工具是声明式的—-它们允许以文本形式定义期望的机器(或其他资源集)的样子,当应用这些脚本时,基础设施将进入该状态。

对基础架构代码的版本控制可以让你了解谁做了更改,这是审计人员喜欢的。它还使在给定时间点重新生成环境变得更容易,当试图跟踪缺陷时,这是特别有用的。

Zero-Downtime Deployment

实现零停机部署是开发和部署微服务的一个巨大进步。在没有零停机部署的情况下,当发布软件时,可能必须与上游用户协调,以提醒他们潜在的停机时间。

零宕机部署的目标是,上游消费者根本不应该注意到何时发布。这在很大程度上取决于微服务的性质。如果已经在微服务和消费者之间使用了中间件支持的异步通信,那么实现起来可能很简单—-发送给你的消息将在你备份时交付。但是,如果你正在使用基于同步的通信,那么这可能会有更多问题。

滚动升级之类的概念在这里很方便,这是使用Kubernetes这样的平台提供的功能,使用滚动升级,微服务不会在部署新版本之前完全关闭,而是随着运行新版本软件的新实例的增加,微服务的实例会慢慢减少。

Desired State Management

理想的状态管理能够指定应用程序的基础设施需求,并在不需要人工干预的情况下维护这些需求。如果正在运行的系统以一种不再维护所需状态的方式发生变化,底层平台将采取必要的步骤将系统恢复到所需状态。

作为理想状态管理如何工作的一个简单示例,可以指定微服务需要的实例数量,也可以指定这些实例需要多少内存和CPU。一些底层平台接受这个配置并应用它,使系统进入所需的状态。平台来确定哪些机器有空闲资源,可以分配这些资源来运行请求的实例数量。如图13所示,如果其中一个实例退出,平台识别出当前状态与期望的状态不匹配,并通过启动替换实例采取适当的行为。

图13

理想状态管理使开发和运营人员不必担心事情是如何完成的—-他们只需要把重点放在正确的状态定义上。意味着,在出现问题的情况下,例如实例退出、底层硬件故障或数据中心关闭,平台可以为你处理该问题,而不需要人工干预。

虽然可以构建自己的工具链来应用所需的状态管理,但通常使用已经支持它的平台。Kubernetes就是一个支持这一理念的工具,还可以使用诸如在公共云提供商(如Azure或AWS)上自动伸缩组等概念实现类似的功能。另一个可以提供这种功能的平台是Nomad。Kubernetes专注于部署和管理基于容器的工作负载,而Nomad有一个非常灵活的模型,可以运行其他类型的应用程序工作负载,比如Java应用程序、VMs、Hadoop作业等等。如果想要一个管理混合工作负载的平台,并且仍然使用期望的状态管理等概念,可以使用Nomad。

这些平台知道资源的底层可用性,并能够将所需状态的请求与可用资源匹配,作为操作员,无需知道底层配置,可以简单地说“我希望在两个数据中心上分布四个实例”,并依赖平台来确保完成这些配置。不同的平台提供不同级别的控制—-如果需要,可以使用更复杂的状态定义。

Prerequisites

为了利用所需的状态管理,平台需要某种方式来自动启动微服务的实例。因此,拥有微服务实例的完全自动化部署是理想状态管理的先决条件。可能还需要仔细考虑实例启动所需的时间。如果正在使用所需的状态管理来确保有足够的计算资源来处理用户负载,那么如果一个实例退出,你希望尽可能快地使用替换实例来替代。如果准备一个新实例需要很长时间,那么在实例退出的情况下,可能需要有多余的容量来处理负载,以便有足够的时间来启动一个新副本。

GitOps

GitOps是由Weaveworks开创的一个新的概念,它将所需的状态管理和基础设施的概念以代码的形式结合在一起。GitOps最初是在Kubernetes的工作环境中构思的,这也是相关工具的重点所在。

使用GitOps,你想要的基础设施状态是在代码中定义的,并存储在源代码控制中。当对期望的状态进行更改时,一些工具确保将更新后的期望状态应用到正在运行的系统。其思想是为开发人员提供一个简化的工作流程来处理他们的应用程序。

如果你使用过Chef或Puppet等基础设施配置工具,那么对于这种模式应该不陌生。当你使用Chef Server或Puppet Master时,你便拥有了一个能够在做出更改时动态推出更改的集中系统。GitOps的不同是,该工具利用Kubernetes内部的功能来帮助管理应用程序,而不仅仅是基础设施。

Deployment Options

当谈到可以用于微服务工作负载的方法和工具时,有很多选择。但应该根据刚才概述的原则来考虑这些方案。我们希望微服务以独立的方式运行,理想的部署方式是避免停机。我们希望我们选择的工具允许我们使用自动化的文化,在代码中定义我们的基础设施和应用程序配置,并在理想情况下为我们管理所需的状态。

让我们简单总结一下各种部署方案,然后看看它们是如何实现的:

  • Physical machine

    微服务实例直接部署到物理机器上,没有虚拟化。

  • Virtual machine

    微服务实例部署到虚拟机上。

  • Container

    微服务实例作为虚拟机或物理机上的独立容器运行。容器运行时可以由Kubernetes之类的容器编排工具管理。

  • Application container

    微服务实例运行在应用程序容器中,该容器管理其他应用程序实例,通常在相同的运行时上。

  • Platform as a Service (PaaS)

    高度抽象的平台用于部署微服务实例,通常抽象掉用于运行微服务的底层服务器的所有概念。例如Heroku、谷歌App Engine和AWS Beanstalk。

  • Function as a Service (FaaS)

    微服务实例被部署为一个或多个功能,这些功能由底层平台(如AWS Lambda或Azure functions)运行和管理。有争议的是,FaaS是PaaS的一种特定类型,但是考虑到最近这个想法的流行以及它提出的从微服务映射到部署工件的问题,它本身值得探索。

Physical Machines

直接将微服务部署到物理机器上的方式越来越少,这里的“直接”是指在你和底层硬件之间没有虚拟化层或容器层。由于一些不同的原因,这种情况变得越来越不常见了。首先,直接部署到物理硬件上可能会降低整个资产的利用率。如果我在物理机器上运行一个微服务实例,并且只使用硬件提供的一半CPU、内存或I/O,那么剩余的资源就会被浪费。这个问题导致了大多数计算基础设施的虚拟化,允许在同一物理机器上共存多个虚拟机。它提供了更高的基础设施利用率,这在成本效率方面有一些明显的好处。

如果你可以直接访问物理硬件,而不选择虚拟化,那么可能会在同一台机器上打包多个微服务—-当然,这违反了我们所讨论的关于为服务提供一个隔离的执行环境的原则。可以使用像Puppet或Chef这样的工具来配置机器—-帮助将基础结构实现为代码。问题是,如果只在单个物理机器的级别上工作,那么实现所需的状态管理、零停机部署等概念就需要我们在更高的抽象级别上工作,在上层使用某种管理层。这些类型的系统更常与虚拟机结合使用。

Virtual Machines

虚拟化已经改变了数据中心,它允许将现有的物理机分成更小的虚拟机。像VMware这样的传统虚拟化或主要云提供商使用的托管虚拟机基础设施(如AWS的EC2服务)在提高计算基础设施利用率方面产生了巨大的好处,同时降低了主机管理的开销。

从根本上说,虚拟化允许将底层机器分割为多个更小的“虚拟”机器,它们就像运行在虚拟机中的软件的普通服务器一样。可以将部分底层CPU、内存、I/O和存储能力分配给每个虚拟机,在我们的上下文中,这允许你将微服务实例的更多独立执行环境塞到单个物理机器上。

每个虚拟机都包含一个完整的操作系统和一组资源,虚拟机内部运行的软件可以使用这些资源。这确保了当每个实例部署到单独的VM上时,实例之间有非常好的隔离程度。每个微服务实例都可以根据自己的本地需求在VM中完全配置操作系统。但是,我们仍然有一个问题,如果运行这些虚拟机的底层硬件发生故障,我们可能会丢失多个微服务实例。有一些方法可以帮助解决这个特定的问题,包括我们前面讨论过的所需状态管理。

Cost of virtualization

当将越来越多的虚拟机打包到相同的底层硬件上时,将发现,就vm本身可用的计算资源而言,得到的回报是递减的。这是为什么呢?

把我们的物理机器想象成一个放袜子的抽屉。如果我们在抽屉里放很多木隔板,我们可以多放袜子还是少放袜子?答案是更少:分隔器本身也占据了空间!我们的抽屉可能更容易处理和整理,也许我们现在可以决定把t恤放在其中一个空间,而不是只放袜子,但更多的隔板意味着整体空间更小。

在虚拟化世界中,我们的开销与袜子抽屉分隔类似。为了理解这种开销来自哪里,让我们看看大多数虚拟化是如何完成的。两种虚拟化的对比如图14所示。在左边,我们看到了所谓的type2型虚拟化所涉及的各个层,在右边,我们看到了基于容器的虚拟化。

图14

Type 2型虚拟化是AWS、VMware、vSphere、Xen和KVM实现的虚拟化类型。(type1型虚拟化是指虚拟机直接在硬件上运行的技术,而不是在另一个操作系统上运行。)在我们的物理基础设施上,我们有一个主机操作系统。在这个操作系统上,我们运行一个叫做hypervisor的东西,它有两个关键任务。首先,它将CPU和内存等资源从虚拟主机映射到物理主机。其次,它充当控制层,允许我们操纵虚拟机本身。

在虚拟机内部,我们得到了看起来完全不同的主机。他们可以使用自己的内核运行自己的操作系统。可以将它们视为几乎是密封的机器,通过管理程序将它们与底层物理主机和其他虚拟机隔离开来。

类型2虚拟化的问题是这里的管理程序需要留出资源来完成它的工作。这占用了可以用于其他地方的CPU、I/O和内存。管理程序管理的主机越多,它需要的资源就越多。在某种程度上,这种开销成为进一步分割物理基础设施的约束。在实践中,这意味着将一个物理盒子分割成越来越小的部分的回报通常是递减的,因为越来越多的资源按比例进入管理程序的开销中。

尽管对于微服务工作负载来说,容器通常更受欢迎,但许多组织已经使用虚拟机来运行大型微服务系统,并取得了很大的效果。作为微服务的典型代表之一,Netflix通过EC2将其大部分微服务构建在AWS管理的虚拟机上。如果你需要它们带来的更严格的隔离级别,或者没有容器化应用程序的能力,那么vm可能是一个很好的选择。

Containers

容器成为了服务器端软件部署的主流方式,对于许多人来说,容器是打包和运行微服务架构的首选。由Docker推广的容器概念,与Kubernetes等支持容器编排平台相结合,已经成为许多人大规模运行微服务架构的首选。

首先看一下容器究竟是什么,并分析它与虚拟机的区别。

Isolated, differently

容器最初出现在unix风格的操作系统上,多年来实际上只在那些操作系统(如Linux)上可行。尽管Windows容器非常流行,但到目前为止,容器对Linux操作系统的影响最大。

在Linux上,进程由给定的用户运行,并根据权限的设置具有某些功能。进程可以产生其他进程。例如,如果我在终端中启动一个进程,该进程通常被认为是终端进程的子进程。Linux内核的任务是维护这个进程树,确保只有被允许的用户才能访问这些进程。此外,Linux内核能够将资源分配给这些不同的进程—-这是构建可行的多用户操作系统的重要部分。

运行在同一台机器上的容器使用相同的底层内核。不直接管理进程,可以将容器看作是整个系统进程树的子树的抽象,内核完成所有工作。这些容器可以为它们分配物理资源,这是内核为我们提供的句柄。这种通用方法已经以多种形式出现过,比如Solaris Zones和OpenVZ,但是这种想法是通过LXC进入Linux操作系统的主流的。当Docker在容器上提供了更高层次的抽象时,Linux容器的概念得到了进一步的发展,最初在内部使用LXC,然后完全替换它。

查看14中运行容器的主机的堆栈图,我们可以看到它与类型2虚拟化的一些不同之处。首先,我们不需要hypervisor。其次,容器似乎没有内核—-这是因为它利用了底层机器的内核。在图15中我们可以更清楚地看到这一点。容器可以运行自己的操作系统,但是操作系统使用了共享内核的一部分—-每个容器的进程树就在这个内核中存在。这意味着我们的主机操作系统可以运行Ubuntu,我们的容器可以运行CentOS,只要它们都可以作为同一底层内核的一部分运行。

图15

有了容器,不仅可以从不需要管理程序而节省的资源中获益;我们也从反馈中获得了好处。Linux容器的启动速度比虚拟机快得多。一个VM需要花很多分钟来启动,这并不少见,但是对于Linux容器,启动只需要几秒钟。在为容器分配资源方面,还可以对容器本身进行更细粒度的控制,这使得调整设置以最大限度地利用底层硬件变得容易得多。

由于容器更轻量级的特性,可以在相同的硬件上运行更多的容器,而不可能在vm上运行。通过在每个容器中部署一个服务(如图16所示),可以从其他容器中获得一定程度的隔离,这样做的成本效益比我们希望在自己的VM中运行每个服务要高得多。回到我们之前的袜子抽屉类比,与容器相比,袜子抽屉的分隔器要薄得多,这意味着袜子抽屉中用于放袜子的比例更高。

图16

Application Containers

图17中,多个不同的服务实例或应用程序部署在一个应用程序容器中。

图17

这种设置还可以在减少语言运行时开销方面产生好处。考虑在单个Java servlet容器中运行5个Java服务,只有一个JVM的开销,将其与使用容器时在同一主机上运行5个独立的jvm进行比较。

Function as a Service (FaaS)

在过去的几年里,唯一能与Kubernetes相提并论的技术是无服务器技术serverless(至少在微服务领域是如此)。无服务器实际上是一系列不同技术的总称,从使用这些技术的人的角度来看,底层计算机并不重要。不再需要管理和配置机器的细节。

“无服务器”并不意味着不再涉及服务器。这只是意味着开发者不再需要考虑太多。计算资源可以作为服务使用,而不必管理物理容量或限制。服务提供商越来越多地承担管理服务器、数据存储和其他基础设施资源的责任。开发人员可以建立自己的开源解决方案,但这意味着他们必须管理服务器、队列和负载。

功能即服务(Function as a Service,简称FaaS)已经成为无服务器的一个重要组成部分,这两个术语在很多情况下是可以互换的。这是不幸的,因为它忽略了数据库、队列、存储解决方案等其他无服务器产品的重要性。

正是AWS于2014年推出的Lambda产品,点燃了围绕FaaS的热情。在某种程度上,这个概念非常简单。你可以部署一些代码(一个“函数”)。代码处于休眠状态,直到有事件触发了它。你负责决定触发器可能是什么—-它可能是到达某个位置的文件、出现在消息队列上的项、通过HTTP传入的调用,或者其他东西。

当函数触发时,它运行;当函数结束时,它关闭。底层平台根据需要处理这些函数的开启关闭,并发执行这些函数,以便在适当的地方可以同时运行多个副本。

不运行的代码不会让你花钱—-你只需要为你使用的代码付费。这使得FaaS在负载低或不可预测的情况下成为一个很好的选择。底层平台为你处理函数,为你提供某种程度的隐式高可用性和健壮性,而无需你做任何工作。从根本上说,使用FaaS平台,就像使用其他许多无服务器产品一样,可以大大减少你需要担心的操作开销。

Limitations

在内部,所有FaaS实现都使用了某种容器技术,通常你不必担心构建将运行的容器,只需提供一些打包形式的代码。然而,这意味着你对运行的内容缺乏一定程度的控制;因此,需要FaaS提供程序支持你所选择的语言。在主要的云供应商中,Azure函数在这方面做得最好,支持各种不同的运行时,而谷歌cloud自己的云函数相比之下只支持很少的语言(谷歌只支持Go、一些Node版本和Python)。值得注意的是,AWS现在允许你为函数定义自己的自定义运行时,理论上允许你实现对所有语言的支持,尽管这将成为你必须维护的另一个操作开销。

这种对底层运行时缺乏控制的情况还扩展到对给予每个函数调用的资源缺乏控制。在谷歌Cloud、Azure和AWS上,你只能控制分配给每个功能的内存。这似乎意味着函数运行时要占用一定数量的CPU和I/O,但你不能直接控制这些。这可能意味着你最终不得不给一个函数更多的内存,即使它不需要,它只是为了获得你需要的CPU。最后,如果你觉得需要对函数可用的资源进行大量微调,那么至少在这个阶段,FaaS可能不是一个很好的选择。

需要注意的另一个限制是,函数调用可以提供运行时间方面的限制。例如,谷歌Cloud函数目前的执行时间限制为9分钟,而AWS Lambda函数可以运行15分钟。如果你愿意,Azure函数可以永远运行(取决于你的计划类型)。如果函数运行了很长一段时间,这可能表明函数并不适合处理这类问题。

最后,大多数函数调用被认为是无状态的。从概念上讲,这意味着函数不能访问前一个函数调用留下的状态,除非该状态存储在其他地方(例如,在数据库中)。这使得将多个函数链接在一起变得很困难—-考虑一个函数协调对其他下游函数的一系列调用。一个值得注意的例外是Azure Durable Functions,它以一种非常有趣的方式解决了这个问题。持久函数支持挂起给定函数的状态,并允许它在没有调用的地方重新启动—-这都是通过使用响应式扩展透明地处理的。这个解决方案比AWS自己的Step Functions(使用基于json的配置将多个函数联系在一起)更有利于开发人员使用。

Challenges

除了刚刚看到的限制之外,在使用FaaS时,可能还会遇到其他一些挑战。

首先,重要的是要解决FaaS中经常出现的一个问题,即“spin-up time”。从概念上讲,除非需要,否则函数根本不会运行。这意味着必须启动它们来服务传入的请求。现在,对于某些运行时,启动一个新版本的运行时需要很长时间,通常称为“冷启动”时间。JVM和. net运行时因此受到了很大的影响,因此使用这些运行时的函数的冷启动时间通常是很严重的。

但实际上,这些运行时很少冷启动。至少在AWS上,运行时是“暖的”,因此传入的请求由已经启动和运行的实例提供服务。由于FaaS提供程序后台进行优化,现在很难衡量“冷启动”的影响。尽管如此,如果这是一个问题,坚持使用运行时快的语言(Go、Python、Node和Ruby)可以有效地回避这个问题。

最后,函数的动态可伸缩性实际上会成为一个问题。函数在触发时启动,所有平台都对并发函数调用的最大数量有严格的限制,需要仔细注意这一点。如果系统的一个部分可以动态伸缩,但系统的其他部分不能,那么可能会发现这种不匹配会导致严重的问题。

总结

本文主要简述了微服务部署的基本原则,以及部署的方式。

感兴趣的关注如下公众号!

文章转载自Halugin,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论