当前位置: 首页 > 科技观察

使用容器构建微服务架构

时间:2023-03-23 10:11:47 科技观察

在本文中,我们将讨论是什么让容器如此适合开发和测试,以及在AWS平台上构建基于微服务的架构。对于Web应用来说,微服务架构可以让应用的代码库更加敏捷和易于管理。下面,我们将介绍为什么这种架构可以极大地提高开发人员的生产力,并了解它如何快速迭代和扩展代码库。对于快速成长的初创公司,微服务架构可以让开发团队在研发过程中更加敏捷灵活。Web发展简史首先,让我们简单回顾一下过去20年的Web发展史。它可以让我们知道为什么微服务架构在Web开发领域如此受欢迎,同时了解这种架构能够解决的问题。在Web应用程序开发的早期,应用程序通常是使用通用网关接口(CGI)构建的,它为Web服务器提供了在处理来自浏览器的HTTP请求时执行脚本(通常用Perl编写)的能力。CGI的扩展性非常好,因为它需要为每个输入请求创建一个Perl进程。为了解决这个问题,那个时代的Web服务器通常会加入模块化的支持。Apache是当今最流行的网络服务器之一,它添加了“mod_perl”以允许Perl代码在内部运行,从而可以在更短的时间内执行CGI脚本。尽管与mod_perl等传统CGI技术相比有了很大的改进,但仍然存在问题。也就是说,负责视图层的代码(例如,在HTML页面上执行动态模块)经常混入应用程序逻辑代码中。这意味着完成一个简单的任务,例如向HTML列表添加一列,或向表单添加一个元素,通常需要修改低级应用程序代码。因此,下一阶段的网络编程技术源自“服务器页面”,它允许执行嵌入在HTML中的代码。这样,应用逻辑代码和视图代码就很好的分离了。在Java开发领域,一种称为“Model2”的设计模式发展迅速。这里,应用代码放在Javaservlets中,数据通过JavaBeans进行,视图层逻辑使用Javaserverpages。见下图:图1:Model2设计模型随后,在Java领域,“Model2”模式在短时间内演变为“Model-View-Controller(MVC)”框架,如ApacheStruts.在其他领域,RubyonRails非常流行。在MVC模式中,控制器类定义了方法,这些方法通过要调用的“路由”类映射到URL模式。控制器方法使用“模型”类封装核心应用程序实体的业务逻辑和数据。***,每个控件方法渲染一个“视图”进行显示,并修改相应模式类的方法。在这种模式下,业务、应用、视图逻辑得到了很好的分离,如图2所示:图2:MVC设计模型REST协议的盛行同时MVC被广泛接受,成为一种网络开发方式,进程间通信(IPC)也开始利用基于文本的序列化格式,例如XML和JSON。在SOAP等协议实现跨HTTPIPC后不久,Web开发不再局限于构建向浏览器传递内容的应用程序,为其他程序执行操作和传递数据的Web服务逐渐走上历史舞台。这种基于服务的架构非常强大,因为它消除了代码库的共享依赖关系,允许开发人员进一步解耦应用程序组件。SOAP协议和相关的WS-*标准也变得越来越复杂,越来越依赖于应用服务器的实现,目前开发者已经开始致力于更轻量级的REST协议。同时,随着移动设备的快速增加,WebUX开发逐渐转向AJAX和JavaScript框架,应用程序开发人员开始广泛使用REST进行客户端设备和Web服务器之间的数据传输。后来发现MVC框架也很适合开发REST端点。REST的面向资源的特性很好的映射到了controller和model的概念上,如图3所示:图3:MVCRESTendpointMonolithicarchitecture因此,曾今由model、view层、controller组成,主要用于MVC向应用程序提供HTML内容的应用程序发生了根本性的变化——它们不仅可以支持传统的HTML,还可以通过REST端点支持JSON。应用程序部署为单个文件(如Java)或作为同一目录中的文件集合(如Rails)。然而,不应忽视的是,所有应用程序代码都在同一进程中运行。因此,在扩展期间,开发人员需要将应用程序代码的多个副本部署到所需数量的服务器上。下图分析了Monolithic架构:图4:Monolithic架构Monolithic架构存在很多问题。首先,随着应用的功能和服务越来越多,代码会越来越复杂。对于新开发人员来说,这可能是一件非常头疼的事情。新的IDE也可能在加载和编译整个应用程序代码时出现问题,这也可能需要很长时间。此外,由于所有程序代码都在服务器上的同一个进程中运行,因此扩展应用程序的某些组件也非常困难。如果一个服务是内存密集型的,另一个是CPU密集型的,那么服务器必须有足够的内存和CPU来满足每个服务的需求。因此,考虑到每台服务器的CPU和内存使用率非常高,基础架构的总体成本可能非常高,尤其是采用扩展策略时。***非常微妙的是,应用程序的组成通常也映射到研发团队的结构。UX工程师负责构建UI组件,中间层开发人员通常负责构建服务器端点,数据库工程师和DBA负责数据访问组件和数据库。如果一个UX工程师希望增加一些展示,他往往需要中间层和数据库工程师的配合。就像通常期望阻力最小的水一样,每个工程师也希望将尽可能多的逻辑嵌入到他负责的应用程序中。鉴于这些问题,随着时间的推移,代码将变得越来越难以管理。微服务架构微服务架构就是为了解决这些问题而发明的。Monolithic架构应用程序中定义的服务将拆分成独立的服务,独立部署在不同的主机上。图5:微服务架构每个微服务都对应一个独立的业务功能,只定义了功能所必需的一些操作。这听起来很像面向服务的架构(SOA),实际上,微服务架构和面向服务的架构确实有很多共同的特点。两种架构都使用服务模式来组织代码,并且两种架构都在不同的服务之间建立了非常清晰的界限。然而,Service-OrientedArchitecture起源于Monolithic应用程序交互的需要,通常相互提供API(基于SOAP)。在面向服务的架构中,集成在很大程度上依赖于中间件,尤其是在企业服务总线(EBS)中。微服务架构通常使用消息总线,但在任何情况下,消息层中都没有逻辑——它纯粹用于服务之间的交互。这与ESB非常不同,后者包含大量逻辑-用于消息路由、模式验证、消息翻译和业务规则。因此,与传统的面向服务的架构相比,微服务架构往往更简单,并且不包括用于定义服务之间接口的相同级别的控制和规范化数据建模。通过使用微服务,开发会非常快,服务的演进只需要匹配业务的需求即可。微服务架构的另一个核心优势是服务可以根据资源需求独立扩展。微服务可以部署在较小的主机上,而不是运行具有大量CPU和内存的大型服务器,这些主机只需要满足部署它们的服务的需求。同时,开发者可以根据业务需求选择开发语言。例如,图像处理服务可以使用C++这样的高性能语言来实现,进行数学或静态运算的服务可以使用Python实现资源的增删查改等。基本操作通常通过Ruby执行。在微服务中,开发人员不需要考虑在Monolithic架构中使用的“一刀切”模型——比如只使用MVC框架和单一的编程语言。但是,不容忽视的是,微服务也有一些缺点。因为服务通常部署在多个主机上,所以很难跟踪给定服务在哪个主机上运行。同时,由于微服务架构所使用的主机容量往往小于单体架构,随着微服务架构的不断横向扩展,主机的数量会以非常恐怖的速度增长。在AWS环境中,微服务架构中的单个服务往往需要比最小的EC2实例类型更少的资源。这会造成过度配置并浪费开销。此外,如果使用不同的编程语言开发服务,则意味着每个服务部署都需要完全不同的库和框架,这使得服务部署非常复杂。容器的使用Linux容器技术的使用可以在很大程度上缓解微服务架构带来的问题。Linux容器技术使用诸如cnames和命名空间之类的内核接口,允许不同的容器共享同一个内核,同时完全隔离容器。Docker执行环境使用了一个名为libcontainer的模块,它标准化了这些接口。Docker还为容器镜像提供了类似GitHub的资源库DockerHub,这使得共享和发布容器变得非常简单。正是这种在同一主机上隔离容器的方式,方便了用不同语言开发的微服务代码的部署。使用Docker,我们可以创建一个DockerFile来描述服务之间所有使用的语言、框架和库依赖关系。例如,以下代码中的DockerFile可用于为微服务定义Docker镜像,它使用Ruby和Sinatra框架:FROMubuntu:14.04MAINTAINERJohnDoeRUNapt-getupdate&&apt-getinstall-ycurlwgetdefault-jregitRUNadduser--home/home/sinatra--disabled-password--gecos''sinatraRUNaddusersinatrasudoRUNecho'%sudoALL=(ALL)NOPASSWD:ALL'>>/etc/sudoersUSERsinatraRUNcurl-sSLhttps://get.rvm.io|bash-sstableRUN/bin/使用此映像构建的bash-l-c"源容器可以轻松部署到主机上,该主机还运行另一个使用Java构建的容器和DropWizard定义的Docker映像。容器执行缓解隔离了运行不同容器的主机,因此没有冲突由于使用不同的语言、库和框架容器而造成的。同时,令人欣慰的是,最近发布的AmazonEC2容器服务(AmazonECS)可以帮助您完成所有这些任务。使用AmazonECS,您可以定义一个池com将资源称为“集群”。一个集群由一个或多个EC2实例组成。AmazonECS负责管理集群中所有基于容器的应用程序,提供遥测和日志记录,并管理集群容量优化以实现高效的任务调度。AmazonECS提供了一个“任务定义”的概念,它可以定义一组容器来组成一个应用程序。任务定义中的每个容器都指定了容器所需的资源,AmazonECS将根据集群中的可用资源来安排任务的执行。微服务可以很方便的定义为一个任务,可以由两个容器组成——一个负责运行服务终端代码,一个负责运行数据库。AmazonECS可以管理这些容器之间的依赖关系,同时还可以跨集群平衡资源。同时,AmazonECS还可以无缝接入ElasticLoadBalancing、AmazonEBS、ElasticNetworkInterface、AutoScaling等多项关键AWS服务。使用AmazonEC2部署应用程序的所有基本特征都可通过AmazonECS用于基于容器的应用程序。此外,像AmazonECS这样的容器解决方案可以简化诸如“服务发现”之类的事情的实施。由于微服务往往跨多个主机部署,并根据负载进行伸缩,服务发现更有利于定位服务。在最简单的情况下,可以使用负载均衡器,但在更复杂的环境中,需要真正的分布式配置服务,例如ApacheZookeeper。使用AmazonECSAPI可以非常轻松地与Zookeeper等第三方工具集成。配置有Zookeeper的容器可以添加到任务定义中,并可以通过AmazonECS安排由集群中的AmazonEC2执行。在许多方面,使用容器技术实现微服务架构转变与Web开发在过去20年中的发展非常相似。其中许多演进旨在更好地利用计算资源和更轻松地维护日益复杂的Web应用程序。正如我们所看到的,使用Linux容器技术实现微服务架构完全符合这两个要求。在本文中,我们简要介绍了使用AmazonECS来定义微服务架构,但容器在分布式系统中的使用已经远远超出了微服务的范畴。在分布式系统中,越来越多的容器正在成为一等公民,在未来的报告中,我将讨论为什么AmazonECS对于管理容器的计算至关重要。