在AWS上构建微服务应用程序

发布于:2021-01-21 14:22:33

0

397

0

微服务 无服务器 教程

在本文中,我们简要总结了微服务的共同特征,讨论了构建微服务的主要挑战,并描述了产品团队如何利用AWS来克服这些挑战。

微服务是一种架构和组织的软件开发方法,用于加快部署周期、促进创新、提高软件应用程序的可维护性和可伸缩性。因此,软件被组合成小型独立服务,这些服务通过定义良好的api进行通信,并由小型自包含团队拥有。

“微服务”一词在过去几年中受到越来越多的关注。微服务体系结构并不是一种全新的软件工程方法,而是各种成功和成熟概念的集合和组合,如面向对象方法、敏捷软件开发、面向服务体系结构、API优先设计和持续交付。

鉴于微服务这个术语是一个总括性术语,很难给出一个精确的定义。然而,所有的微服务架构都有一些共同的特点:

  • 分散式:微服务架构是具有分散式数据管理的分布式系统。他们不依赖中央数据库中的统一模式。每个微服务在数据模型上都有其自己的视图。这些系统还以开发,部署,管理和操作的方式分散。

  • 独立的:微服务架构中的不同组件可以独立更改,升级或替换,而不会影响其他组件的功能。同样,负责不同微服务的团队可以相互独立行动。

  • 做好一件事情:每个组件都是围绕一组功能而设计的,并且侧重于特定领域。一旦组件达到一定的复杂度,它可能会成为自己的微服务的候选者。

  • Polyglot:微服务架构没有遵循“一刀切”的方法。团队可以自由选择适合其特定问题的最佳平台。结果,微服务架构通常在操作系统,编程语言,数据存储和工具方面是异构的,这种方法称为多语言持久性和编程。

  • 黑匣子:微服务的各个组件被设计为一个黑匣子,即它们将复杂性的细节从其他组件隐藏起来。服务之间的任何通信都是通过定义明确的API进行的。通常,它们避免任何会损害组件独立性的隐藏通信,例如共享库或数据。

  • 构建,运行它:通常,负责构建服务的团队还负责生产中的操作和维护-此原理也称为DevOps。团队不仅可以按照自己的进度独立进步,而且还有助于使开发人员与软件的实际用户紧密联系,并增进对客户需求和期望的理解。微服务的组织方面不应该被低估,因为根据康韦定律,系统设计在很大程度上受到构建系统团队的组织结构的影响。

微服务的好处

微服务的分布式特性培养了一个由小型独立团队组成的组织,这些团队负责他们的服务。它们能够独立地开发和部署,并与其他团队并行,从而加快开发和部署过程。代码库团队正在处理的复杂度降低了,依赖项的数量减少了,从而使代码冲突最小化,方便了更改,缩短了测试周期,并最终缩短了新特性和服务的上市时间。来自客户的反馈可以更快地集成到即将发布的版本中。

事实上,小团队可以自主行动,并为各自的问题领域选择适当的技术、框架和工具,这是创新的重要驱动力。责任和问责培养了服务的主人翁文化。

通过在同一组中合并开发和操作技能来建立DevOps文化,可以消除可能的摩擦和相互矛盾的目标。当涉及到部署时,敏捷过程不再停止。相反,从提交到发布代码的整个应用程序生命周期管理过程可以自动化。尝试新的想法变得很容易,如果有什么东西不起作用,就可以回过头来。失败的低成本创造了一种变革和创新的文化。

围绕微服务组织软件工程也可以提高代码的质量。将软件划分为定义良好的小模块的好处类似于面向对象软件工程的好处:提高了代码的可重用性、可组合性和可维护性。

