《微服务架构设计模式》阅读笔记(四)

第7章 在微服务架构中实现查询

在微服务架构中实现查询操作有两种不同的模式:

  • API组合模式:这是最简单的方式,应尽可能使用。它的工作原理是让拥有数据的服务的客户端负责调用服务端,应组合服务返回的查询结果。
  • 命令查询职责隔离(CQRS)模式:它比API组合模式更强大,但也更复杂。它维护一个或多个视图数据库,其唯一的目的是支持查询。

7.1 使用API组合模式进行查询

7.1.1 findOrder()查询曹组偶

findOrder()操作通过主键检索订单。它将orderId作为参数并范围OrderDetails对象,该对象包含有关订单的信息。如图7-1所示。
在这里插入图片描述

7.1.2 什么是API组合模式

API组合模式通过调用有用数据的服务并组合结果来实现查询操作。图7-2显示了该模式的结构。它有两种类型的参与者:

  • API组合器:它通过查询数据提供方的服务来实现查询操作
  • 数据提供方服务:拥有查询返回的部分数据的服务
    在这里插入图片描述

7.1.3 使用API组合模式实现findOrder()查询操作

如图7-3所示。
在这里插入图片描述

7.1.4 API组合模式的设计缺陷

使用此模式时,必须解决两个设计问题:

  • 确定架构中的哪个组件是查询操作的API组合器
  • 如何编写有效的聚合逻辑

由谁来担任API组合器的角色
你有三个选择。第一个选择,如图7-4所示,由服务的客户端扮演API组合器的角色。
在这里插入图片描述
对于防火墙之外的客户以及通过较慢网络访问的服务,此选择可能不实用。
第二个选择,如图7-5所示,由实现应用程序外部API的API Gateway来扮演API组合器的角色。
在这里插入图片描述
这种方法使得运行在防火墙之外的客户端(例如移动设备)能够通过单个API调用有效地从众服务中检索数据。
第三个选择,如图7-6所示,将API组合器实现为独立的服务。
在这里插入图片描述
此选择可以用于由多个服务在内部使用的查询操作。还可用于外部可访问的查询操作,由于他们的聚合逻辑过于复杂,因此无法在API Gateway中完成查询,必须使用单独的服务。

API组合器应该使用响应式编程模型
略~

7.1.5 API组合模式的好处和弊端

此模式是在微服务架构中实现查询操作的简单直观方式。但它也有一些缺点:

  • 增加了额外的开销:需要调用多个服务和查询多个数据库,需要更多的计算和网络资源
  • 带来可用性降低的风险:操作的可用性随着所涉及的服务数量而下降
  • 缺乏事务数据一致性:存在查询操作返回不一致数据的风险

7.2 使用CQRS模式

许多企业级应用程序使用关系型数据库作为数据记录的事务系统,并使用文本搜索数据库(如Elasticsearch或Solr)进行文本搜索查询。具有此架构的应用程序利用了多个数据库的优势:关系型数据库的事务属性和文本数据的查询功能。
CORS是这种架构的概括。它维护一个或多个视图数据库,而不仅仅是文本搜索数据库,进而实现一个或多个应用程序的查询。

7.2.1 为什么要使用CQRS

实现一些特定的服务查询很有挑战性。也许服务的数据库不能有效地支持查询。或者,有时服务必须实现检索不同服务所拥有的数据的查询。

7.2.2 什么是CQRS

在微服务架构中实现查询经常为遇到以下三个问题:

  • 使用API组合模式检索分散在多个服务中的数据会导致昂贵、低效的内存中连接
  • 拥有数据的服务将数据存储在不能有效支持所需查询的表单或数据库中
  • 隔离问题的考虑意味着,拥有数据的服务不一定是会实现查询操作的服务

所有这三个问题的解决方案是使用CQRS模式。

CQRS隔离命令和查询
CQRS是命令查询职责隔离的简称,顾名思义,它涉及隔离或问题的分隔。如图7-8所示,它将持久化数据模型和使用数据的模块分为两部分:命令端和查询端。查询端通过订阅命令端发布的事件,使其数据模型与命令端数据模型保持同步。
在这里插入图片描述

7.2.3 CQRS的好处

在微服务架构中高效地实现查询
CQRS有效地实现了检索多个服务所拥有的数据的查询。使用API组合模式实现查询有时会导致大规模数据的昂贵、低效的内存中连接。对于这些查询,使用易于查询的CQRS视图更有效,该视图预加载(并预处理)来自两个或更多服务的数据。

