编者:本系列共7篇文章,现已全部发布:
还可以下载电子书,其中收录了全套文章以及使用NGINX Plus实施微服务的相关信息:《微服务:从设计到部署》。另请参阅我们的微服务参考架构系列文章和微服务解决方案页面。
本文是微服务应用构建系列的第6篇文章。第1篇文章介绍了微服务架构模式,并探讨了使用微服务的优缺点。后续文章分别讨论微服务架构的不同方面:使用API网关、进程间通信、服务发现以及事件驱动的数据管理。本文将探讨微服务的部署策略。
动机
部署单体应用意味着运行同一个应用的多个相同副本,而该应用通常较为庞大。通常需要预置N台服务器(物理服务器或虚拟服务器),并在每台服务器上运行该应用的M个实例。部署单体应用并非总是十分简单,但比部署微服务应用简单得多。
一个微服务应用由数十个甚至数百个服务组成。这些服务使用各种语言和框架编写。每个服务都是一个微型应用,有各自特定的部署、资源、扩展和监控要求。例如,需要根据每个服务的需求运行一定数量的服务实例。此外,还必须为每个服务实例提供适当的CPU、内存和I/O资源。更具挑战性的是,尽管如此复杂,服务部署仍必须快速、可靠且经济高效。
微服务有多种部署模式。我们先来了解“每台主机部署多个服务实例”模式。
每台主机多个服务实例模式
部署微服务的一种方式是使用“每台主机多个服务实例”模式。使用此模式时,需要预置一台或多台物理或虚拟主机,并在每台主机上运行多个服务实例。从许多方面来看,这是传统的应用部署方式。每个服务实例都在一台或多台主机上的已知端口运行。主机通常会被当作宠物对待。
下图显示了此模式的结构。

此模式有几种变体。其中一种是将每个服务实例作为一个进程或进程组。例如,可以将Java服务实例作为Web应用部署在Apache Tomcat服务器上。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实例)。下图显示了此模式的结构:

