DDD(领域驱动设计)—— 微服务架构
微服务架构模型有好多种,例如洋葱架构、六边形架构和 CQRS 架构等等。种架构模式虽然提出的时代和背景不同,但其核心理念都是为了设计出高内聚低耦合的架构,轻松实现架构演进。DDD 分层架构的出现,使架构边界变得越来越清晰,它在微服务架构模型中,占有非常重要的位置。
文章目录
0.前言
微服务架构模型有好多种,例如洋葱架构、六边形架构和 CQRS 架构等等。
种架构模式虽然提出的时代和背景不同,但其核心理念都是为了设计出 高内聚低耦合 的架构,轻松实现架构演进。
DDD 分层架构的出现,使架构边界变得越来越清晰,它在微服务架构模型中,占有非常重要的位置。
1.DDD 分层架构
分层架构是指在软件设计过程中按照既定的原则将不同的功能实现拆分到不同的层级进行实现的一种设计方式。每个层级有独立的职责,多个层次协同以提供完整功能。
按照 DDD 的分层模型,通常可以划分为:接入层、应用层、领域层、基础设施层。
1.1 传统四层架构

用户接口层
用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化测试和批处理脚本等等。
应用层
应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。
领域层
领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。
领域模型的业务逻辑主要是由实体和领域服务来实现的,其中实体会采用充血模型来实现所有与之相关的业务功能。其次,你要知道,实体和领域对象在实现业务逻辑上不是同级的,当领域中的某些功能,单一实体(或者值对象)不能实现时,领域服务就会出马,它可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
基础层
基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能是提供数据库持久化。
1.2 改良四层架构
传统四层分层架构的基础设施层位于底层,持久化和消息机制便位于该层。可将基础设施层中所有组件看作应用程序的低层服务,较高层与该层发生耦合以复用基础设施。即便如此,依然应避免核心的领域模型对象与基础设施层直接耦合。
传统架构的缺陷:就是将基础设施层放在最底层存在缺点,比如此时领域层中的一些技术实现令人头疼:违背分层架构的基本原则,难以编写测试用例等。
因此可以通过依赖倒置原则实现各层对基础资源的解耦。
依赖倒置原则:具体依赖于抽象,而不是抽象依赖于具体。
低层服务(如基础设施层)应依赖高层组件(比如用户接口层、应用层和领域层)所提供接口。高层定义好仓库的接口,基础设施层实现各层定义好的仓库接口。

1.3 DDD 分层架构的原则
分层架构的一个重要原则是每层只能与位于其下方的层发生耦合。
分层架构根据每层耦合的紧密程度分为两种:
严格分层架构: 某层只能与位于其直接下方的层发生耦合。
松散分层架构: 则允许某层与它的任意下方层发生耦合。
优化后的 DDD 分层架构模型就属于严格分层架构,任何层只能对位于其直接下方的层产生依赖。而传统的 DDD 分层架构则属于松散分层架构,它允许某层与其任意下方的层发生依赖。
那我们怎么选呢?综合我的经验,为了服务的可管理,我建议你采用严格分层架构。
在严格分层架构中,领域服务只能被应用服务调用,而应用服务只能被用户接口层调用,服务是逐层对外封装或组合的,依赖关系清晰。而在松散分层架构中,领域服务可以同时被应用层或用户接口层调用,服务的依赖关系比较复杂且难管理,甚至容易使核心业务逻辑外泄。
试想下,如果领域层中的某个服务发生了重大变更,那该如何通知所有调用方同步调整和升级呢?但在严格分层架构中,你只需要逐层通知上层服务就可以了。
2.整洁架构
整洁架构又名 洋葱架构 。
为什么叫它洋葱架构?看看下面这张图你就明白了。整洁架构的层就像洋葱片一样,它体现了分层的设计思想。
在整洁架构里,同心圆代表应用软件的不同部分,从里到外依次是领域模型、领域服务、应用服务和最外围容易变化的内容,比如用户界面和基础设施。
整洁架构最主要的原则是依赖原则,它定义了各层的依赖关系,越往里依赖越低,代码级别越高,越是核心能力 。外圆代码依赖只能指向内圆,内圆不需要知道外圆的任何情况。

在洋葱架构中,各层的职能是这样划分的:
-
领域模型实现领域内核心业务逻辑,它封装了企业级的业务规则。领域模型的主体是实体,一个实体可以是一个带方法的对象,也可以是一个数据结构和方法集合。
-
领域服务实现涉及多个实体的复杂业务逻辑。
-
应用服务实现与用户操作相关的服务组合与编排,它包含了应用特有的业务流程规则,封装和实现了系统所有用例。
-
最外层主要提供适配的能力,适配能力分为主动适配和被动适配。主动适配主要实现外部用户、网页、批处理和自动化测试等对内层业务逻辑访问适配。被动适配主要是实现核心业务逻辑对基础资源访问的适配,比如数据库、缓存、文件系统和消息中间件等。
-
红圈内的领域模型、领域服务和应用服务一起组成软件核心业务能力。
3.六边形架构
六边形架构又名端口适配器架构 。
追溯微服务架构的渊源,一般都会涉及到六边形架构。
六边形架构的核心理念是:应用通过端口与外部进行交互 。我想这也是微服务架构下 API 网关盛行的主要原因吧。
下图的红圈内的核心业务逻辑(应用程序和领域模型)与外部资源(包括 APP、Web 应用以及数据库资源等)完全隔离,仅通过适配器进行交互。它解决了业务逻辑与用户界面的代码交错问题,很好地实现了前后端分离。六边形架构各层的依赖关系与整洁架构一样,都是由外向内依赖。

