编辑– 本系列文章共七部分,现已完成:
您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署。 并参阅我们关于微服务参考架构和微服务解决方案页面的系列文章。
这是使用微服务构建应用的系列文章的第六篇。 第一篇文章介绍了微服务架构模式,并讨论了使用微服务的优点和缺点。 以下文章讨论了微服务架构的不同方面:使用 API 网关、进程间通信、服务发现和事件驱动的数据管理。 在本文中,我们将讨论部署微服务的策略。
部署单片应用意味着运行单个(通常很大)应用的多个相同副本。 您通常会配置 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 实例。
您可以使用多种工具来构建自己的虚拟机。您可以配置持续集成 (CI) 服务器(例如Jenkins )来调用 Aminator将您的服务打包为 EC2 AMI。Packer.io 是自动创建虚拟机映像的另一种选择。 与 Aminator 不同,它支持多种虚拟化技术,包括 EC2、DigitalOcean、VirtualBox 和 VMware。
Boxfuse公司有一种引人注目的构建 VM 映像的方法,它克服了我在下面描述的 VM 的缺点。 Boxfuse 将您的 Java应用打包为最小 VM 映像。 这些图像构建速度快,启动迅速,并且由于暴露的攻击面有限,因此更安全。
CloudNative公司拥有 Bakery,这是一款用于创建 EC2 AMI 的 SaaS 产品。 您可以配置您的 CI 服务器以在微服务测试通过后调用 Bakery。 然后,Bakery 会将您的服务打包为 AMI。使用 Bakery 等 SaaS 产品意味着您不必浪费宝贵的时间来设置 AMI 创建基础设施。
每个虚拟机服务实例模式有许多好处。 虚拟机的一个主要优点是每个服务实例都完全独立地运行。 它具有固定数量的 CPU 和内存,并且不能从其他服务窃取资源。
将微服务部署为虚拟机的另一个好处是您可以利用成熟的云基础设施。 AWS 等云提供了负载均衡和自动扩展等有用的功能。
将服务部署为虚拟机的另一大好处是它封装了服务的实现技术。 一旦服务被打包为虚拟机,它就变成了黑盒子。 VM 的管理 API 成为部署服务的 API。 部署变得更加简单和可靠。
然而,每个虚拟机服务实例模式有一些缺点。 一个缺点是资源利用效率较低。 每个服务实例都有整个虚拟机的开销,包括操作系统。 此外,在典型的公共 IaaS 中,虚拟机的大小是固定的,因此虚拟机可能未得到充分利用。
此外,公共 IaaS 通常会对虚拟机收费,无论虚拟机处于繁忙还是空闲状态。 AWS 等 IaaS 提供了自动扩展功能,但很难对需求变化做出快速反应。 因此,您经常需要过度配置虚拟机,这会增加部署成本。
这种方法的另一个缺点是部署新版本的服务通常很慢。 VM 映像通常由于其大小而构建较慢。 此外,由于虚拟机的大小,其实例化速度通常很慢。 此外,操作系统通常需要一些时间来启动。 但请注意,这并不普遍正确,因为存在诸如 Boxfuse 构建的轻量级虚拟机。
每个虚拟机服务实例模式的另一个缺点是,通常您(或您组织中的其他人)要负责大量无差别的繁重工作。 除非您使用 Boxfuse 之类的工具来处理构建和管理虚拟机的开销,否则这是您的责任。 这种必要但耗时的活动会分散您对核心业务的注意力。
现在让我们看一下部署微服务的另一种方法,这种方法更轻量级,但仍具有虚拟机的许多优点。
当您使用每个容器服务实例模式时,每个服务实例都在其自己的容器中运行。 容器是操作系统级别的虚拟化机制。 容器由在沙箱中运行的一个或多个进程组成。 从进程的角度来看,它们有自己的端口命名空间和根文件系统。 您可以限制容器的内存和 CPU 资源。 一些容器实现也有 I/O 速率限制。 容器技术的示例包括Docker和Solaris Zones 。
下图显示了此模式的结构:
要使用此模式,您需要将您的服务打包为容器映像。 容器镜像是一个文件系统镜像,由运行服务所需的应用和库组成。 一些容器镜像由完整的 Linux 根文件系统组成。 其他的则更轻便。 例如,要部署 Java 服务,您需要构建一个包含 Java 运行时(可能是 Apache Tomcat 服务器)和已编译的 Java应用的容器映像。
将服务打包为容器镜像后,即可启动一个或多个容器。 您通常在每个物理或虚拟主机上运行多个容器。 您可以使用Kubernetes或Marathon等集群管理器来管理您的容器。 集群管理器将主机视为资源池。 它根据容器所需的资源和每个主机上可用的资源来决定将每个容器放在何处。
每个容器一个服务实例模式既有优点也有缺点。 容器的优点与虚拟机类似。它们将您的服务实例彼此隔离。 您可以轻松监控每个容器消耗的资源。 此外,与虚拟机一样,容器封装了用于实现服务的技术。 容器管理API也可作为管理您的服务的API。
然而,与虚拟机不同,容器是一种轻量级技术。 容器镜像通常构建得非常快。 例如,在我的笔记本电脑上,只需 5 秒钟即可将Spring Boot应用打包为 Docker 容器。 由于没有冗长的操作系统启动机制,容器启动也非常快。 当容器启动的时候,运行的是服务。
使用容器有一些缺点。 虽然容器基础设施正在迅速成熟,但它并不像虚拟机基础设施那样成熟。此外,容器不如虚拟机安全,因为容器彼此共享主机操作系统的内核。
容器的另一个缺点是您需要负责管理容器镜像的繁重工作。 此外,除非您使用托管容器解决方案(例如Google Container Engine或Amazon EC2 Container Service (ECS)),否则您必须管理容器基础设施以及它所运行的 VM 基础设施。
此外,容器通常部署在按虚拟机定价的基础架构上。 因此,如前所述,为了处理负载高峰,您可能会因过度配置虚拟机而产生额外成本。
有趣的是,容器和虚拟机之间的区别可能会变得模糊。 如前所述,Boxfuse VM 构建和启动速度很快。 Clear Containers 项目旨在创建轻量级虚拟机。 [编辑 – 正如 2017 年 12 月宣布的那样,Clear Containers 的开发现在正在开源Kata Containers项目中继续进行。]人们对unikernels的兴趣也日益浓厚。 Docker, Inc. 最近收购了 Unikernel Systems。
还有一种更新且越来越流行的无服务器部署概念,这种方法可以避免在容器或虚拟机中部署服务之间做出选择的问题。接下来让我们看看。
AWS Lambda是无服务器部署技术的一个例子。 它支持 Java、Node.js 和 Python 服务。 要部署微服务,您需要将其打包为 ZIP 文件并上传到 AWS Lambda。 您还提供元数据,其中除其他内容外,还指定了调用来处理请求(又称事件)的函数的名称。 AWS Lambda 自动运行足够的微服务实例来处理请求。 您只需根据所花费的时间和消耗的内存为每个请求付费。 当然,魔鬼藏在细节中,您很快就会发现 AWS Lambda 存在局限性。 但是,您作为开发人员或您组织中的任何人都不需要担心服务器、虚拟机或容器的任何方面,这种想法非常有吸引力。
Lambda 函数是一种无状态服务。 它通常通过调用 AWS 服务来处理请求。 例如,当将图像上传到 S3 存储桶时调用的 Lambda 函数可以将一个项目插入 DynamoDB 图像表中,并将消息发布到 Kinesis 流以触发图像处理。 Lambda 函数还可以调用第三方 Web 服务。
调用 Lambda 函数有四种方法:
cron
的计划定期如您所见,AWS Lambda 是一种部署微服务的便捷方式。 基于请求的定价意味着您只需为您的服务实际执行的工作付费。 此外,由于您不负责 IT 基础设施,因此您可以专注于开发应用。
但也存在一些重大的限制。 它不适用于部署长期运行的服务,例如使用来自第三方消息代理的消息的服务。 请求必须在 300 秒内完成。 服务必须是无状态的,因为理论上 AWS Lambda 可能会为每个请求运行一个单独的实例。 它们必须使用其中一种受支持的语言编写。 服务也必须快速启动;否则,它们可能会超时并终止。
部署微服务应用具有挑战性。 有数十甚至数百种用各种语言和框架编写的服务。 每个都是一个小型应用,具有自己特定的部署、资源、扩展和监控要求。 有几种微服务部署模式,包括每个虚拟机的服务实例和每个容器的服务实例。 部署微服务的另一个有趣的选择是 AWS Lambda,一种无服务器方法。 在本系列的下一篇也是最后一部分中,我们将研究如何将单片应用迁移到微服务架构。
编辑– 本系列文章共七部分,现已完成:
您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署。 并参阅我们关于微服务参考架构和微服务解决方案页面的系列文章。
客座博主 Chris Richardson 是原CloudFoundry.com的创始人,该网站是针对 Amazon EC2 的早期 Java PaaS(平台即服务)。 他现在为各组织提供咨询服务,以改进他们开发和部署应用的方式。 他还定期在https://microservices.io上撰写有关微服务的博客。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”