这是Netflix部署其视频流服务的主要方法。Netflix使用Aminator将每项服务打包为EC2 AMI。每个正在运行的服务实例都是一个EC2实例。
您可以使用多种工具构建自己的虚拟机。可以配置持续集成(CI)服务器(例如Jenkins),调用Aminator将服务打包为EC2 AMI。Packer.io是自动创建虚拟机镜像的另一种选择。与Aminator不同,它支持多种虚拟化技术,包括EC2、DigitalOcean、VirtualBox和VMware。
The company Boxfuse公司提供了一种颇具吸引力的VM镜像构建方式,可克服下文所述的VM缺点。Boxfuse将Java应用程序打包为精简的VM镜像。这些镜像构建速度快、启动迅速,并且由于暴露的攻击面有限,安全性更高。
The company CloudNative公司提供Bakery,这是一项用于创建EC2 AMI的SaaS服务。您可以将CI服务器配置为在微服务通过测试后调用Bakery。随后,Bakery会将服务打包为AMI。使用Bakery这样的SaaS服务,无需耗费宝贵时间搭建AMI创建基础设施。
每个虚拟机一个服务实例模式具有多项优势。虚拟机的一大优势是,每个服务实例都在完全隔离的环境中运行。每个实例都分配有固定的CPU和内存资源,无法占用其他服务的资源。
将微服务部署为虚拟机的另一个好处是,可以利用成熟的云基础设施。AWS等云平台提供负载均衡和自动扩缩容等实用功能。
将服务部署为虚拟机(VM)的另一大优势是,可以封装服务的实现技术。服务打包为VM后,就会成为一个黑盒。VM的管理API将作为部署该服务的API,从而使部署变得更加简单、可靠。
不过,每个虚拟机一个服务实例模式也存在一些缺点。其中一个缺点是资源利用效率较低。每个服务实例都需要承担整个虚拟机(包括操作系统)的开销。此外,在典型的公有IaaS中,虚拟机采用固定规格,因此可能无法得到充分利用。
此外,公有IaaS通常会对VM收费,无论VM处于繁忙还是空闲状态。AWS等IaaS虽然提供自动扩缩功能,但难以快速响应需求变化。因此,通常需要为VM预留过多资源,从而增加部署成本。
这种方法的另一个缺点是,部署新版本的服务通常较慢。VM镜像通常体积较大,因此构建速度较慢。VM同样会因体积较大而需要较长的实例化时间。此外,操作系统通常也需要一定的启动时间。不过,这并非普遍情况,因为也有由Boxfuse等工具构建的轻量级VM。
每个虚拟机一个服务实例模式的另一个缺点是,通常需要由您(或组织中的其他人员)承担大量繁重但无法形成差异化优势的工作。除非使用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基础设施。
此外,容器通常部署在按VM计费的基础设施上。因此,如前所述,为应对负载峰值,可能需要超额配置VM,从而产生额外成本。
值得注意的是,容器与VM之间的界限可能会逐渐模糊。如前所述,Boxfuse VM的构建和启动速度都很快。Clear Containers项目旨在创建轻量级VM。[编者注:根据2017年12月发布的公告,Clear Containers的开发工作现已转至开源Kata Containers项目并继续推进。]此外,unikernel也日益受到关注。Docker, Inc.最近收购了Unikernel Systems。
此外,还有一种较新且日益流行的无服务器部署理念。这种方法无需再纠结于将服务部署在容器中还是虚拟机中。接下来,我们来了解一下。
无服务器部署
AWS Lambda是无服务器部署技术的一个示例。它支持Java、Node.js和Python服务。要部署微服务,需要将其打包为ZIP文件并上传到AWS Lambda。此外,还需提供元数据,其中包括指定用于处理请求(也称为事件)的函数名称。AWS Lambda会自动运行足够数量的微服务实例来处理请求。每个请求仅根据处理时长和内存用量计费。当然,实际情况涉及许多细节,稍后您会看到AWS Lambda也存在一些限制。不过,无论是开发人员还是组织中的其他人员,都无需操心服务器、虚拟机或容器的任何问题,这一理念极具吸引力。
A Lambda 函数是一种无状态服务。它通常通过调用AWS服务来处理请求。例如,将图像上传到S3 存储桶时调用的Lambda函数,可以在DynamoDB的images表中插入一条记录,并向Kinesis流发布消息以触发图像处理。Lambda函数还可以调用第三方Web服务。
可通过以下四种方式调用Lambda函数:
- 直接使用Web服务请求调用
- 自动响应由S3、DynamoDB、Kinesis或Simple Email Service等AWS服务生成的事件
- 通过AWS API Gateway自动处理应用程序客户端发出的HTTP请求
- 按照类似
cron的计划定期执行
可以看出,AWS Lambda为部署微服务提供了一种便捷方式。按请求计费意味着只需为服务实际执行的工作付费。此外,由于无需负责IT基础设施,可以专注于应用开发。
不过,它也存在一些重大限制。它并非用于部署长时间运行的服务,例如从第三方消息代理接收消息的服务。请求必须在300秒内完成。服务必须是无状态的,因为理论上,AWS Lambda可能会为每个请求运行一个单独的实例。服务必须使用受支持的语言之一编写,并且必须快速启动,否则可能会因超时而终止。
总结
部署微服务应用颇具挑战。应用中包含数十甚至数百个使用不同语言和框架编写的服务。每个服务都是一个微型应用,对部署、资源、扩展和监控都有各自的特定要求。微服务有多种部署模式,包括每台虚拟机一个服务实例和每个容器一个服务实例。AWS Lambda是另一种值得关注的微服务部署方案,它采用无服务器方式。在本系列的下一篇也是最后一篇文章中,我们将介绍如何将单体应用迁移到微服务架构。
编者:本系列共7篇文章,现已全部发布:
还可以下载电子书,其中收录了全套文章以及使用NGINX Plus实施微服务的相关信息:《微服务:从设计到部署》。另请参阅我们的微服务参考架构系列和微服务解决方案页面。
客座博主Chris Richardson是早期网站CloudFoundry.com的创始人。该网站是面向Amazon EC2的早期Java平台即服务(PaaS)。目前,他为各类组织提供咨询,帮助其改进应用开发和部署方式。他还定期在https://microservices.io上发布有关微服务的博文。
相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
