基于DDD的微服务设计和开发实战
⽬录
你是否还在为微服务应该拆多⼩⽽争论不休?到底如何才能设计出收放⾃如的微服务?怎样才能保证业务领域模型与代码模型的⼀致性?或许本⽂能帮你到答案。
本⽂是基于 DDD 的微服务设计和开发实战篇,通过借鉴领域驱动设计思想,指导微服务项⽬团队进⾏设计和开发(理论篇详见)。本⽂包括三部分内容:第⼀部分讲述领域驱动设计基本知识,包括:分层架构、服务视图、数据视图和领域事件发布和订阅等;第⼆部分讲述微服务设计⽅法、过程、模板、代码⽬录、设计原则等内容;最后部分以⼀个项⽬为例讲述基于 DDD 的微服务设计过程。
1 ⽬标
通过领域模型和 DDD 的分层思想,屏蔽外部变化对领域逻辑的影响,确保交付的软件产品是边界清晰的微服务,⽽不是内部边界依然混乱的⼩单体。在需求和设计变化时,可以轻松的完成微服务的开发、拆分和组合,确保微服务不易受外部变化的影响,并稳定运⾏。
2 适⽤范围
本⽂适⽤于按照 DDD 设计⽅法进⾏微服务设计和开发的项⽬及相关⼈员。
以下情况不适⽤:
1. “我们的⽬标是按期盖出⼀栋⼤楼来,不要跟我提什么⽅法,有这啰嗦的时间,还不如抓紧点时间搬砖,把楼给我快点盖好!”。
2. “我的⼯作就是让软件运⾏起来,能⼯作⼀切就 OK!我不需要那么多约束,什么设计⽅法、扩展性、业务变化、领域模型、响应能
⼒与我⽆关。别耽误⼯期啦!先上线再说!”。
3. “好的软件是⾃⼰演进出来的,我们不需要设计!”。
哈哈,开个玩笑啦!其实设计不会花太多时间的!
不耽误⼤家时间了,⾔归正传。
3 DDD 分层架构视图
DDD 分层架构包括:展现层、应⽤层、领域层和基础层。
DDD 分层架构各层职能如下:
展现层
展现层负责向⽤户显⽰信息和解释⽤户指令。
应⽤层
应⽤层是很薄的⼀层,主要⾯向⽤户⽤例操作,协调和指挥领域对象来完成业务逻辑。应⽤层也是与其他系统的应⽤层进⾏交互的必要渠道。应⽤层服务尽量简单,它不包含业务规则或知识,只为下⼀层的领域对象协调任务,使它们互相协作。应⽤层还可进⾏安全认证、权限校验、分布式和持久化事务控制或向外部应⽤发送基于事件的消息等。
领域层
领域层是软件的核⼼所在,它实现全部业务逻辑并且通过各种校验⼿段保证业务正确性。它包含业务所涉及的领域对象(实体、值对象)、领域服务以及它们之间的关系。它负责表达业务概念、业务状态以及业务规则,具体表现形式就是领域模型。
基础层
基础层为各层提供通⽤的技术能⼒,包括:为应⽤层传递消息、提供 API 管理,为领域层提供数据库持久化机制等。它还能通过技术框架来⽀持各层之间的交互。
4 服务视图
微服务内的服务视图
微服务内有 Facade 接⼝、应⽤服务、领域服务和基础服务,各层服务协同配合,为外部提供服务。
1、接⼝服务
接⼝服务位于⽤户接⼝层,⽤于处理⽤户发送的 Restful 请求和解析⽤户输⼊的配置⽂件等,并将信息传递给应⽤层。
2、应⽤服务
应⽤服务位于应⽤层。⽤来表述应⽤和⽤户⾏为,负责服务的组合、编排和转发,负责处理业务⽤例的执⾏顺序以及结果的拼装。
应⽤层的服务包括应⽤服务和领域事件相关服务。
应⽤服务可对微服务内的领域服务以及微服务外的应⽤服务进⾏组合和编排,或者对基础层如⽂件、缓存等数据直接操作形成应⽤服务,对外提供粗粒度的服务。
领域事件服务包括两类:领域事件的发布和订阅。通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦。
3、领域服务
领域服务位于领域层,为完成领域中跨实体或值对象的操作转换⽽封装的服务,领域服务以与实体和值对象相同的⽅式参与实施过程。
领域服务对同⼀个实体的⼀个或多个⽅法进⾏组合和封装,或对多个不同实体的操作进⾏组合或编排,对外暴露成领域服务。领域服务封装了核⼼的业务逻辑。实体⾃⾝的⾏为在实体类内部实现,向上封装成领域服务暴露。
为隐藏领域层的业务逻辑实现,所有领域⽅法和服务等均须通过领域服务对外暴露。
为实现微服务内聚合之间的解耦,原则上禁⽌跨聚合的领域服务调⽤和跨聚合的数据相互关联。
4、基础服务
基础服务位于基础层。为各层提供资源服务(如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响。
基础服务主要为仓储服务,通过依赖反转的⽅式为各层提供基础资源服务,领域服务和应⽤服务调⽤仓储服务接⼝,利⽤仓储实现持久化数据对象或直接访问基础资源。
微服务外的服务视图
1. 前端应⽤与微服务
微服务中的应⽤服务通过⽤户接⼝层组装和数据转换后,发布在 API ⽹关,为前端应⽤提供数据展⽰服务。
2. 微服务与外部应⽤
跨微服务数据处理时,对实时性要求⾼的场景,可选择直接调⽤应⽤服务的⽅式(新增和修改类型操作需关注事务⼀致性)。对实时性要求不⾼的场景,可选择异步化的领域事件驱动机制(最终数据⼀致性)。
5 数据视图
DDD 分层架构中数据对象转换的过程如下图。
数据视图应⽤服务通过数据传输对象(DTO)完成外部数据交换。领域层通过领域对象(DO)作为领域实体和值对象的数据和⾏为载体。基础层利⽤持久化对象(PO)完成数据库的交换。
DTO 与 VO 通过 Restful 协议实现 JSON 格式和对象转换。
前端应⽤与应⽤层之间 DTO 与 DO 的转换发⽣在⽤户接⼝层。如微服务内应⽤服务需调⽤外部微服务的应⽤服务,则 DTO 的组装和DTO 与 DO 的转换发⽣在应⽤层。
领域层 DO 与 PO 的转换发⽣在基础层。
6 领域事件和事件总线
领域事件是领域模型中⾮常重要的部分,⽤来表⽰领域中发⽣的事件。⼀个领域事件将导致进⼀步的业务操作,有助于形成完整的业务闭环。领域事件主要⽤于解耦微服务,各个微服务之间不再是强⼀致性,⽽是基于事件的最终⼀致性。
微服务内的领域事件
微服务内的领域事件可以通过事件总线或利⽤应⽤服务实现不同聚合之间的业务协同。当微服务内发
⽣领域事件时,由于⼤部分事件的集成发⽣在同⼀个线程内,不⼀定需要引⼊消息中间件。但⼀个事件如果同时更新多个聚合数据,按照 DDD“⼀个事务只更新⼀个聚合根”的原则,可以考虑引⼊消息中间件,通过异步化的⽅式,对微服务内不同的聚合根采⽤不同的事务。
微服务之间的领域事件
微服务之间的数据交互⽅式通常有两种:应⽤服务调⽤和领域事件驱动机制。
领域事件驱动机制更多的⽤于不同微服务之间的集成,实现微服务之间的解耦。事件库(表)可以⽤于微服务之间的数据对账,在应⽤、⽹络等出现问题后,可以实现源和⽬的端的数据⽐对,在数据暂时不⼀致的情况下仍可根据这些数据完成后续业务处理流程,保证微服务之间数据的最终⼀致性。
应⽤服务调⽤⽅式通常应⽤于实时性要求⾼的业务场景,但⼀旦涉及到跨微服务的数据修改,将会增加分布式事务控制成本,影响系统性能,微服务之间的耦合度也会变⾼。
事件总线
事件总线位于基础层,为应⽤层和领域层服务提供事件消息接收和分发等服务。其⼤致流程如下:
1、服务触发并发布事件。
2、事件总线事件分发。
1. 如果是微服务内的订阅者(微服务内的其它聚合),则直接分发到指定订阅者。
2. 如果是微服务外的订阅者,则事件消息先保存到事件库(表)并异步发送到消息中间件。
3. 如果同时存在微服务内和外订阅者,则分发到内部订阅者,并将事件消息保存到事件库(表)并异步发送到消息中间件。为了保证事
务的⼀致性,事件表可以共享业务数据库。也可以采⽤多个微服务共享事件库的⽅式。当业务操作和事件发布操作跨数据库时,须保证业务操作和事件发布操作数据的强⼀致性。
事件数据持久化
事件数据的持久化存储可以有两种⽅案,在项⽬实施过程中根据具体场景选择最佳⽅案。
1. 事件数据保存到微服务所在业务数据库的事件表中,利⽤本地事务保证业务操作和事件发布操作的强⼀致性。
2. 事件数据保存到多个微服务共享的事件库中。需要注意的⼀点是:这时业务操作和事件发布操作会跨数据库操作,须保证事务的强⼀
致性(如分布式事务机制)。
事件数据的持久化可以保证数据的完整性,基于这些数据可以完成跨微服务数据的⼀致性⽐对。
7 微服务设计⽅法
分布式和微服务的关系事件风暴
本阶段主要完成领域模型设计。
基于 DDD 的微服务设计通常采⽤事件风暴⽅法。通过事件风暴完成领域模型设计,划分出微服务逻辑边界和物理边界,定义领域模型中的领域对象,指导微服务设计和开发。事件风暴通常包括产品愿景、场景分析、领域建模、微服务设计和拆分等过程。本⽂不对事件风暴详细⽅法做深⼊描述,如感兴趣可查阅相关资料。
1、产品愿景
产品愿景是对产品的顶层价值设计,对产品⽬标⽤户、核⼼价值、差异化竞争点等信息达成⼀致,避免产品偏离⽅向。建议参与⾓⾊:业务需求⽅、产品经理和开发组长。
2、场景分析
场景分析是从⽤户视⾓出发,探索业务领域中的典型场景,产出领域中需要⽀撑的场景分类、⽤例操作以及不同⼦域之间的依赖关系,⽤以⽀撑领域建模。
建议参与⾓⾊:产品经理、需求分析⼈员、架构师、开发组长和测试组长。
3、领域建模
领域建模是通过对业务和问题域进⾏分析,建⽴领域模型,向上通过限界上下⽂指导微服务边界设计,向下通过聚合指导实体的对象设计。
建议参与⾓⾊:领域专家、产品经理、需求分析⼈员、架构师、开发组长和测试组长。
4、微服务拆分和设计
结合业务限界上下⽂与技术因素,对服务的粒度、分层、边界划分、依赖关系和集成关系进⾏梳理,完成微服务拆分和设计。
微服务设计应综合考虑业务职责单⼀、敏态与稳态业务分离、⾮功能性需求(如弹性伸缩要求、安全性等要求)、团队组织和沟通效率、软件包⼤⼩以及技术异构等因素。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论