细粒度解耦是构建大规模系统的最佳实践。这是性能优化的先决条件,因为它允许为特定的服务选择合适的最佳技术。每个服务都可以使用适当的编程语言和框架实现,利用最佳的数据持久性解决方案,并使用性能最佳的服务配置进行微调。适当解耦的服务可以水平扩展并且相互独立。垂直扩展,即在更大的机器上运行相同的软件,受到单个服务器容量的限制,在扩展过程中可能会导致停机。水平扩展(即向现有池中添加更多服务器)是高度动态的,不会受到单个服务器的限制。缩放过程可以完全自动化。此外,应用程序的弹性可以得到提高,因为故障组件可以很容易地自动更换。

微服务架构也使得实现故障隔离变得更容易。诸如健康检查、缓存、隔板或断路器之类的技术允许减少故障组件的爆炸半径,并提高给定应用程序的总体可用性。

基于AWS的简单微服务体系结构

上图显示了AWS上典型微服务的参考体系结构。该体系结构分为四层:内容交付层、API层、应用层和持久层。

内容交付层的目的是加速静态和动态内容的交付,并可能卸载API层的后端服务器。由于微服务的客户端是从最近的边缘位置提供服务的,并且可以从缓存或代理服务器获得响应,并优化到源服务器的连接,因此可以显著减少延迟。相互靠近运行的微服务不会从CDN中受益,但可能会实现其他缓存机制以减少聊天次数并最小化延迟。

API层是所有客户机请求的中心入口点,它将应用程序逻辑隐藏在一组编程接口(通常是httprestapi)后面。API层负责接受和处理来自客户端的调用,并可能实现诸如流量管理、请求过滤、路由、缓存或身份验证和授权等功能。许多AWS客户使用Amazon弹性负载平衡(ELB)和Amazon弹性计算云(EC2)以及自动伸缩来实现API层。

应用层实现实际的应用逻辑。与API层类似,它可以使用ELB、Auto Scaling和EC2实现。

持久性层集中了使数据持久化所需的功能。将此功能封装在一个单独的层中有助于将状态排除在应用程序层之外,并更容易实现应用程序层的水平扩展和容错。静态内容通常存储在amazons3上,由amazoncloudfront交付。常用的会话数据存储在内存缓存中,如Memcached或Redis。AWS提供这两种技术作为托管Amazon ElastiCache服务的一部分。在应用程序服务器和数据库之间放置缓存是一种常见的机制,可以减轻数据库的读取负载,从而允许使用资源来支持更多的写入。缓存还可以改善延迟。

关系数据库在存储结构化数据和业务对象方面仍然非常流行。AWS提供了六个数据库引擎(microsoftsqlserver、Oracle、MySQL、MariaDB、PostgreSQL和amazonaurora)作为托管服务。

图2显示了微服务的体系结构,其中所有层都是由托管服务构建的,这消除了为实现可扩展性和高可用性而进行设计的体系结构负担,并消除了运行和监视微服务底层基础结构的操作工作。

降低复杂性

上面的架构已经高度自动化了。尽管如此,仍有空间进一步减少运行、维护和监控所需的操作工作。

构建、持续改进、部署、监视和维护API层可能是一项耗时的任务。有时需要运行不同版本的api,以确保客户端所有api的向后兼容性。开发周期中的不同阶段(如开发、测试、生产)进一步增加了操作工作。

访问授权是所有api的一个关键特性,但构建起来通常很复杂,而且常常是重复性的工作。当一个API发布并获得成功后,下一个挑战就是管理、监控和利用API的第三方开发人员的生态系统。

其他重要的特性和挑战包括限制请求以保护后端、缓存API响应、请求和响应转换,或者使用Swagger等工具生成API定义和文档。