高效地实现多种不同的查询类型
尝试使用单个持久化数据库支持所有查询通常具有挑战性,并且在某些情况下是不可能的。一些NoSQL数据库具有非常有限的查询能力。即使数据库具有支持特定类型查询的扩展,使用专用数据库通常也更有效。CQRS模型通过定义一个或多个视图来避免单个数据存储的限制,每个视图都有效地实现特定查询。

在基于事件溯源技术的应用程序中实现查询
CQRS还客服了事件溯源的主要限制。事件存储库仅支持基于主键的查询。CQRS模式订阅由基于事件溯源的聚合发布的事件流,可以保持最新的聚合的一个或多个视图,由此解决此限制。这也是基于事件溯源的应用程序总是使用CQRS的原因。

更进一步实现问题隔离
CQRS的另一个好处是它会隔离问题。领域模型及其相应的持久化数据模型不必同时处理命令和查询。CQRS模式为服务的命令端和查询端定义了单独的代码模块和数据库模式。通过隔离问题,命令端和查询端可能更简单,更易于维护。

7.2.4 CQRS的弊端

更加复杂的架构
CQRS的一个缺点是它使复杂性增加了。开发人员必须编写更新和查询视图的查询端服务。管理和运维额外的数据存储库提高了运维的复杂性。此外,应用程序可能使用不同类型的数据库,这进一步增加了开发人员和运维人员面临的复杂性。

处理数据复制导致的延迟
CQRS的另一个缺点是处理命令端和查询端视图之间的“滞后”。更新聚合然后立即查询视图的客户端应用程序可能会看到聚合的先前版本。

7.3 设计CQRS视图

略~

7.4 实现基于AWS DynamoDB的CQRS视图

略~

第8章 外部API模式

8.1 外部API的设计难题

API的一种设计思路是让客户端直接调用服务。从表面上看,这听起来非常简单,毕竟,这就是客户端调用单体应用程序的API的方式。但由于存在以下弊端,这种方法很少用于微服务架构:

  • 细粒度服务API要求客户端发出多个请求以检索所需的数据,这样做效率低,并且可能导致糟糕的用户体验。
  • 由于客户端了解每项服务以及服务的API从而导致封装不足(紧耦合),因此今后很
    难更改服务的架构和API
  • 服务可能使用对客户端而言不便或不能使用的进程间通信机制,尤其是防火墙外的客户端。

8.1.1 FTGO移动客户端API的设计难题

FTGO应用程序的单体版本具有返回订单详细信息的API接口。移动客户端通过发出单请求来检索所需的信息。相比之下,在FTGO应用程序的微服务版本中,订单
详细信息分散在多个服务中。
如果移动客户端直接调用服务,则必须如图8-2所示,进行多次调用以检索此数据。
在这里插入图片描述
多次客户端请求导致用户体验不佳
第一个问题是移动应用程序有时必须发出多个请求来检索它想要显示给用户的数据。应用程序和服务之间的频繁交互可能使应用程序看起来无响应,尤其是当它使用互联网或移动网络时。与局域网相比,互联网具有更低的带宽和更高的延迟,移动网络甚至更糟。移动网络(和互联网)的延迟通常是局域网的100倍。
检索订单详细信息时,较高的延迟可能不是问题,因为移动应用程序通过同时执行请求来最小化延迟。总体响应时间不大于单个请求的响应时间。但在其他情况下,客户端可能需要按顺序执行请求,这将导致糟糕的用户体验。
更重要的是,由于网络延迟导致的糟糕的用户体验并不是烦琐的API的唯一问题。它可能要求移动开发人员编写复杂的API组合代码。而前端开发人员的首要任务应该是创建优质的用户体验,而不是分散精力与后端的API较劲。此外,由于每个网络请求都会消耗电力,因此烦琐的API会更快地耗尽移动设备的电池电量。

缺乏封装导致前端开做出的代码修改影响后端
直接访问服务的移动应用程序的另一个弊端是缺少封装。随着应用程序的发展,服务开发人员有时会以破坏现有客户端的方式更改API。他们甚至可能将系统分解为服务。开发人员可以添加新服务并拆分或合并现有服务。但是,如果将有关服务的知识融入到移动应用程序中(导致客户端和服务端过度耦合),则可能很难更改服务的API。
与更新服务器端应用程序不同,推出移动应用程序的新版本需要数小时甚至数天。 而你又不能强迫不愿升级的用户。因此,将服务API暴露给移动设备的策略为这些API今后的变更带来了重大障碍。

