《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

导读

  • 在微服务中查询数据的挑战
  • 何时以及如何使用API组合模式实现查询
  • 何时以及如何使用CQRS模式实现查询

在微服务中编写查询非常具有挑战性,查询通常需要检索分数在多个服务所拥有的数据库中的数据,但不能使用传统的分布式查询处理机制,即使技术可行,也会打破服务之间的隔离和封装。

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

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

使用API组合模式进行查询

findOrder()查询操作:从多个服务获取数据的查询方法

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

什么是API组合模式

API组合模式:通过查询每个服务的API并组合结果,实现从多个服务检索数据的查询

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

其有两种类型的参与者:

  • API组合器:它通过查询数据提供方的服务来实现查询操作
  • 数据提供方服务:拥有查询返回的部分数据的服务

是否可以使用此模式实现特定查询操作取决于几个因素,包括数据的分区方式、拥有数据的服务公开的API的功能,以及服务使用数据库的功能。

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

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

由谁来担任API组合器的角色

可选:客户端(web等)、api gateway(简单逻辑)、独立的服务(复杂逻辑)

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

应该使用响应式编程模型

  • 有时API聚合器需要一个提供方服务的结果才能调用另一个服务;在这种情况下,它需要按顺序调用一部分提供方服务
  • 应该使用基于Java CompletableFuture、RxJava可观测或其他类似的响应式设计(详情见《第8章 API Gateway模式》)

API组合模式的优缺点

优点:实现查询操作简单直观

缺点:

  • 增加了额外的开销:涉及多个请求和数据库查询,需要更多的计算和网络资源
  • 带来可用性降低的风险:操作的可用性随着所涉及的服务数量而下降,解决办法:在提供方不可用时,返回先前缓存的数据;或者让API组合器返回不完整的数据
  • 缺乏事务数据一致性

使用CQRS模式

命令查询职责隔离(CQRS)模式:使用事件来维护从多个服务复制数据的只读视图,借此实现对来自多个服务的数据的查询。

CORS是这中架构的概况,通常维护一个或者多个试图数据库,实现一个或者多个应用程序的查询。

为什么要使用CQRS

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

什么是CQRS

CORS将持久化数据模型和使用数据的模块分为两部分:命令端和查询端。命令端模块和数据模型实现创建、更新和删除操作(CUD),查询端模块和数据模型实现查询(R)。查询端通过订阅命令端发布的事件,时期数据模型与命令端数据模型保持同步。

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

CQRS和查询专用服务

查询端服务订阅多个服务发布的事件,这种视图(和数据)不属于任何特定服务,因此将其实现为独立的服务是合理的。

查询服务也是实现复制单个服务所拥有的数据的好方案,可以把查询的实现和服务的功能分隔开。

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

CQRS的优缺点

优点

  • 在微服务架构中高效地实现查询
  • 高效地实现多种不同的查询类型
  • 在基于事件溯源技术的应用程序中实现查询
  • 更进一步地实现问题隔离

缺点

  • 更加复杂的架构:开发人员必须编写更新和查询视图的查询端服务
  • 处理数据复制导致的延迟

设计CQRS视图

CQRS视图模块包括由一个或者多个查询操作组成的API,通过订阅由一个或者多个服务发布的事件来更新它的数据库视图,从而实现这些查询操作。

《微服务架构设计模式》读书笔记(七):在微服务架构中实现查询

视图模块包含视图数据库和三个子模块:

  • 数据访问模块实现数据库访问逻辑
  • 事件处理程序模块订阅事件,并使用数据访问模块更新数据库
  • 查询API模块负责实现查询API,并使用数据访问模块查询数据库

选择视图存储库

SQL数据库

  • 在主流硬件上运行的现代关系型数据库具有出色的性能
  • SQL数据库通常具有非关系特征的扩展,如地理空间数据类型和查询
  • CQRS视图可能需要使用SQL数据库才能支持报表引擎

NoSQL

  • CQRS视图受益于NoSQL数据库更丰富的数据模型和性能,
  • 不受NoSQL数据库事务处理能力的限制

支持更新操作:

  • 通常使用其主键更新或删除视图数据库中的记录
  • 有时需要使用类似外键的做法来更新或删除记录

如果你需要

使用

例如

基于主键的JSON对象查找

文档型数据库,例如MongoDB或者DynamoDB,或者Redis键值存储数据库

通过维护包含每个客户的MongoDB文档来实现订单历史记录

基于查询的JSON对象查找

文档型数据库,例如MongoDB或者DynamoDB

使用MongoDB或DynamoDB实现客户视图

文本查询

文本搜索引擎,例如Elasticsearch

通过维护每个订单的Elasticsearch文旦来实现订单的文本搜索

图查询

图数据库,例如Neo4j

通过维护客户、订单和其他数据图表来实现欺诈检测

传统的SQL报表/BI

关系型数据库

标准业务报告和分析

设计数据库访问模块

事件处理程序和查询API模块不直接访问数据库存储区。相反,它们使用数据访问模块,该模块由数据访问对象(DAO)及其辅助类组成。

  • 处理并发更新确保更新幂等

当视图订阅由多个聚合类型发布的事件时,多个事件处理程序可能同时更新同一记录,DAO必须能够正确处理这种情况。

  • 幂等事件处理程序

为了确保可靠,事件处理程序必须记录事件ID并以原子化的方式更新数据存储区,如何执行此操作取决于数据库的类型。

事件处理程序不需要记录每个事件的ID,每个记录仅需要存储从给定聚合实例接收的max(eventId)。

  • 让客户端应用程序采用最终一致性的视图

执行更新命令后执行查询命令可能看不到更新前的数据 ,视图是最终一致的。

为了检测不一致,命令端操作可以将包含已发布事件和ID标记返回给客户端,然后客户端将事件有关的ID传递给查询操作,如果该事件尚未更新视图,则返回查询错误。视图模块可以使用重复事件检测机制来实现这样的功能。

添加和更新CQRS视图

添加和更新CQRS视图在概念上很简单,即:创建新视图:开发查询端模块、设置数据存储区并部署服务。查询端模块的事件处理程序处理所有事件,最终视图将是最新的。更新现有视图:更改事件处理程序并从头开始重构视图。

但在实际中会产生一些问题,消息代理无法无限期存储信息。如:RabbitMQ会在消费者处理完消息后删除该消息,Apache Kafka可在配置的保留期内保留消息,但也不会无限期存储事件。

解决办法:使用归档事件构建CQRS视图,使用可扩展的大数据技术(如Apache Spark)实现。

处理所有事件所需的时间和资源随着时间推移而不断增长。

解决办法:增量式构建CQRS视图,使用两步增量算法。第一步基于先前的快照和自创建快照以来发生的事件,定期计算每个聚合实例的快照。第二步使用快照和任何后续事件创建视图。

本章小结

  • 实现从多个服务检索数据的查询具有挑战性,因为每个服务的数据都是私有的。
  • 有两种方法可以实现这些类型的查询:API组合模式和命令查询职责隔离(CQRS)模式。
  • 从多个服务获取数据的API组合模式是实现查询的最简单方法,应尽可能使用。
  • API组合模式的局限性是某些复杂查询需要大型数据集的低效内存连接。
  • 使用视图数据库实现查询的CQRS模式功能更强大,但实现起来更复杂。
  • CQRS视图模块必须处理并发更新以及检测和丢弃重复事件。
  • CQRS有助于改善问题隔离,服务不必为自己拥有的数据实现查询功能。
  • 客户必须处理CQRS视图的最终一致性。
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章