amazonapi网关解决了这些挑战,降低了API层的操作复杂性。amazonapigateway允许客户通过导入Swagger定义或在AWS管理控制台中单击几下,以编程方式创建API。API网关充当运行在Amazon EC2、Amazon ECS、AWS Lambda或任何本地环境上的任何web应用程序的前门。简而言之:它允许在不管理服务器的情况下运行api。图2显示了API网关如何处理API调用以及如何与其他组件交互。来自移动设备、网站或其他后端服务的请求被路由到最近的Amazon CloudFront PoP,以最小化延迟并提供最佳的用户体验。API网关首先检查请求是否在缓存中,如果没有可用的缓存记录,则将其转发到后端进行处理。一旦后端处理了请求,API调用度量就会记录在amazoncloudwatch中,内容就会返回给客户端。

与运行ELB/Autoscaling/EC2相比,AWS提供了几个选项来简化部署,并进一步降低维护和运行应用程序服务的操作复杂性。一种选择是使用弹性豆茎。Elastic Beanstalk背后的主要思想是,开发人员可以轻松地上传他们的代码,并让Elastic Beanstalk自动处理基础设施供应和代码部署。重要的基础设施特性(如自动扩展、负载平衡或监视)是服务的一部分。

AWS Elastic Beanstalk支持多种编程框架,如Java、.Net、PHP、,节点.js,Python、Ruby、Go和Docker,以及熟悉的web服务器,如Apache、Nginx、Phusion Passenger和IIS。

另一种减少部署操作工作量的方法是基于容器的部署。像Docker这样的容器技术在过去的几年里得到了广泛的应用。这得益于以下几个好处:

  • 灵活性:容器化鼓励将应用程序分解为独立的细粒度组件,这使其非常适合微服务体系结构。

  • 效率:容器允许对资源需求(CPU,RAM)进行明确规定,从而可以轻松地在基础主机之间分布容器并显着提高资源利用率。与虚拟服务器相比,容器的性能开销也很轻,并且可以在底层操作系统上有效共享资源

  • 速度:容器是定义明确且可重复使用的工作单元,具有不变性,显式版本控制和易于回滚,精细的粒度和隔离等特性,所有这些特性均有助于显着提高开发人员的生产率和运营效率。

amazonecs无需安装、操作和扩展自己的集群管理基础设施。通过简单的API调用,您可以启动和停止支持Docker的应用程序,查询集群的完整状态,并访问许多熟悉的功能,如安全组、弹性负载平衡、EBS卷和IAM角色。

无服务器计算

消除操作复杂性的最终方法就是不再使用服务器。客户只需上传他们的代码,让AWS Lambda处理运行所需的一切,并以高可用性扩展执行。Lambda支持多种编程语言,可以从其他AWS服务触发,也可以直接从任何web或移动应用程序调用。Lambda与amazonapi网关高度集成。从amazonapi网关到AWS Lambda进行同步调用的可能性允许创建完全无服务器的应用程序。

虽然关系数据库仍然非常流行,而且人们对它的理解也很透彻,但它们并不是为无限规模而设计的,这会使应用技术来支持大量查询变得非常困难和耗时。NoSQL数据库被设计成支持可伸缩性、性能和可用性而不是关系数据库的一致性。一个重要的因素是NoSQL数据库通常不强制执行严格的模式。数据分布在可以水平缩放的分区上,并通过分区键检索。

由于单个微服务的设计目的是做好一件事,因此它们通常有一个简化的数据模型,非常适合NoSQL持久性。您可以使用amazondynamiodb创建一个数据库表,该表可以存储和检索任意数量的数据,并提供任意级别的请求通信。amazondynamiodb自动将表的数据和通信量分布在足够多的服务器上,以处理客户指定的请求容量和存储的数据量,同时保持一致和快速的性能。

为无服务器体系结构协调部署可能是一项具有挑战性的任务,因为有时必须更新一些管理服务。如果要向现有API添加新功能,则必须更改API网关中的API并部署新的Lambda函数。像Chalice或Serverless这样的框架极大地简化了整个部署过程。以下示例演示如何设置和部署由无服务器框架管理的简单应用程序:

npm install serverless –g
serverless create --template aws-nodejs
serverless deploy