服务可能选用对客户端不友好的进程间通信机制
在防火墙外部运营的客户端应用程序通常使用HTTP和WebSockets等协议。某些应用程序的服务可能使用gRPC,而其他服务可能使用AMQP消息传递协议。这些类型的协议在局域网内部运行良好,但可能不容易被移动客户端使用,有些甚至无法穿透防火墙。

8.1.2 其他类型客户端API的设计难题

略~

8.2 API Gateway模式

API Gateway是一种服务,它是外部世界进入应用程序的入口点。它负责请求路由
API组合和身份验证等各项功能。

8.2.1 什么是API Gateway模式

我们可以把 API Gateway视为一种服务,作为从防火墙外部进入应用程序的API请求的单一入口点。它类似于面同对象设计的外观(Facade)模式。与外观一样,API Gateway封装了应用程序的内部架构,并为其客户端提供API。它还可能具有其他职责,例如身份验证、流量监控和速率限制。图8-3显示了客户端、API Gateway和服务之间的关系。
API Gateway负责请求路由、API组合和协议转换。来自外部客户端的所有API请求
首先转到 API Gateway,后者将一些请求路由到相应的服务。 API Gateway使用API组合模式处理其他请求,调用多个服务并聚合结果。它还可以在客户端友好的协议(如HTTP和Web Sockets)与客户端不友好的协议之间进行转换。
在这里插入图片描述
请求路由
API Gateway通过将请求路由到相应的服务来实现一些API操作。当它收到请求时,API Gateway会查询路由映射,该映射指定将请求路由到哪个服务。例如,路由映射可以将HTTP方法和路径映射到服务的HTTP URL。此功能与NGINX等Web服务器提供的反向代理功能相同。

API组合
如图8-4所示,移动应用程序向API Gateway发出一个请求,该API Gateway从多个服务获取订单详细信息。
在这里插入图片描述
协议转换
它可能为外部客户端提供RESTful API,即使应用程序服务在内部使用混合协议,包括REST和gRPC。

API Gateway能够为每一个客户端提供他们专用的API
API Gateway可以提供单一的万能(one-size-fits-a,OSFA)API。单一API的问题在于不同的客户端通常具有不同的需求。例如,第三方应用程序可能需要Get Order Details API操作以返回完整的Order信息;而移动客户端只需要订单的部分数据即可。解决此问题的一种方法是为客户端提供在请求中指定服务器应返回哪些字段和相关对象的选项。这种方法适用于公共API,因为这些AP必须为大量的第三方应用程序提供服务,但它通常不会为客户端提供所需的细颗粒度控制。
更好的方法是API Gateway为每个客户端提供自己的API。例如,FTGO API Gateway可以为FTGO移动客户端提供专门为满足其要求而设计的API。它甚至可以为Android和iPhone移动应用程序提供不同的API。 API Gateway还将为第三方开发人员实现公共API。

实现边缘功能
边缘功能(Edge Function),顾名思义,是在应用程序边缘实现的请求、处理功能。应用程序可能实现的边缘功能包括:

  • 身份验证:验证发出请求的客户端身份。
  • 访问授权:验证客户端是否有权执行该特定操作。
  • 速率限制:限制特定客户或所有客户端每秒的请求数。
  • 缓存:缓存响应以减少对服务的请求数。
  • 指标收集:收集有关API使用情况的指标,以进行计费分析
  • 请求日志:记录请求历史。

应用程序中有三个不同的位置可以实现这些边缘功能。首先,你可以在后端服务中实现它们。这可能对某些功能有意义,例如缓存、指标收集和可能的访问授权。但是,如果应用程序在到达服务之前对边缘上的请求进行身份验证,则通常会更安全。
第二种选择是在 API Gateway上游的边缘服务中实现这些边缘功能。边缘服务是外部客户端的第一个联系点。它在将请求传递给 API Gateway之前对请求进行身份验证并完成其他边缘处理。
使用专用边缘服务的一个重要好处是它可以分隔问题。 API Gateway侧重于API路由和组合。另一个好处是它集中了关键边缘功能的职责,例如身份验证。当应用程序具有多种语言和框架编写的API Gateway时,这一点变得尤为重要。这种方法的弊端是由于额外的请求跳跃而增加了网络延迟。它还增加了应用程序的复杂性。
因此,使用第三个选项,在API Gateway中实现这些边缘功能(尤其是访问授权)通常就很方便。网络跳跃少一个,就可以改善延迟状况。需要改动的部分也较少,这就降低了复杂性。

