06-微服务部署策略

原文链接

这是关于使用微服务构建应用程序的系列文章的第六篇。第一篇文章介绍了微服务架构模式,并讨论了使用微服务的优缺点。以下文章讨论了微服务架构的不同方面:使用API网关,进程间通信,服务发现和事件驱动的数据管理。在本文中,我们将介绍部署微服务的策略。

动机

部署单体应用意味着运行单个(通常是大型)应用程序的多个相同副本。通常会配置N个服务器(物理或虚拟),并在每个服务器上运行M个实例。单体应用的部署并不总是完全简单,但它比部署微服务应用程序简单得多。

微服务应用程序包含数十甚至数百个服务。服务以各种语言和框架编写,每个都是一个迷你应用程序,具有自己的特定部署,资源,扩展和监控要求。

例如,需要根据根据服务的需求运行每个服务特定数量的实例。同时,必须为每个服务实例提供适当的CPU,内存和I/O资源。

更具挑战性的是:尽管存在这种复杂性,但部署服务必须快速,可靠且具有成本效益

有一些不同的微服务部署模式。让我们首先看一下每个主机多服务实例模式。

单主机多服务实例模式

部署微服务的一种方法是使用单主机多服务实例模式。使用此模式时,可以配置一个或多个物理或虚拟主机,并在每个主机上运行多个服务实例。这是应用程序部署的传统方法,每个服务实例都在一个或多个主机上的一个已知的端口上运行。下图显示了此模式的结构。

image

这种模式有几种变体。

  • 一种变体是:每个服务实例是进程或进程组。例如:

    • Java服务实例部署为Apache Tomcat服务器上的Web应用程序
    • Node.js服务实例可能包含父进程和一个或多个子进程
  • 另一个变体是:在同一进程或进程组中运行多个服务实例。例如:

    • 可以在同一个Apache Tomcat服务器上部署多个Java Web应用程序
    • 或者在同一个OSGI容器中运行多个OSGI包

单主机多服务实例模式的优点:

  • 资源使用相对有效。多个服务实例共享服务器及其操作系统。如果进程或进程组运行多个服务实例,例如,多个Web应用程序共享同一个Apache Tomcat服务器和JVM,则效率更高。
  • 部署服务实例的速度相对较快。只需将服务复制到主机并启动它。
    • 如果服务是用Java编写的,则复制JAR或WAR文件。
    • 对于其他语言,例如Node.js或Ruby,可以复制源代码。

在任何一种情况下,通过网络复制的字节数相对较小。

此外,由于开销很小,所以启动服务通常非常快。如果服务是它自己的进程,你只需启动它。否则,如果服务是在同一容器进程或进程组中运行的多个实例之一,则可以将其动态部署到容器中,也可以重新启动容器。

每个主机多服务实例模式的缺点:

  • 几乎没有服务实例的隔离,除非每个服务实例是一个单独的进程。虽然可以准确地监视每个服务实例的资源利用率,但无法限制每个实例使用的资源。

    行为不当的服务实例可能会占用主机的所有内存或CPU。如果多个服务实例在同一进程中运行,则根本没有隔离。例如,所有实例可能共享相同的JVM堆。行为不端的服务实例可能很容易破坏在同一进程中运行的其他服务。并且无法监视每个服务实例使用的资源。

  • 部署服务的运营团队必须知道如何执行该操作的具体细节。服务可以用各种语言和框架编写,因此开发团队必须与操作共享许多细节。这种复杂性增加了部署期间出错的风险。

单主机多服务实例模式具有一些明显的缺点,现在让我们看看部署避免这些问题的微服务的其他方法。

单主机单服务实例模式

单主机单服务实例模式。使用此模式时,可以在其自己的主机上独立运行每个服务实例。此模式有两种不同的特殊化:

  • 单虚拟机的服务实例
  • 单容器的服务实例

单虚拟机单服务实例模式

