DDD六边形架构架构

分层架构被认为是所有架构的始祖.它支持n层架构系统,因此被官方的应用于web企业级应用和桌面应用.这种架构中,我们将一个应用程序或者系统分为不同的层次

六边形架构

六边形架构又称为端口-适配器,这个名字更容器理解。六边形架构将系统分为内部(内部六边形)和外部,内部代表了应用的业务逻辑,外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通信,端口代表了一定协议,以API呈现。一个端口可能对应多个外部系统,不同的外部系统需要使用不同的适配器,适配器负责对协议进行转换。这样就使得应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,并且,可以在与实际运行的设备和数据库相隔离的情况下开发和测试。

六边形架构的核心理念是:应用是通过端口与外部进行交互的。

在下图的六边形架构中,红圈内的核心业务逻辑(应用程序和领域模型)与外部资源(包括 APP、Web 应用以及数据库资源等)完全隔离,仅通过适配器进行交互。它解决了业务逻辑与用户界面的代码交错问题,很好地实现了前后端分离。六边形架构各层的依赖关系是由外向内依赖的。

六边形架构将系统分为内六边形和外六边形两层,这两层的职能划分如下:

红圈内的六边形实现应用的核心业务逻辑;
外六边形完成外部应用、驱动和基础资源等的交互和访问,对前端应用以 API 主动适配的方式提供服务,对基础资源以依赖倒置被动适配的方式实现资源访问。
六边形架构的一个端口可能对应多个外部系统,不同的外部系统也可能会使用不同的适配器,由适配器负责协议转换。这就使得应用程序能够以一致的方式被用户、程序、自动化测试和批处理脚本使用。

CQRS

CQRS,作为一种战术办法,是实现DDD建模领域的最佳途径之一。事实上,它就是因为这个目标而诞生在这个世界上。

CQRS本身只是一个读写分离的架构思想,全称是:Command Query Responsibility Segregation,即命令查询职责分离,表示在架构层面,将一个系统分为写入(命令)和查询两部分。一个命令表示一种意图,表示命令系统做什么修改,命令的执行结果通常不需要返回;一个查询表示向系统查询数据并返回。

CQRS架构中,另外一个重要的概念就是事件,事件表示命令操作领域中的聚合根,然后聚合根的状态发生变化后产生的事件。
前提

由于CQRS架构的一致性模型为最终一致性,所以,你的系统要接受查询到的数据可能不是最新的,而是有几个毫秒的延迟。之所以会有这个前提,是因为CQRS架构考虑到,作为一个多用户同时访问的互联网应用,当在高并发修改数据的情况下,比如秒杀、12306购票等场景,用户UI上看到的数据总是旧的。比如你秒杀时提交订单前看到库存还大于0,但是当你提交订单时,系统提示你宝贝卖完了。这个就说明,在这种高并发修改同一资源的情况下,任何人看到的数据总是Stale的,即旧的。

CQRS作为一种架构思想,可以有多种实现方式:

  • 最常见的CQRS架构是数据库的读写分离
  • 系统底层存储不分离,但是上层逻辑代码分离
  • 系统底层存储分离,C 端采用 Event Sourcing 的技术,在 EventStore 中存储事件;Q 端存储对象的最新状态,用于提供查询支持;

Event Sourcing - 事件溯源:

  • 不保存对象的最新状态,而是保存对象产生的所有事件;
  • 通过事件溯源(Event Sourcing, ES)得到对象最新状态。

当我们的应用的写模型和读模型差别比较大时;

当我们希望实践DDD时;因为CQRS架构可以让我们实现领域模型不受任何ORM框架带来的对象和数据库的阻抗失衡的影响;

当我们希望对系统的查询性能和写入性能分开进行优化时,尤其是读/写比非常高的系统,CQ分离是必须的;

当我们希望我们的系统同时满足高并发的写、高并发的读的时候;因为CQRS架构可以做到C端最大化的写,Q端非常方便的提供可扩展的读模型。

这里我主要分享的CQRS架构是上面第3种实现方式,也就是上图所画的架构。在我心目中,只有第三种才是真正意义上的CQRS架构。

CQRS架构的数据流

客户端如(MVC Controller)发送命令通知系统做修改:

发送命令到分布式MQ;
然后命令的订阅者处理命令;
订阅者内部根据不同的命令调用不同的 Command Handler 进行处理;
Command Handler 内部根据命令所指定的聚合根 ID 从 In-Memory 内存中直接获取聚合根对象的引用,然后操作聚合根对象;
聚合根对象状态发生变化并产生事件;
框架负责自动持久化事件到 Event Storage(简称EventStore);
框架负责将事件发布到 Event MQ;
Event 订阅者订阅事件,然后调用对应的 Event Handler 进行处理,如更新 Data Storage(保存了聚合根的最新状态,通常叫读库,ReadDB)。

Q端的查询的执行流程

客户端如(MVC Controller)发出查询请求系统返回数据:

调用轻薄的 Query Service,传如 Query DTO;
Query Service 从读库进行查询并返回结果。
读库可以有很多种,依据我们的业务场景来选择:比如关系型DB、分布式缓存等NoSQL、搜索引擎,etc。

Last modification:August 2, 2023
如果觉得我的文章对你有用,请随意赞赏