这三行代码使用NPM安装Serverless框架,在中创建一个简单的项目节点.js,并将项目部署到AWS。Serverless使用AmazonCloudFormation作为基础来存储所有必要的配置。Serverless创建的每个资源都是通过一个中心CloudFormation模板创建的。例如,如果您想为映像添加一个额外的S3 bucket,可以在无服务器.yml-文件:

service: lambda-images
provider: aws
functions:
  ...

resources:
  Resources:
    ImagesBucket:
      Type: AWS::S3::Bucket
      Properties:
         BucketName: images-lambda
         # Or you could reference an environment variable
         # BucketName: ${env:BUCKET_NAME}

通过简单的无服务器部署,将为您部署此自定义资源。

服务发现

微服务体系结构的主要挑战之一是允许服务发现并相互交互。微服务体系结构的分布式特性不仅使服务难以通信,而且还带来了一些有趣的挑战,比如检查这些系统的健康状况以及何时有新的应用程序上线。此外,我们必须决定如何以及在何处存储元存储信息,例如应用程序可以使用的配置数据。下面我们将探讨在基于微服务架构的AWS上执行服务发现的几种技术。

一种相当直接的方法是使用弹性负载平衡服务(ELB)。这种方法的优点之一是,它提供运行状况检查,并在出现故障时自动注册/注销后端服务。将这些功能与DNS功能结合起来,就可以以最小的工作量和较低的成本构建一个简单的服务发现解决方案。您可以为每个微服务配置一个自定义域名,并通过CNAME条目将域名与ELB的DNS名称相关联。然后在需要访问的其他应用程序之间发布服务端点的DNS名称。使用新的应用程序负载均衡器,可以使用创建一个具有规则的侦听器来转发基于URL路径的请求。这称为基于路径的路由。您可以使用基于路径的路由将流量路由到多个后端服务。例如,可以将常规请求路由到一个目标组,将渲染图像的请求路由到另一个目标组。

Amazon Route 53可能是保存服务发现信息的另一个来源。路由53提供了几个可用于服务发现的功能。私有托管区域功能允许它保存域或子域的DNS记录集,并限制对特定虚拟私有云(VPC)的访问。您可以将IP地址、主机名和端口信息注册为特定微服务的SRV记录,并限制对相关客户端微服务的专有网络的访问。您还可以配置运行状况检查,定期验证应用程序的状态,并可能触发资源记录之间的故障转移。

另一种方法是使用键/值存储来发现微服务。尽管与其他方法相比,这种方法需要更多的时间来构建,但它提供了更多的灵活性和可扩展性,并且不会遇到DNS缓存问题。它还可以很好地与客户端负载平衡技术(如Netflix Ribbon)配合使用。客户端负载平衡可以帮助消除瓶颈并简化管理。

最后,许多人使用服务发现软件,如HashiCorp Consul或Netflix Eureka。Consul使服务注册自己和通过DNS或HTTP接口发现其他服务变得简单。此外,它还通过运行状况检查提供故障检测,从而防止将请求路由到不健康的主机。下面的博客文章展示了如何使用amazonecs通过Consul设置服务发现。

分布式监控

微服务体系结构可能由许多必须被监控的“移动部分”组成。您可以使用amazoncloudwatch来收集和跟踪度量,集中和监视日志文件,设置警报,并自动对AWS环境中的更改做出反应。Amazon CloudWatch可以监视AWS资源,如Amazon EC2实例、Amazon DynamoDB表和Amazon RDS DB实例,以及应用程序和服务生成的自定义度量,以及应用程序生成的任何日志文件。您可以使用amazoncloudwatch在系统范围内了解资源利用率、应用程序性能和运行状况。Amazon CloudWatch提供了一个可靠、可扩展且灵活的监控解决方案,您可以在几分钟内开始使用。您不再需要设置、管理和扩展自己的监控系统和基础设施。在微服务架构中,使用amazoncloudwatch监控定制度量的功能是一个额外的好处,因为开发人员可以决定应该为每个服务收集哪些度量。除此之外,还可以基于自定义度量实现动态伸缩。一致的日志记录对于故障排除和确定问题至关重要。微服务允许生产比以往更多的版本,并鼓励工程团队对生产中的新特性进行实验。了解客户影响对于逐步改进应用程序至关重要。