API Gateway的架构
API Gateway具有分层的模块化架构。其架构由两层组成,如图8-5所示:API层和公共层。AP层由一个或多个独立的AP模块组成。每个API模块都为特定客户端实现API。公共层实现共享功能,包括边缘功能,如身份验证。
在这里插入图片描述
API Gateway的所有者模式
你必须回答的一个重要问题:谁负责API Gateway的开发及运维?这个问题有几种不同的答案。其一是由一个单独的团队负责API Gateway。弊端是它与SOA类似,SOA中企业服务总线(ESB)团队负责所有ESB开发。如果从事移动应用程序的开发人员需要访问特定服务,他们必须向API Gateway团队提交请求并等待他们公开API。组织中的这种集中式的瓶颈与微服务架构的理念背道而驰,微服务架构下我们更提倡松散耦合的自治团队。
Netflix推出的方法或许更好,此方法让客户端团队(包括移动、Web和公共API团
队)拥有与他们有关的AP模块并公开API。 API Gateway团队负责开发公共模块和API Gateway的运维。如图8-6所示,该所有权模型使团队可以控制属于他们自己的API。
在这里插入图片描述
使用后端前置模式
API Gateway的一个问题是它的职责不明确。多个团队为相同的代码库做贡献。API Gateway团队负责运维。虽然没有SOA ESB那么糟糕,但这种职责模糊与“如果你构建它,你就拥有它”的微服务架构哲学背道而驰。
解决方案是为每个客户端提供一个 API Gateway,即所谓的后端前置(Backends for frontends,BFF)模式。如图8-7所示,每个AP模块都成为自己的独立API Gateway,由对应的客户端团队开发和运维。
在这里插入图片描述
理论上,可以使用不同的技术栈开发不同的API Gateway。但这有可能需要通过复制代码来实现公共层的功能,例如实现边缘功能的代码。理想情况下,所有 API Gateway都使用相同的技术栈。公共层的功能是由API Gateway团队实现的共享库。
除了明确界定职责外,后端前置模式还有其他好处。API模块彼此隔离,从而提高了可靠性。一个行为不端的API不会轻易影响其他API。它还能提高可观测性,因为不同的API模块是不同的进程。后端前置模式的另一个好处是每个API都是可独立扩展的。后端前置模式还能减少启动时间,因为每个API Gateway都是一个更小、更简单的应用程序。

8.2.2 API Gateway模式的好处和弊端

API Gateway的好处
使用API Gateway的一个主要好处是它封装了应用程序的内部结构。客户端不必调用特定服务,而是与API Gateway通信。API Gateway为每个客户端提供特定于客户端的API,从而减少客户端和应用程序之间的往返次数。它还简化了客户端代码。
API Gateway的弊端
API Gateway模式也有一些弊端。它是另一个必须开发、部署和管理的高可用组件,但存在成为开发瓶颈的风险。开发人员必须更新API Gateway才能对外公开服务的API。更新API Gateway的过程尽可能轻量化是非常重要的。否则,开发人员将被迫排队等待更新 API Gateway。

以Netflix为例的API Gateway

略~

8.2.4 API Gateway的设计难题

性能和可扩展
影响性能和可扩展性的关键设计决策是API Gateway应该使用同步还是异步I/O。
在同步I/O模型中,每个网络连接由专用线程处理。然而,同步I/O的一个限制是操作系统线程是重量级的,因此API Gateway可拥有的的线程数量和并发连接数量存在上限。
另一种方法是使用异步(非阻塞)I/O。在此模式中,单个事件循环线程将I/O请求分派给事件处理程序。
非阻塞I/O更具可扩展性,因为它没有使用多个线程的开销。但弊端是它比基于异步回调的编程模型复杂得多,代码更难写、理解和调试。事件处理程序必须快速返回以避免阻塞事件循环流程。

使用响应式编程抽象
个人认为响应式编程(RP)并没有从根本上解决什么问题,只是采用了事件驱动的异步方式。
疑问:

  1. RP不也需要很多回调吗?同样会有调试困难和堆栈追踪困难的问题
  2. 采用并发模式同样可以使用多线程,这并不是RP的优势

处理局部故障
除了可扩展之外,API Gateway也必须可靠。实现可靠性的一种方法是在负载均衡器后面运行多个API Gateway实例。如果一个实例失败,负载均衡器会将请求路由到其他实例。
还有一种方法可以提高API Gateway的可靠性:API Gateway在调用服务时使用欧冠断路器模式。

8.3 实现一个API Gateway

略~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值