面向数据的架构( 三 )


当然,存在一种简单的方法可以实现基于数据的事件,在这种方法中,每个事件都是以与 RPC 请求序列化版本 1:1 的对应关系持久化到自身表的数据库中 。在这种情况下,基于数据的事件根本不会使系统解耦合 。为了使基于数据的事件能正常运行,则要求将请求 / 响应转换成的持久化事件必须是有意义的业务逻辑结构 。
基于数据的事件有时可能不太合适 。例如,我们实际上要触发某个特定组件中的行为 。在这些情况下,可能仍然需要保留少量的实际组件到组件的 RPC 。
面向数据的架构的成功案例研究高集成问题空间我之所以一直以交易 / 财务软件为例,部分原因在于财务通常需要较大的集成表面积 。一个典型的允许较小客户进行交易的卖方公司,通常会与许多市场进行整合,以与客户进行互动,而许多流动资金提供者则会通过其获取价格并下订单 。在请求进入市场到对客户做出响应之间需要处理的业务逻辑是一个复杂的、多阶段的流程 。
在高集成问题空间中,单个服务可能需要了解许多其他服务 。为了避免 O(N^2) 的集成成本及具有高扇出比率的复杂独立服务的出现,围绕数据生产者和消费者的重新配置系统可以使集成更加简单 。假设要进行一个新的集成,不能编写 N 个新系统,也不能编写一个具有向 N 个其他系统进行复杂扇出的系统,那么集成过程可能需要编写一个适配器,该适配器以通用的 DOA 模式生产数据、消费最终的输出并以正确的线性格式来呈现 。
隐含地是,集成中出现了一种新的复杂性:需要考虑模式 。任何新的集成对我们的系统而言都应该是原生的,并且我们的模式应该能在不添加补充、修改和特殊用例的情况下扩展 。这本身就是一项艰巨的任务 。但是,当集成的数量足够多时,难度就会降低,而且往往是值得的 。
沙箱数据以及数据隔离的推理

面向数据的架构

文章插图
 
如果我们要手动建模或测试,则希望最好能在生产之外进行 。但是,某些 SOA 生态系统的架构方式通常意味着,想要知道某个服务所处的环境或特定环境是否完全独立并不那么容易 。
环境是指内部一致、连接一致的服务集合,通常或理想情况下,它应与生产的拓扑结构相同 。由于 SOA 服务通常是可独立寻址的,因此,环境一致性断言要求环境中的每个服务必须与环境中的其他服务就调用哪个地址能达成共识 。RPC、订阅模式(pubsub)和数据流不能从一个环境泄漏到另一个环境中 。
很明显,在 SOA 中有很多方法可以解决这个问题,比如转换到能为服务生成正确配置的服务注册中心 (4),或者,如果是通过 URI 访问服务,则隐藏直接的服务地址,以支持某个环境前缀下的不同路径(5) 。
然而,在 DOA 中,环境的概念要简单得多 。知道组件连接到哪个数据存储层就足以描述它所处的环境了 。由于所有组件都不在内部存储任何状态,因此数据是根据定义来隔离的 。组件仅通过数据存储进行通信,因此不存在将数据从一种环境泄漏到另一种环境的危险 。
面向数据架构比你想象的更接近现实如今,有很多类似于面向数据的架构的通用案例 。将所有(或大部分)数据保存在一个大型数据存储中的数据单体,在系统架构上就非常接近于 DOA 。
例如,知识图谱(Knowledge Graphs)就是一个广义的数据单体 。也就是说,它们通常不是很通用;许多与业务逻辑相关的状态可能会丢失 。
GraphQL 通常被用作标准化的数据存储层,就像数据单体一样 。GraphQL 是否能成功地成为 DOA 系统的后端,在很大程度上取决于系统对模式设计的选择:选择与业务逻辑概念相关的通用模式和表,而不是选择特定于该数据特定源的模式和表 。
权衡取舍这种架构也不是万能的 。当面向数据的架构消除了某些类型的问题时,就会出现新的问题:它要求设计人员需要认真考虑数据的所有权 。当多个写程序修改同一记录时,可能会很麻烦,它通常会鼓励系统仔细划分记录的写入所有权 。而且,由于组件间的 API 是在数据中编码的,因此必须采用需要谨慎考虑的共享全局模式 。
我记得 google 的 Protocol Buffers 文档,在讨论如何根据需要将模式中的字段标记为 required 时,它会警告说:“ Required Is Forever ” 。在 Broadway Technology,首席技术官(CTO)Joshua Walsky 曾对 DOA 模式说过类似的话:数据是永远存在(Data Is Forever) 。事实证明,出于与 Protobuf 警告类似的原因,在松耦合的分布式系统中,从表中删除列确实非常困难 。


推荐阅读