当使用单虚拟机单服务实例模式,将每个服务打包为虚拟机(VM)镜像,例如Amazon EC2 AMI。每个服务实例都是使用该VM镜像启动的VM(例如,EC2实例)。下图显示了此模式的结构:

image

这是Netflix用于部署其视频流服务的主要方法。

Netflix使用Aminator将其每项服务打包为EC2 AMI。每个正在运行的服务实例都是EC2实例。可以使用各种工具来构建自己的VM。可以配置持续集成(CI)服务器(例如,Jenkins)以调用Aminator将的服务打包为EC2 AMI。

Packer.io是自动创建VM镜像的另一种选择。与Aminator不同,它支持各种虚拟化技术,包括EC2,DigitalOcean,VirtualBox和VMware。

Boxfuse公司有一种令人信服的方法来构建VM镜像,它克服了我在下面描述的虚拟机的缺点。Boxfuse将Java应用程序打包为最小的VM镜像。这些镜像构建速度快,启动快,并且因为它们暴露有限的攻击面而更安全。

CloudNative公司拥有Bakery,这是一个用于创建EC2 AMI的SaaS产品。可以将CI服务器配置为在微服务通过测试后调用Bakery。然后,Bakery将的服务打包为AMI。使用Bakery等SaaS产品意味着不必浪费宝贵的时间来设置AMI创建基础架构。

单虚拟机单服务实例模式的优点:

  • 每个服务实例都完全隔离运行:它具有固定数量的CPU和内存,不能从其他服务中窃取资源。
  • 利用成熟的云基础架构:诸如AWS之类的云提供了有用的功能,例如负载均衡和自动扩展。
  • 封装了用于实现服务的技术:一旦服务被打包为VM,它就变成了黑盒子,VM的管理API成为部署服务的API。部署变得更加简单和可靠。

单虚拟机单服务实例模式的缺点:

  • 资源利用效率较低:每个服务实例都有整个VM的开销,包括操作系统。
  • 在典型的公共IaaS中,VM具有固定的大小,并且VM可能未充分利用
  • 迁移,公共IaaS通常会为VM收费,无论他们是忙还是闲。AWS等IaaS提供自动扩展功能,但很难对需求变化做出快速反应。因此,经常需要过度配置VM,这会增加部署成本
  • 部署新版本的服务通常很慢
    • VM镜像由于其大小而构建缓慢
    • VM的实例由于其大小运行很慢
    • 操作系统通常需要一些时间来启动(但请注意,这并非普遍适用,因为存在Boxfuse构建的轻量级VM)
  • 通常组织中的其他人负责大量无差别的繁重工作。除非使用像Boxfuse这样的工具来处理构建和管理VM的开销。这项必要但耗时的活动会分散的核心业务。

现在让我们看一下部署微服务的替代方法,这些微服务更轻量级但仍具有VM的许多优点。

单容器单服务实例模式

当使用单容器单服务实例模式时,每个服务实例都在其自己的容器中运行。容器是操作系统级别的虚拟化机制,在沙箱中运行的一个或多个进程,它们有自己的端口、命名空间、根文件系统,可以限制容器的内存和CPU资源,某些容器实现也具有I/O速率限制。容器技术的示例包括DockerSolaris Zones。下图显示了此模式的结构:

image

要使用此模式,请将服务打包为容器镜像(是由运行服务所需的应用程序和库组成的文件系统镜像)。一些容器镜像由完整的Linux根文件系统组成,其他更轻巧。

例如,要部署Java服务,需要构建一个包含Java运行时(可能是Apache Tomcat服务器)和已编译的Java应用程序的容器镜像。将服务打包为容器镜像后,即可启动一个或多个容器。

通常在每个物理或虚拟主机上运行多个容器,可以使用集群管理器(如Kubernetes或Marathon)来管理容器。集群管理器将主机视为资源池,根据容器所需的资源和每个主机上可用的资源决定放置每个容器的位置。

