面向数据的架构

在软件架构中,有一种模式虽鲜为人知的,但值得引起更多的关注 。面向数据的架构(Data-Oriented Architecture)由 Rajive Joshi在RTI 的2007 年白皮书中首次提出,而维也纳大学(University of Vienna)的Christian Vorhemus 和Erich Schikuta 在2017 年的 iiWAS 论文中又再次对其进行了描述 。DOA 是对传统二分法的颠覆,它介于单体架构和微服务(Microservices)、面向服务的架构(Service-Oriented Architecture)之间 。单体架构由一个单体二进制文件(binary)和数据存储组成;微服务、面向服务的架构由许多小型的、分布式的、独立的二进制文件组成,并且每个二进制文件都有自己的数据存储 。在面向数据的架构中,单体数据存储是系统中状态的唯一来源,并由松耦合无状态的微服务对其进行操作 。

面向数据的架构

文章插图
 
我很幸运,我的前雇主也采用了这种非同寻常的架构选择 。它提醒我们,事情可以用不同的方式来做 。无论如何,面向数据的架构都不是银弹 。它有自己独特的成本和收益 。不过,我确实发现,许多大型公司和生态系统都陷入了某种种类型的瓶颈,而这种类型的瓶颈正是面向数据的架构能解决的 。
单体架构简介由于许多架构通常都是在与单体架构(Monolithic Architecture)进行对比的情况下定义的,因此,花一些时间来介绍单体架构是值得的 。毕竟,它是服务端软件开发传说中的自然状态 。
面向数据的架构

文章插图
 
在单体(monolithic)服务中,大部分服务端代码都在一个程序中,该程序与一个或多个数据库通信,并处理功能计算的各个方面 。假设有一个交易系统,它接收客户购买或出售某种证券的请求,为它们定价,并完成订单 。
在单体服务中,仍然可以将代码组件化并分离到各个模块中,但是程序中不同组件之间的 API 边界不是强制的 。程序中唯一经过严格定义的 API 通常是:**(a)UI 和服务端之间的 API(可以使用任何它们约定好的 REST/HTTP 协议);(b)服务端和数据存储之间的 API(可以使用任何它们约定好的查询语言);或(c)** 服务端与其外部依赖之间的 API 。
面向服务的架构和微服务另一方面,面向服务的架构(Service-oriented architectures,SOA)将单体程序分解成各个相互独立的、组件化的功能服务 。在我们的交易应用程序中,我们可能需要一个单独的服务来作为外部 API 接收请求并处理客户响应;第二个单独的系统来接收报价和其他市场相关的信息;第三个系统来跟踪订单和风险等 。这些服务之间的接口都是一个个形式化定义的 API 层 。服务之间通常通过 RPC 进行点对点的通信,此外,通过其他通信技术(如,消息传递和发布订阅模式)进行通信也是很常见的 。
面向数据的架构

文章插图
 
面向服务的架构允许根据需要对不同的服务进行独立(并行)开发和推理 。这些服务是松耦合的,这就意味着一个全新的服务现在可以重用其他服务了 。
由于 SOA 中的每个服务都定义了自己的 API,因此可以独立访问每个服务并与之交互 。开发人员如果要调试或模拟各个功能部分,可以分别调用各个组件,并且新流程可以重新组合这些单独的服务以启用新的行为 。
微服务是面向服务的架构的一种形式 。根据服务对象的不同,它们可能与 SOA 不同,因为这些服务本应特别小巧轻量,或者它们只是 SOA 的同义词 。
规模问题在 SOA 中,各个组件通过每个组件各自定义的特定 API 直接相互通信 。为了通信,每个组件都可以单独寻址(即,使用 IP 地址、服务地址或其他内部标识符来相互发送请求 / 消息) 。这意味着架构中的每个组件都需要了解它们的依赖关系,并且需要专门与它们的依赖进行集成 。
依赖于架构的拓扑结构,这可能意味着需要一个额外的组件来跟踪了解所有之前的组件 。此外,这可能还意味着要替换一个已经与其他 N 个组件通信的单个服务也是一种挑战:我们需要注意保留我们定义的任何点对点的 API,并确保有一个迁移计划,用于将每个组件从老的寻址服务移动到新的寻址服务上 。由于服务到服务的 API 是点对点的(ad-hoc)(1),这通常意味着组件之间的 RPC 可以是任意复杂的,这可能会增加将来 API 变更的影响面 。因为如果要对服务中被其他服务依赖的每个 API 进行变更都将是一项艰巨的任务 。


推荐阅读