部署单体应用程序的时候,我们往往需要运行单个的通常也是大型应用程序的多个相同副本。通常,您需要配置N台服务器(物理服务器或虚拟服务器),并在每台服务器上运行M个应用程序实例。单体应用程序的部署并非总是完全简单的,但比部署微服务应用程序要简单得多。
微服务应用程序包含数十甚至数百个服务。服务以多种语言和框架编写。每个应用程序都是一个微型应用程序,具有自己的特定部署,资源,扩展和监视要求。例如,我们需要根据对该服务的需求运行一定数量的每个服务的实例。另外,必须为每个服务实例提供适当的CPU,内存和I / O资源。更具挑战性的是,尽管存在这种复杂性,但部署服务必须快速,可靠且具有成本效益。
有几种不同的微服务部署模式。首先是每个主机多个服务实例的模式。
部署微服务的一种方法是使用“每个主机多个服务实例”模式。 使用此模式时,您将配置一个或多个物理或虚拟主机,并在每个虚拟或虚拟主机上运行多个服务实例。 这是应用程序部署的传统方法。 每个服务实例在一个或多个主机上的一个端口上运行。
下图显示了此模式的结构。
此模式有多种变体。每个服务实例的一个变体是一个流程或一个流程组。例如,您可以将Java服务实例作为Web应用程序部署在Apache Tomcat服务器上。一个Node.js服务实例可能包含一个父进程和一个或多个子进程。
此模式的另一个变体是在同一进程或进程组中运行多个服务实例。例如,您可以在同一Apache Tomcat服务器上部署多个Java Web应用程序,或在同一OSGI容器中运行多个OSGI捆绑软件。
每个主机多个服务实例模式既有优点也有缺点。一个主要的好处是它的资源使用相对高效。多个服务实例共享服务器及其操作系统。如果一个进程或进程组运行多个服务实例,例如共享同一个Apache Tomcat服务器和JVM的多个Web应用程序,则效率更高。
这种模式的另一个好处是,部署服务实例相对较快。您只需将服务复制到主机并启动即可。如果服务是用Java编写的,则可以复制JAR或WAR文件。对于其他语言,例如Node.js或Ruby,则复制源代码。无论哪种情况,通过网络复制的字节数都相对较小。
另外,由于缺少开销,因此启动服务通常非常快。如果服务是它自己的过程,则只需启动它。否则,如果服务是在同一容器进程或进程组中运行的多个实例之一,则可以将其动态部署到容器中或重新启动容器。
尽管具有吸引力,但“每个主机的多个服务实例”模式仍存在一些重大缺陷。一个主要缺点是,除非每个服务实例是一个单独的进程,否则服务实例几乎没有隔离。虽然您可以准确地监视每个服务实例的资源利用率,但不能限制每个实例使用的资源。行为异常的服务实例可能会占用主机的所有内存或CPU。
如果多个服务实例在同一进程中运行,则根本没有隔离。例如,所有实例可能共享相同的JVM堆。行为异常的服务实例很容易破坏在同一进程中运行的其他服务。此外,您无法监视每个服务实例使用的资源。
这种方法的另一个重要问题是,部署服务的运营团队必须知道如何执行服务的具体细节。服务可以用多种语言和框架编写,因此开发团队必须与操作共享许多细节。这种复杂性增加了部署期间出错的风险。
如您所见,尽管很熟悉,但是“每个主机的多个服务实例”模式仍存在一些重大缺陷。现在,让我们看一下避免这些问题的其他微服务部署方式。
部署微服务的另一种方法是“每主机服务实例”模式。 使用此模式时,每个服务实例都在其自己的主机上独立运行。 此模式有两种不同的专业化:每个虚拟机的服务实例和,每个容器的服务实例。
使用每个虚拟机模式的服务实例时,会将每个服务打包为虚拟机(VM)映像,例如Amazon EC2 AMI。 每个服务实例都是使用该VM映像启动的VM(例如,EC2实例)。 下图显示了此模式的结构
这是Netflix部署其视频流服务的主要方法。 Netflix使用Aminator将其每项服务打包为EC2 AMI。每个正在运行的服务实例都是一个EC2实例。
您可以使用多种工具来构建自己的VM。您可以配置持续集成(CI)服务器(例如Jenkins)以调用Aminator将服务打包为EC2 AMI。 Packer.io是用于自动创建VM映像的另一个选项。与Aminator不同,它支持多种虚拟化技术,包括EC2,DigitalOcean,VirtualBox和VMware。
Boxfuse公司有一种引人注目的方式来构建VM映像,它克服了我在下面描述的VM的缺点。 Boxfuse将Java应用程序打包为最小的VM映像。由于这些映像暴露出有限的攻击面,因此它们可以快速构建,快速启动并且更安全。
CloudNative公司拥有Bakery,这是一个SaaS产品,用于创建EC2 AMI。您可以将CI服务器配置为在微服务测试通过后调用面包店。然后,面包店将您的服务打包为AMI。使用Bakery等SaaS产品意味着您不必浪费宝贵的时间来建立AMI创建基础架构。
每个虚拟机模式的服务实例有很多好处。 VM的主要优点是,每个服务实例都可以完全隔离地运行。它具有固定数量的CPU和内存,无法从其他服务中窃取资源。
将微服务部署为VM的另一个好处是,您可以利用成熟的云基础架构。 AWS之类的云提供了有用的功能,例如负载平衡和自动扩展。
将服务部署为VM的另一个好处是,它封装了服务的实施技术。将服务打包为VM后,它将变成一个黑匣子。 VM的管理API成为用于部署服务的API。部署变得更加简单和可靠。
但是,每个虚拟机的服务实例模式有一些缺点。一个缺点是资源利用效率较低。每个服务实例都有整个VM(包括操作系统)的开销。此外,在典型的公共IaaS中,VM具有固定的大小,并且VM使用率可能不足。
迁移时,公共IaaS通常对VM收费,而不管它们是忙还是闲。像AWS这样的IaaS可提供自动扩展功能,但是很难对需求变化做出快速反应。因此,您通常必须过量配置VM,这会增加部署成本。
这种方法的另一个缺点是,部署新版本的服务通常很慢。由于VM映像的大小,其生成速度通常很慢。同样,再次由于其大小,VM实例化速度通常很慢。另外,操作系统通常需要一些时间才能启动。但是请注意,这并不是普遍适用的,因为存在轻量级VM,例如Boxfuse构建的那些。
每个虚拟机服务实例模式的另一个缺点是通常您(或组织中的其他人)要承担很多无差别的工作。除非您使用Boxfuse之类的工具来处理构建和管理VM的开销,否则这是您的责任。这项必要但耗时的活动分散了您的核心业务。
当您使用“每个容器的服务实例”模式时,每个服务实例都在其自己的容器中运行。 容器是操作系统级别的虚拟化机制。 容器由在沙箱中运行的一个或多个进程组成。 从进程的角度来看,它们具有自己的端口名称空间和根文件系统。 您可以限制容器的内存和CPU资源。 一些容器实现也具有I / O速率限制。 容器技术的示例包括Docker和Solaris Zones。
下图显示了此模式的结构:
要使用此模式,请将服务打包为容器映像。容器映像是由运行服务所需的应用程序和库组成的文件系统映像。一些容器映像由完整的Linux根文件系统组成。其他则更轻巧。例如,要部署Java服务,您需要构建一个容器映像,其中包含Java运行时(可能是Apache Tomcat服务器)和已编译的Java应用程序。
将服务打包为容器映像后,便可以启动一个或多个容器。通常,您在每个物理或虚拟主机上运行多个容器。您可以使用集群管理器(例如Kubernetes或Marathon)来管理容器。集群管理器将主机视为资源池。它根据容器所需的资源和每个主机上可用的资源来决定将每个容器放置在何处。
每个容器的服务实例模式既有优点也有缺点。容器的好处类似于VM的好处。它们将您的服务实例彼此隔离。您可以轻松地监视每个容器消耗的资源。另外,容器与VM一样,封装了用于实现服务的技术。容器管理API也可用作管理服务的API。
但是,与VM不同,容器是一种轻量级技术。容器映像通常构建起来非常快。例如,在我的笔记本电脑上,将Spring Boot应用程序打包为Docker容器仅需5秒钟。由于没有冗长的OS启动机制,因此容器也可以非常快速地启动。当容器启动时,运行的是服务。
使用容器有一些缺点。尽管容器基础结构日趋成熟,但它不如VM基础结构成熟。另外,容器不如VM安全,因为容器彼此共享主机OS的内核。
容器的另一个缺点是,您要对管理容器图像进行无差别的繁重工作负责。另外,除非您使用托管容器解决方案(例如Google Container Engine或Amazon EC2容器服务(ECS)),否则您必须管理容器基础架构以及可能在其上运行的VM基础架构。
此外,容器通常部署在按虚拟机定价的基础架构上。因此,如前所述,您可能会产生过度配置VM的额外费用,以处理负载高峰。
有趣的是,容器和VM之间的区别可能会模糊。如前所述,Boxfuse VM可以快速构建和启动。 Clear Containers项目旨在创建轻量级VM。 [编辑–正如2017年12月宣布的那样,开源容器Kata Containers项目现在继续进行Clear Containers的开发。]对Unikernels的兴趣也越来越大。 Docker,Inc.最近收购了Unikernel Systems。
还有一种新的和越来越流行的无服务器部署概念,它是一种避免必须在容器或VM中部署服务之间进行选择的问题的方法。接下来让我们看看。
AWS Lambda是无服务器部署技术的示例。它支持Java,Node.js和Python服务。要部署微服务,请将其打包为ZIP文件,然后将其上传到AWS Lambda。您还提供元数据,元数据除其他事项外,该元数据指定为处理请求(也称为事件)而调用的函数的名称。 AWS Lambda自动运行您的微服务的足够实例来处理请求。您只需根据花费的时间和消耗的内存为每个请求付费。当然,细节中有魔鬼,您很快就会看到AWS Lambda有局限性。但是,无论您是开发人员还是组织中的任何人都不需要担心服务器,虚拟机或容器的任何方面的想法令人着迷。
Lambda函数是无状态服务。它通常通过调用AWS服务来处理请求。例如,将图像上载到S3存储桶时调用的Lambda函数可以将项目插入DynamoDB图像表中,并将消息发布到Kinesis流以触发图像处理。 Lambda函数还可以调用第三方Web服务。
有四种方法可以调用Lambda函数:
如您所见,AWS Lambda是部署微服务的便捷方法。基于请求的定价意味着您只需为服务实际执行的工作付费。另外,由于您不对IT基础结构负责,因此您可以专注于开发应用程序。
但是,存在一些重大限制。它不打算用于部署长期运行的服务,例如消耗来自第三方消息代理的消息的服务。请求必须在300秒内完成。服务必须是无状态的,因为从理论上讲,AWS Lambda可能会为每个请求运行一个单独的实例。必须使用一种受支持的语言编写它们。服务还必须快速启动;否则,它们可能会超时并终止。
部署微服务应用程序具有挑战性。 以多种语言和框架编写的服务有数十甚至数百种。 每个应用程序都是一个微型应用程序,具有自己的特定部署,资源,扩展和监视要求。 有几种微服务部署模式,包括每个虚拟机的服务实例和每个容器的服务实例。 部署微服务的另一个有趣的选择是无服务器方法AWS Lambda。