单容器单服务实例模式的好处类似于VM的好处:

  • 将的服务实例彼此隔离,可以轻松监视每个容器所消耗的资源。
  • 与VM类似,容器封装了用于实现服务的技术。容器管理API还可用作管理服务的API。 > 与VM不同,容器是一种轻量级技术。容器镜像通常非常快速构建(例如,在我的笔记本电脑上,将Spring Boot应用程序打包为Docker容器只需5秒钟)。
  • 容器也很快启动,因为没有冗长的操作系统启动机制,当容器启动时,运行的就是服务。

单容器单服务实例模式的缺点:

  • 虽然容器基础设施正在快速成熟,但它并不像VM的基础设施那样成熟。
  • 容器不如VM安全,因为容器彼此共享主机OS的内核。
  • 负责管理容器镜像是大量无差别的繁重工作。
  • 除非使用托管容器解决方案(如GKEECS),否则,必须管理容器基础结构以及可能运行的VM基础结构。

容器通常部署在收费的虚拟机基础架构上,因此,为了处理负载峰值,可能会产生过度配置VM的额外成本。有趣的是,容器和虚拟机之间的区别可能会变得模糊。如前所述,Boxfuse VM的构建和启动速度很快。

Clear Containers项目旨在创建轻量级VM。正如2017年12月宣布的那样,Clear Containers的开发现在继续在开源Kata Containers项目中进行。对unikernel的关注越来越多, Docker Inc. 最近收购了Unikernel Systems

还有一种更新且越来越流行的无服务器部署概念,这种方法可以避免在容器或虚拟机中部署服务之间做出选择的问题。让我们看看下一步。

无服务模式部署

AWS Lambda是无服务部署技术的一个示例。它支持Java,Node.js和Python服务。要部署微服务:

  1. 请将其打包为ZIP文件并将其上载到AWS Lambda
  2. 提供元数据,其中包括为处理请求而调用的函数的名称(例如,事件)

AWS Lambda自动运行足够的微服务实例来处理请求。只需根据所花费的时间和消耗的内存为每个请求付费。当然,魔鬼在细节中,很快就会看到AWS Lambda有局限性。但是,作为开发人员或组织中的任何人都不需要担心服务器,虚拟机或容器的任何方面,这一概念令人难以置信。

Lambda函数是无状态服务。它通常通过调用AWS服务来处理请求。例如,将镜像上载到S3存储桶时调用的Lambda函数可以将数据项插入DynamoDB镜像表,并将消息发布到Kinesis流以触发镜像处理。Lambda函数还可以调用第三方Web服务。

有四种方法可以调用Lambda函数:

  1. 直接使用Web服务请求
  2. 自动响应AWS服务(如S3,DynamoDB,Kinesis或简单电子邮件服务)
  3. 自动生成的事件,通过AWS API网关处理来自应用程序客户端的HTTP请求
  4. 定期任务,根据类似cron的执行计划

AWS Lambda是部署微服务的便捷方式。基于请求的定价意味着只需为服务实际执行的工作付费。此外,由于不负责IT基础架构,因此可以专注于开发应用程序。

但是,有一些重大的局限性,它不能用于部署长时间运行的服务(例如,使用来自第三方消息代理的消息服务):

  • 请求必须在300秒内完成
  • 服务必须是无状态的,因为理论上AWS Lambda可能为每个请求运行单独的实例。它们必须使用其中一种受支持的语言编写。服务也必须迅速开始;否则,他们可能会因为超时而被终止。

总结

部署微服务应用程序具有挑战性。有数十甚至数百种服务以各种语言和框架编写,每个都是一个迷你应用程序,具有自己的特定部署模式,资源,扩展和监视要求。

有几种微服务部署模式,包括:

  • 单虚拟机单服务实例
  • 单容器单服务实例
  • 无服务模式(AWS Lambda)

在本系列的下一部分和最后一部分中,我们将介绍如何将单体应用迁移到微服务架构。

上次修改: 14 April 2020