六边形架构将系统分为内六边形和外六边形两层,这两层的职能划分如下:
-
红圈内的六边形实现应用的核心业务逻辑;
-
外六边形完成外部应用、驱动和基础资源等的交互和访问,对前端应用以 API 主动适配的方式提供服务,对基础资源以依赖倒置被动适配的方式实现资源访问。
六边形架构的一个端口可能对应多个外部系统,不同的外部系统也可能会使用不同的适配器,由适配器负责协议转换。这就使得应用程序能够以一致的方式被用户、程序、自动化测试和批处理脚本使用。
4.三种微服务架构对比
CQRS 全称为 Command Query Responsibility Segregation,顾名思义是读写分离,就是将 command 与 query 分离的一种模式。
Command 命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。
Query 查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。
Command 与 Query 对应的数据源可以公用一种数据源,也可以互相独立,即更新操作在一个数据源,而查询操作在另一个数据源上。
CQRS三种模式:
(1)共享模型/共享存储:读写共用一种领域模型,读写模型共用一种。
(2)分离模型/共享存储:读写分别用不同的领域模型,读操作使用读领域模型,写操作使用写领域模型。
(3)分离模型/分离存储:也叫做事件源 (Event source) CQRS,使用领域事件保证读写数据的一致性。也就是当 Command 系统完成数据更新的操作后,会通过领域事件的方式通知 Query 系统。Query 系统在接受到事件之后更新自己的数据源。
CQRS(读写操作分别使用不同的数据库)。

软件中的读模型和写模型是很不一样的,我们通常所讲的业务逻辑更多的时候是在写操作过程中需要关注的东西,而读操作更多关注的是如何向客户方返回恰当的数据展现。
因此在 DDD 的写操作中,我们需要严格地按照“应用服务 -> 聚合根 -> 资源库”的结构进行编码,而在读操作中,采用与写操作相同的结构有时不但得不到好处,反而使整个过程变得冗繁,还多了模型转换,影响效率。本来读操作就需要速度快,性能高。
因此 CQRS 实战中的读操作是基于数据模型,应用层提供一个单独的用于读的仓库,然后绕过聚合根和资源库,也就是绕过领域层,在应用层直接返回数据。而写操作是基于领域模型,通过应用服务->领域服务->资源库的结构进行编码。
5.微服务架构对比
虽然 DDD 分层架构、整洁架构、六边形架构的架构模型表现形式不一样,但你不要被它们的表象所迷惑,这三种架构模型的设计思想正是微服务架构高内聚低耦合原则的完美体现,而它们身上闪耀的正是以领域模型为中心的设计思想。

我们看下上面这张图,结合图示对这三种架构模型做一个分析。
请你重点关注图中的红色线框,它们是非常重要的分界线,这三种架构里面都有,它的作用就是将核心业务逻辑与外部应用、基础资源进行隔离。
红色框内部主要实现核心业务逻辑,但核心业务逻辑也是有差异的,有的业务逻辑属于领域模型的能力,有的则属于面向用户的用例和流程编排能力。按照这种功能的差异,我们在这三种架构中划分了应用层和领域层,来承担不同的业务逻辑。
领域层实现面向领域模型,实现领域模型的核心业务逻辑,属于原子模型,它需要保持领域模型和业务逻辑的稳定,对外提供稳定的细粒度的领域服务,所以它处于架构的核心位置。
应用层实现面向用户操作相关的用例和流程,对外提供粗粒度的 API 服务。它就像一个齿轮一样进行前台应用和领域层的适配,接收前台需求,随时做出响应和调整,尽量避免将前台需求传导到领域层。应用层作为配速齿轮则位于前台应用和领域层之间。
可以说,这三种架构都考虑了前端需求的变与领域模型的不变 。需求变幻无穷,但变化总是有矩可循的,用户体验、操作习惯、市场环境以及管理流程的变化,往往会导致界面逻辑和流程的多变。但总体来说,不管前端如何变化,在企业没有大的变革的情况下,核心领域逻辑基本不会大变,所以领域模型相对稳定,而用例和流程则会随着外部应用需求而随时调整。把握好这个规律,我们就知道该如何设计应用层和领域层了。
参考文献
更多推荐
所有评论(0)