Dawn's Blogs

分享技术 记录成长

0%

微服务架构设计模式 (7) 微服务中的查询

在微服务中,查询通常是复杂的,因为所需要的数据通常分散在多个服务之中。微服务的查询通常分为两种不同的模式:

  • API 组合模式:最简单的方法,应该首先考虑和使用。让一个统一的服务或者应用网关调用多个服务,然后将查询到的结果进行组合并返回。
  • 命令查询职责隔离(CQRS,Command-Query Responsibility Segregation)模式:比 API 组合模式更加复杂,也更强大。维护一个或者多个数据视图,目的仅仅是查询。

API 组合模式

API 组合模式就是访问多个服务进行查询,将多个服务的查询结果组合起来并返回给用户。这种模式有两种参与者:

  • API组合器:用于查询多个服务的数据,并负责将结果组合起来。
  • 数据提供方服务:拥有部分数据的服务提供者。

image-20230524205406597

设计缺陷

使用 API 组合模式,必须解决的问题:

  • 由谁来担任 API 组合器。
  • 如何编写有效的聚合逻辑。
  • 可用性降低。
  • 结果的不一致性。

由谁来担任 API 组合器

API 组合器负责发出各个子查询,并且将查询聚合起来,所以决定由谁来担任 API 组合器非常重要。通常来说,可以有三个选择:客户端担任、API 网关担任、API 组合器作为独立的服务。

  • 客户端:这样的查询效率是最低的,因为客户端到服务之间是互联网(带宽低,时延高),而服务之间是局域网(带宽高,时延低)。

image-20230524205908696

  • API 网关:

image-20230524210118071

  • 作为独立的服务:

image-20230524210136109

有效的聚合逻辑

在请求数据提供方服务时,应该尽量并行的调用每一个数据提供方服务。当然了,不排除有些情况下提供方服务有依赖关系,此时就必须顺序的调用。

可用性降低

因为请求了多个服务,这必然会导致可用性的降低。在请求的多个服务中,如果其中一个服务请求失败了,那么整个查询就可以看作是失败。在这种情况下,有两种方法可以提高可用性:

  • 在子查询失败时,返回先前已经缓存的数据。
  • 让 API 组合器返回不完整的数据

结果的不一致性

因为是分布式请求多个服务,事务的 ACID 特性无法保证,也就无法保证查询的结果的一致性。API 组合器需要检测到查询结果的不一致性(但这可能是无法实现的,所以可能会把不一致的数据返回给客户端)。

CQRS 模式

命令查询指责隔离(Command- Query Responsibility Segregation,CQRS)顾名思义,涉及到命令查询隔离。命令端就是增删改操作,查询端就是查询操作。CQRS 就是利用事务在本服务维护多个外部服务的数据只读视图,从而实现来自多个服务的数据查询。

CQRS 的核心思想是将这两类不同的操作进行分离,并且命令端和查询端维护的是不同的两个数据库。

命令端完成数据更新的操作后,会以发布领域事件的方式通知查询端。查询端在收到领域事件后,更新自己的数据库。

CQRS 的好处就是在查询端可以使用与查询需求更为贴近的数据存储引擎(高效的查询),如 NoSQL。比较常见的情况是,命令端使用传统的关系型数据库,但是对于那些比较特殊的查询则使用专门的数据存储。例如在一些基于关键字进行全文检索的场景可以将数据存储换为 ElasticSearch 这样的检索引擎,在性能方面会得到非常明显的提升。

带来的问题

实时性

因为在进行增删改后,会以事件的方式通知查询端更新数据视图。那么这就存在着一定的时间差,如果业务要求很高的实时性,CQRS 就不适合了。

复杂性

因为查询端需要维护自己的数据视图,所以就必须设计针对查询的数据库模型。同时,因为引入了查询端服务,所以导致的更加复杂的架构