你是否还在为微服务应该拆多小而争论不休?到底如何能力设计出收放自如的微服务?怎样才能保障业务畛域模型与代码模型的一致性?或者本文能帮你找到答案。
本文是基于 DDD 的微服务设计和开发实战篇,通过借鉴畛域驱动设计思维,领导微服务项目团队进行设计和开发(实践篇详见《当中台遇上 DDD,咱们该如何设计微服务?》)。本文包含三局部内容:第一局部讲述畛域驱动设计基本知识,包含:分层架构、服务视图、数据视图和畛域事件公布和订阅等;第二局部讲述微服务设计办法、过程、模板、代码目录、设计准则等内容;最初局部以一个我的项目为例讲述基于 DDD 的微服务设计过程。
一、指标
本文采纳 DDD(畛域驱动设计)作为微服务设计指导思想,通过事件风暴建设畛域模型,正当划分畛域逻辑和物理边界,建设畛域对象及服务矩阵和服务架构图,定义合乎 DDD 分层架构思维的代码构造模型,保障业务模型与代码模型的一致性。通过上述设计思维、办法和过程,领导团队依照 DDD 设计思维实现微服务设计和开发。
通过畛域模型和 DDD 的分层思维,屏蔽内部变动对畛域逻辑的影响,确保交付的软件产品是边界清晰的微服务,而不是外部边界仍然凌乱的小单体。在需要和设计变动时,能够轻松的实现微服务的开发、拆分和组合,确保微服务不易受内部变动的影响,并稳固运行。
二、适用范围
本文实用于依照 DDD 设计办法进行微服务设计和开发的我的项目及相干人员。
以下状况不实用:
- “咱们的指标是按期盖出一栋大楼来,不要跟我提什么办法,有这啰嗦的工夫,还不如放松点工夫搬砖,把楼给我快点盖好!”。
- “我的工作就是让软件运行起来,能工作所有就 OK!我不须要那么多束缚,什么设计办法、扩展性、业务变动、畛域模型、响应能力与我无关。别耽搁工期啦!先上线再说!”。
- “好的软件是本人演进进去的,咱们不须要设计!”。
哈哈,开个玩笑啦!其实设计不会花太多工夫的!
不耽搁大家工夫了,言归正传。
三、DDD 分层架构视图
DDD 分层架构包含:展示层、应用层、畛域层和根底层。
DDD 分层架构各层职能如下:
展示层
展示层负责向用户显示信息和解释用户指令。
应用层
应用层是很薄的一层,次要面向用户用例操作,协调和指挥畛域对象来实现业务逻辑。应用层也是与其余零碎的应用层进行交互的必要渠道。应用层服务尽量简略,它不蕴含业务规定或常识,只为下一层的畛域对象协调工作,使它们相互合作。应用层还可进行平安认证、权限校验、分布式和长久化事务管制或向内部利用发送基于事件的音讯等。
畛域层
畛域层是软件的外围所在,它实现全副业务逻辑并且通过各种校验伎俩保障业务正确性。它蕴含业务所波及的畛域对象(实体、值对象)、畛域服务以及它们之间的关系。它负责表白业务概念、业务状态以及业务规定,具体表现形式就是畛域模型。
根底层
根底层为各层提供通用的技术能力,包含:为应用层传递音讯、提供 API 治理,为畛域层提供数据库长久化机制等。它还能通过技术框架来反对各层之间的交互。
四、服务视图
微服务内的服务视图
微服务内有 Facade 接口、应用服务、畛域服务和根底服务,各层服务协同配合,为内部提供服务。
1、接口服务
接口服务位于用户接口层,用于解决用户发送的 Restful 申请和解析用户输出的配置文件等,并将信息传递给应用层。
2、应用服务
应用服务位于应用层。用来表述利用和用户行为,负责服务的组合、编排和转发,负责解决业务用例的执行程序以及后果的拼装。
应用层的服务包含应用服务和畛域事件相干服务。
应用服务可对微服务内的畛域服务以及微服务外的应用服务进行组合和编排,或者对根底层如文件、缓存等数据间接操作造成应用服务,对外提供粗粒度的服务。
畛域事件服务包含两类:畛域事件的公布和订阅。通过事件总线和音讯队列实现异步数据传输,实现微服务之间的解耦。
3、畛域服务
畛域服务位于畛域层,为实现畛域中跨实体或值对象的操作转换而封装的服务,畛域服务以与实体和值对象雷同的形式参加施行过程。
畛域服务对同一个实体的一个或多个办法进行组合和封装,或对多个不同实体的操作进行组合或编排,对外裸露成畛域服务。畛域服务封装了外围的业务逻辑。实体本身的行为在实体类外部实现,向上封装成畛域服务裸露。
为暗藏畛域层的业务逻辑实现,所有畛域办法和服务等均须通过畛域服务对外裸露。
为实现微服务内聚合之间的解耦,原则上禁止跨聚合的畛域服务调用和跨聚合的数据互相关联。
4、根底服务
根底服务位于根底层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,升高内部资源变动对业务逻辑的影响。
根底服务次要为仓储服务,通过依赖反转的形式为各层提供根底资源服务,畛域服务和应用服务调用仓储服务接口,利用仓储实现长久化数据对象或间接拜访根底资源。
微服务外的服务视图
1. 前端利用与微服务
微服务中的应用服务通过用户接口层组装和数据转换后,公布在 API 网关,为前端利用提供数据展现服务。
2. 微服务与内部利用
跨微服务数据处理时,对实时性要求高的场景,可抉择间接调用应用服务的形式(新增和批改类型操作需关注事务一致性)。对实时性要求不高的场景,可抉择异步化的畛域事件驱动机制(最终数据一致性)。
五、数据视图
DDD 分层架构中数据对象转换的过程如下图。
数据视图应用服务通过数据传输对象(DTO)实现内部数据交换。畛域层通过畛域对象(DO)作为畛域实体和值对象的数据和行为载体。根底层利用长久化对象(PO)实现数据库的替换。
DTO 与 VO 通过 Restful 协定实现 JSON 格局和对象转换。
前端利用与应用层之间 DTO 与 DO 的转换产生在用户接口层。如微服务内应用服务需调用内部微服务的应用服务,则 DTO 的组装和 DTO 与 DO 的转换产生在应用层。
畛域层 DO 与 PO 的转换产生在根底层。
六、畛域事件和事件总线
畛域事件是畛域模型中十分重要的局部,用来示意畛域中产生的事件。一个畛域事件将导致进一步的业务操作,有助于造成残缺的业务闭环。畛域事件次要用于解耦微服务,各个微服务之间不再是强一致性,而是基于事件的最终一致性。
微服务内的畛域事件
微服务内的畛域事件能够通过事件总线或利用应用服务实现不同聚合之间的业务协同。当微服务内产生畛域事件时,因为大部分事件的集成产生在同一个线程内,不肯定须要引入消息中间件。但一个事件如果同时更新多个聚合数据,依照 DDD“一个事务只更新一个聚合根”的准则,能够思考引入消息中间件,通过异步化的形式,对微服务内不同的聚合根采纳不同的事务。
微服务之间的畛域事件
微服务之间的数据交互方式通常有两种:应用服务调用和畛域事件驱动机制。
畛域事件驱动机制更多的用于不同微服务之间的集成,实现微服务之间的解耦。事件库(表)能够用于微服务之间的数据对账,在利用、网络等呈现问题后,能够实现源和目标端的数据比对,在数据临时不统一的状况下仍可依据这些数据实现后续业务解决流程,保障微服务之间数据的最终一致性。
应用服务调用形式通常利用于实时性要求高的业务场景,但一旦波及到跨微服务的数据批改,将会减少分布式事务管制老本,影响零碎性能,微服务之间的耦合度也会变高。
事件总线
事件总线位于根底层,为应用层和畛域层服务提供事件音讯接管和散发等服务。其大抵流程如下:
1、服务触发并公布事件。
2、事件总线事件散发。
- 如果是微服务内的订阅者(微服务内的其它聚合),则间接散发到指定订阅者。
- 如果是微服务外的订阅者,则事件音讯先保留到事件库(表)并异步发送到消息中间件。
- 如果同时存在微服务内和外订阅者,则散发到外部订阅者,并将事件音讯保留到事件库(表)并异步发送到消息中间件。为了保障事务的一致性,事件表能够共享业务数据库。也能够采纳多个微服务共享事件库的形式。当业务操作和事件公布操作跨数据库时,须保障业务操作和事件公布操作数据的强一致性。
事件数据长久化
事件数据的长久化存储能够有两种计划,在我的项目施行过程中依据具体场景抉择最佳计划。
- 事件数据保留到微服务所在业务数据库的事件表中,利用本地事务保障业务操作和事件公布操作的强一致性。
- 事件数据保留到多个微服务共享的事件库中。须要留神的一点是:这时业务操作和事件公布操作会跨数据库操作,须保障事务的强一致性(如分布式事务机制)。
事件数据的长久化能够保证数据的完整性,基于这些数据能够实现跨微服务数据的一致性比对。
七、微服务设计办法
事件风暴
本阶段次要实现畛域模型设计。
基于 DDD 的微服务设计通常采纳事件风暴办法。通过事件风暴实现畛域模型设计,划分出微服务逻辑边界和物理边界,定义畛域模型中的畛域对象,领导微服务设计和开发。事件风暴通常包含产品愿景、场景剖析、领域建模、微服务设计和拆分等过程。本文不对事件风暴具体办法做深刻形容,如感兴趣可查阅相干材料。
1、产品愿景
产品愿景是对产品的顶层价值设计,对产品指标用户、外围价值、差异化竞争点等信息达成统一,防止产品偏离方向。倡议参加角色:业务需求方、产品经理和开发组长。
2、场景剖析
场景剖析是从用户视角登程,摸索业务畛域中的典型场景,产出畛域中须要撑持的场景分类、用例操作以及不同子域之间的依赖关系,用以撑持领域建模。
倡议参加角色:产品经理、需要剖析人员、架构师、开发组长和测试组长。
3、领域建模
领域建模是通过对业务和问题域进行剖析,建设畛域模型,向上通过限界上下文领导微服务边界设计,向下通过聚合领导实体的对象设计。
倡议参加角色:领域专家、产品经理、需要剖析人员、架构师、开发组长和测试组长。
4、微服务拆分和设计
联合业务限界上下文与技术因素,对服务的粒度、分层、边界划分、依赖关系和集成关系进行梳理,实现微服务拆分和设计。
微服务设计应综合思考业务职责繁多、敏态与稳态业务拆散、非功能性需要(如弹性伸缩要求、安全性等要求)、团队组织和沟通效率、软件包大小以及技术异构等因素。
倡议参加角色:产品经理、需要剖析人员、架构师、开发组长和测试组长。
八、畛域对象及服务矩阵和代码模型设计
本阶段实现畛域对象及服务矩阵文档以及微服务代码模型设计。
1、畛域对象及服务矩阵
依据事件风暴过程畛域对象和关系,对产出的限界上下文、聚合、实体、值对象、仓储、事件、应用服务、畛域服务等畛域对象以及各对象之间的依赖关系进行梳理,确定各对象在分层架构中的地位和依赖关系,建设畛域对象分层架构视图,为每个畛域对象建设与代码模型对象的一一映射。
倡议参加角色:架构师和开发组长。
2、微服务代码模型
依据畛域对象在 DDD 分层架构中所在的层、畛域类型、与代码对象的映射关系,定义畛域对象在微服务代码模型中的包、类和办法名称等,设计微服务工程的代码层级和代码构造,明确各层间的调用关系。
倡议参加角色:架构师和开发组长。
畛域对象及服务矩阵样例阐明
畛域对象及服务矩阵次要用来记录事件风暴和微服务设计过程中产出的畛域对象属性,如:各畛域对象在 DDD 分层架构中的地位、属性、依赖关系以及与代码对象的映射关系等。通过建设畛域对象与代码对象的映射关系,可领导软件开发人员准确无误的依照设计文档实现微服务开发。
以下为畛域对象及服务矩阵样例(局部数据,仅供参考)。
各栏阐明如下:
层:定义畛域对象位于 DDD 分层架构中的哪一层。如:接口层、应用层、畛域层以及根底层等。
聚合:在事件风暴过程中将关联严密的实体和值对象等组合造成聚合。本栏阐明聚合名称。
畛域对象名称:畛域模型中畛域对象的具体名称。如:“销假审批已通过”是类型为“事件”的畛域对象;“请假单”是畛域类型为“实体”的畛域对象。
畛域类型:在畛域模型中依据 DDD 常识域定义的畛域对象的类型,如:限界上下文、聚合、聚合根(实体)、实体、值对象、事件、命令、应用服务、畛域服务和仓储服务等。
依赖对象名称:依据业务对象依赖或分层调用依赖关系建设的畛域对象的依赖关系(如服务调用依赖、关联对象聚合等)。本栏阐明畛域对象需依赖的其余畛域对象,如下层服务在组合和编排过程中对上层服务的调用依赖、实体之间或者实体与值对象在聚合内的依赖等。
包名:代码模型中的包名,本栏阐明畛域对象所在的软件包。
类名:代码模型中的类名,本栏阐明畛域对象的类名。
办法名:代码模型中的办法名,本栏阐明畛域对象实现或操作的办法名。
九、微服务代码构造模型
微服务代码模型最终后果来源于畛域对象及服务矩阵。在代码模型设计时须建设畛域对象和代码对象的一一映射,保障业务模型与代码模型的一致性,即便不熟悉业务的开发人员或者不相熟代码的业务人员也能够很快定位到代码地位。
微服务代码总目录 基于 DDD 的代码模型包含 interfaces、application、domain 和 infrastructure 四个目录。
Interfaces(用户接口层):本目录次要寄存用户接口层代码。前端利用通过本层向应用服务获取展示所需的数据。本层次要用于解决用户发送的 Restful 申请和解析用户输出的配置文件等,并将信息传递给 Application 层。次要代码状态是数据组装以及 Facade 接口等。
Application(应用层):本目录次要寄存应用层代码。应用服务代码基于微服务内的畛域服务或微服务外的应用服务实现服务编排和组合。为用户接口层提供各种利用数据展示反对。次要代码状态是应用服务和畛域事件等。
Domain(畛域层):本目录次要寄存畛域层代码。本层代码次要实现外围畛域逻辑,其次要代码状态是实体类办法和畛域服务等。
Infrastructure(根底层):本目录寄存根底层代码,为其它各层提供通用技术能力、三方软件包、配置和根底资源服务等。
用户接口层代码模型
用户接口层代码模型目录包含:assembler、dto 和 facade。
相干文章:
基于 DDD 的微服务设计和开发实战
浅谈我对 DDD 畛域驱动设计的了解