面向数据的架构( 二 )


我要说的是,随着微服务生态系统的发展,在规模上,它变得很容易受到如下问题的影响:

  1. 随着组件数量的增长(2),集成的复杂度也以 N^2 的级别增加 。
  2. 网络的形状变得很难用先验来推理;即,创建或维护测试环境或沙箱将需要进行大量的推理才能确保图中的任何组件都不具有外部依赖性
我的一些朋友也提出了一些他们在使用大规模面向服务的架构时遇到的问题:
随着 SOA 规模的增长,我发现的另一个问题是服务之间的循环依赖 。由于我们是单独发布各个服务的,很少从头开始构建整个系统,因此很容易引入循环并破坏 DAG 。
大规模 SOA 另一个值得注意的问题是:它们要求我们提前了解所有未来的客户工作流 。假设我们需要跨多个垂直领域来隔离单个工作流的数据,如果没有做到提前了解,那么我们要么会遇到性能问题,因为它将试图保证跨多个持久化存储的事务性;要么需要重新定义要用哪些垂直主服务器来复制(缓存,但实际上是持久化到数据库中的)数据 。
面向数据的架构在面向数据的架构( Data-Oriented Architecture,DOA)中,系统仍然围绕小型的、松耦合的标准来组织组件,就像在 SOA、微服务中一样 。但是 DOA 与微服务的区别主要体现在两个方面:
面向数据的架构

文章插图
 
  1. 组件通常是无状态的
DOA 没有对每个相关组件的数据存储进行组件化和联合,而是要求按照集中管理的全局模式来描述数据或状态层 。
  1. 最小化了组件之间的交互,并通过数据层的交互来替代
在我们的交易系统中,接收不同证券报价的组件在我们的数据存储中只是以一种规范的形式来发布价格 。系统可以通过查询数据层的价格来使用这些报价,而无需通过特定的 API 向某个特定的服务(或一组服务)请求价格 。
这里,集成的代价是线性的 。变更 DOA 模式意味着最多只需要更新 N 个组件,而不是它们之间互联的最大值 N^2 。
真正令人瞩目的地方在于不同的提供者可以填充独立的高级数据类型 。如果我们用一张表来替换一个服务,这并不会带来太大的简化 。但是当同一个通用数据类型有多个源时,这样做就会有很大的帮忙 。假设交易系统需要连接到多个市场,每个市场都会将客户的请求发布到询价(RFQ)表中,那么下游系统就可以查询这个表,而无需关心客户请求到底来自何处 。
组件通信类型由于在 DOA 中最小化了组件之间的交互,那么如何通过数据层的交互来代替当今 SOA 中组件之间的通信呢?
1. 数据生产和消费
设计 DOA 系统的主要方法是将组件组织成数据的生产者和消费者 。
如果我们能够在较高层次上将业务逻辑编写为一系列的 map、filter、reduce、flatMap 和其他一元(monadic)操作,那么我们就可以将 DOA 系统编写成一系列的组件,每个组件都查询或订阅其输入并产生其输出 。DOA 面临的挑战在于这些中间步骤是可见的、可查询的数据,这意味着需要对其进行良好的封装和表示,并且需要将其与特定的业务逻辑概念对应 。不过,它的优势在于系统的行为是可从外部观察、跟踪和审核的 。
在 SOA 交易系统中,从市场上接收订单的组件可能会使用 RPC 调用来确定如何对订单进行定价、报价或交易 。在 DOA 中,微服务接收来自市场的请求(通常是通过 SOA 的方式)并生成询价(RFQ),而其他生产者则生产定价数据,等等 。另一个微服务通过请求来查询 RFQ,该 RFQ 会结合它们的所有定价以输出报价、订单或任何其他需要响应的自定义数据 。
2. 触发动作和行为
有时,RPC 是组件之间通信的最简单方式 。虽然在设计良好的 DOA 系统中(3),其大部分组件间的通信采用的是生产者 / 消费者模式,但是我们可能仍需要采用直接的方式来让组件 X 告诉 Y 去做 Z 。
首先,必须考虑是否可以将 RPC 重组为事件(event)及其影响(effect) 。即,不是让组件 X 向发生事件 E 的组件 Y 发送 RPC 请求,而是询问 X 是否可以生成事件 E,并让组件 Y 通过消费这些事件来驱动响应?
这种方法,我称之为基于数据的事件(data-based events),它可以很好地逆转我们通常使用的组件通信方式 。它之所以如此强大是因为它使我们可以将“松耦合”这个术语提升到一个全新的层次 。系统不需要知道谁在消费它的事件(即,系统不是一个绝对需要知道他们在调用谁的 RPC 调用方),生产者也无需担心事件的来源,只需知道这些事件的业务逻辑语义即可 。


推荐阅读