0106-选择微服务部署策略
动机
部署单一应用程序意味着运行单个,通常是大型应用程序的多个相同副本。您通常配置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公司有一种非常有吸引力的方式来构建虚拟机映像,这可以克服我在下面描述的虚拟机的缺点。Boxfuse将您的Java应用程序打包为最小的VM镜像。这些图像构建速度快,启动速度快,并且因为它们暴露有限的攻击面而更安全。
CloudNative公司拥有面包房,这是一种用于创建EC2 AMI的SaaS产品。您可以配置您的CI服务器以在微服务测试通过后调用Bakery。面包店然后将您的服务打包为AMI。使用面包房等SaaS产品意味着您不必浪费宝贵的时间设置AMI创建基础架构。
每个虚拟机模式的服务实例具有许多优点。虚拟机的一个主要优点是每个服务实例都完全独立运行。它具有固定数量的CPU和内存,不能从其他服务中窃取资源。
将微服务部署为虚拟机的另一个好处是您可以利用成熟的云基础架构。诸如AWS之类的云提供了有用的功能,例如负载平衡和自动调节。
将服务部署为虚拟机的另一大好处是它封装了服务的实现技术。一旦服务已经被打包成虚拟机,它就变成了一个黑匣子。VM的管理API成为部署服务的API。部署变得更简单,更可靠。
然而,每个虚拟机模式的服务实例有一些缺点。一个缺点是资源利用效率较低。每个服务实例都有整个虚拟机的开销,包括操作系统。而且,在典型的公共IaaS中,虚拟机的大小固定,虚拟机可能会被利用不足。
移动,公共IaaS通常收取虚拟机费用,无论它们是忙碌还是空闲。像AWS这样的IaaS提供了自动调节功能,但很难对需求变化做出快速反应。因此,您经常需要过度配置虚拟机,这会增加部署成本。
这种方法的另一个缺点是部署新版本的服务通常很慢。虚拟机映像的大小通常很慢。而且,VM的实例化速度通常很慢,这也是因为它们的大小。另外,操作系统通常需要一些时间才能启动。但是,请注意,这并不普遍,因为轻量级虚拟机(如由Boxfuse构建的虚拟机)存在。
每个虚拟机模式的服务实例的另一个缺点是通常您(或您组织中的其他人)负责进行大量无差别的繁重工作。除非您使用像Boxfuse这样的工具来处理构建和管理虚拟机的开销,否则这是您的责任。这项必要但费时的活动会分散您的核心业务。
现在让我们看看另一种部署更轻量级的微服务的方法,但仍然具有VM的许多优点。
每个容器模式的服务实例
当您使用每个容器模式的服务实例时,每个服务实例都在其自己的容器中运行。容器是操作系统级别的虚拟化机制。一个容器由一个或多个在沙箱中运行的进程组成。从进程的角度来看,他们有自己的端口名称空间和根文件系统。您可以限制容器的内存和CPU资源。一些容器实现也具有I / O速率限制。容器技术的示例包括Docker和Solaris Zones。
下图显示了这种模式的结构:
要使用此模式,请将您的服务打包为容器图像。容器映像是由运行服务所需的应用程序和库组成的文件系统映像。某些容器映像由完整的Linux根文件系统组成。其他人更轻。例如,要部署Java服务,需要构建包含Java运行时(可能是Apache Tomcat服务器)和已编译的Java应用程序的容器映像。
一旦将服务打包为容器图像,您就可以启动一个或多个容器。您通常在每台物理或虚拟主机上运行多个容器。您可以使用Kubernetes或Marathon等集群管理器来管理您的容器。集群管理器将主机视为资源池。它根据容器所需的资源和每台主机上可用的资源决定放置每个容器的位置。
每个容器模式的服务实例具有优点和缺点。容器的好处与虚拟机类似。他们隔离你的服务实例。您可以轻松监视每个容器消耗的资源。而且,像虚拟机一样,容器封装了用于实现服务的技术。容器管理API也可用作管理服务的API。
但是,与虚拟机不同,容器是一种轻量级技术。容器图像通常非常快速地构建。例如,在我的笔记本电脑上,将Spring Boot应用程序作为Docker容器封装需要5秒。由于没有冗长的操作系统启动机制,因此容器的启动速度也非常快。当容器启动时,运行的是服务。
使用容器有一些缺点。虽然容器基础架构正在迅速成熟,但并不像虚拟机的基础架构那么成熟。而且,容器不像虚拟机那样安全,因为容器彼此共享主机操作系统的内核。
容器的另一个缺点是,您要负责管理容器图像的无差别繁重工作。此外,除非您使用的是托管容器解决方案(如Google容器引擎或Amazon EC2容器服务(ECS)),那么您必须管理容器基础架构以及运行的虚拟机基础架构。
此外,容器通常部署在具有每个虚拟机定价的基础架构上。因此,如前所述,为了处理负载峰值,您可能会承担过度配置虚拟机的额外成本。
有趣的是,容器和虚拟机之间的区别可能会模糊。如前所述,Boxfuse虚拟机的构建和启动速度非常快。Clear Containers项目旨在创建轻量级VM。[编辑 - 正如2017年12月宣布的那样,Clear Container的开发现在在开源的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函数:
- 直接使用Web服务请求
- 自动响应由AWS服务(如S3,DynamoDB,Kinesis或简单电子邮件服务)生成的事件
- 自动通过AWS API网关处理来自应用程序客户端的HTTP请求
- 定期按照类似
cron
的时间表
如您所见,AWS Lambda是部署微服务的便捷方式。基于请求的定价意味着您只需支付您的服务实际执行的工作。另外,由于您不负责IT基础架构,因此您可以专注于开发应用程序。
但是,有一些重大的限制。它不打算用于部署长时间运行的服务,例如从第三方消息代理消费消息的服务。请求必须在300秒内完成。服务必须是无状态的,因为理论上AWS Lambda可能会为每个请求运行一个单独的实例。它们必须使用其中一种支持的语言编写。服务也必须快速启动; 否则,他们可能会超时并终止。
概要
部署微服务应用程序具有挑战性。有数十甚至数百种以各种语言和框架编写的服务。每个应用都有自己特定的部署,资源,扩展和监控需求。有几种微服务部署模式,包括每个虚拟机的服务实例和每个容器的服务实例。AWS Lambda是一种无服务器方式,是部署微服务的另一个有趣的选择。在本系列的下一个也是最后一部分中,我们将介绍如何将单一应用程序迁移到微服务架构。