将日志存储在一个中心位置对于在分布式系统上进行调试和获得聚合视图至关重要。在AWS中,您可以使用Amazon CloudWatch日志来监视、存储和访问来自Amazon Elastic Compute Cloud(amazonec2)实例、AWS CloudTrail或其他源的日志文件。amazonec2包括对awslogs日志驱动程序的支持,该驱动程序允许将容器日志集中到CloudWatch日志。有不同的选项来集中日志文件。大多数AWS服务已经将日志文件集中化。AWS上日志文件的主要目的地是amazons3和amazoncloudwatch日志。日志文件是每个系统的敏感部分,几乎每个进程都会生成日志文件。集中式日志解决方案将所有日志聚合在一个中心位置,以便能够使用amazonemr或amazonredshift等工具搜索和分析这些日志。在许多情况下,一组微服务协同工作来处理请求。想象一下,一个复杂的系统由几十个微服务组成,而调用链中的一个服务发生了错误。即使每个微服务都正确地记录日志,并且日志都整合在一个中央系统中,也很难找到所有相关的日志消息。

correlationid的中心思想是,如果面向用户的服务接收到请求,则创建一个特定的ID。该ID可以在HTTP报头中传递(例如,使用诸如“x-correlation-ID”之类的报头字段)到每一个其他服务或传递的有效负载中。ID可以包含在每个日志消息中,以查找特定请求的所有相关日志消息。为了获得日志文件中调用的正确顺序,一个好方法是在头中发送一个计数器,如果请求流经体系结构,计数器将递增。springcloud提供了一个称为Sleuth的相关ID实现,它可以用于分布式跟踪,例如Zipkin。Zipkin是一个分布式跟踪系统。它有助于收集解决微服务体系结构中延迟问题所需的时间数据。使用springcloudsleuth非常简单,只需将Sleuth添加到Spring启动应用程序的类路径中,相关数据就会被收集到日志中。在日志中放置相关ID的HTTP处理程序示例如下所示:

@RestController
public class BaseController {
  private static Logger log = LoggerFactory.getLogger(BaseController);
  @RequestMapping("/")
  public String base() {
    log.info("Handling base");
    ...
    return "Hello World";
  }
}

闲谈

通过将单片应用程序分解为小型微服务,通信开销会增加,因为微服务必须相互通信。在许多实现中,restoverhttp被用作通信协议,它相当轻,但是高容量可能会导致问题。在某些情况下,考虑整合来回发送大量消息的服务可能是有意义的。如果您发现自己处于这样一种情况:为了减少聊天,您整合了越来越多的服务,那么您应该检查您的问题域和域模型。对于微服务来说,使用像HTTP这样的简单协议是很常见的。服务交换的消息可以以不同的方式编码,例如,以JSON或YAML等人类可读的格式或有效的二进制格式编码。HTTP是一种同步协议。客户端发送请求并等待响应。通过使用异步IO,客户机的当前线程不必等待响应,但可以执行不同的操作。

结论

微服务体系结构是一种克服传统单片体系结构局限性的分布式方法。虽然微服务有助于扩展应用程序和组织,同时缩短周期,但它们也带来了一些挑战,这些挑战可能会导致额外的体系结构复杂性和操作负担

AWS提供了大量的托管服务组合,帮助产品团队构建微服务体系结构,并将体系结构和操作复杂性降至最低。本文将指导您了解相关的AWS服务,以及如何使用AWS服务实现典型的模式,例如Service Discovery。