微服务与领域驱动设计,架构实践总结

怎样的架构才能配得上造到飞起的变化?

一、软件复杂性

1、复杂原因

如果软件系统存在持续的迭代周期,那么其中业务、技术、架构的复杂性都会直线拉升,其相应的开发难度也会提高,可以用一句话总结其根本原因:唯一不变的就是变化;

微服务与领域驱动设计,架构实践总结
  • 业务变化:导致复杂性的根本原因,在多端多版本适配的过程中代码快速膨胀;
  • 数据变化:数据随着业务的变化和发展,不断沉淀积累,需要做横向与纵向的管理;
  • 技术升级:技术组件可能因为漏洞,或者更好的解决问题,不间断升级版本;
  • 人员变动:模块的开发人员一旦出现流动,换人接手会给代码带来风格上的差异;
  • 心态起伏:持续应对复杂问题,但平稳的心态很难持续,也是人员流动的一个因素;

应对复杂的变化一直都是软件工程的核心难点问题,如何用较小的架构变化应对较大的业务变化,就是设计中常说的:高内聚、低耦合;还需要补充很重要的一点:单从技术层面是无法持续解决复杂问题的,还需要从管理角度去定义流程标准,规范各种解决方案,是整个部门要持续面对的事项。

2、应对复杂

不管是常说的设计模式、原则、面向对象,还是架构中常用的集群、微服务、领域驱动等,都是在寻求更合理的方案来应对业务的变化;但是没有一劳永逸的解决方法,既要做一定前瞻性的设计去预期业务,同时还要避免过度的设计影响业务进度;这就需要研发团队具备一定的业务高度和技术深度:

微服务与领域驱动设计,架构实践总结

在系统落地的过程中,需要对业务深入的分析和理解,不断优化技术层面的解决方案;比如微服务的思想是通过拆分的手段实现业务块之间的低耦合,领域驱动设计则实现各个业务逻辑的高内聚;下面围绕两种方式的实践去详细分析。

二、微服务架构

1、架构设计

系统的架构设计是一件极度复杂的事情,在工作的这几年大致经历过如下几个阶段:单服务、多服务集群、微服务、持续集成;在近2年比较稳定的选型是微服务+自动化集成的模式:

微服务与领域驱动设计,架构实践总结

思考其本质的变化逻辑,即为了应对更复杂的业务体系;不管是业务拆分还是模型设计,都是在不断实现 高内聚低耦合的原则;降低业务之间的关联影响,分离业务和技术的高度耦合。

2、业务场景

这里先来看一个经典的业务场景:电商交易;基于微服务架构的电商交易场景中,通常至少会涉及如下几个核心服务:交易、账户、订单、商品、仓储、物流;

微服务与领域驱动设计,架构实践总结

站在业务角度,进行模块化拆分和管理,结合持续集成的组件,通常可以轻松的应对各种复杂的业务场景,但是不存在真正意义上一劳永逸的手段,业务变化带来的各种问题总会无脑推动开发去寻找更合理的解决方案;

微服务与领域驱动设计,架构实践总结

在一次完整的电商交易场景中,实际上真正涉及到的微服务远不止图中的几个,在Trade服务中交织关联多个其他服务,在MVC的分层管理下,初期并不会存在较大风险,但是业务一旦经过多版升级改造之后,并且还存在版本兼容的要求,会给人一种极度混乱和不踏实的感觉;

如果团队成员的综合能力较高,并且版本有充足的时间去设计和优化,这种问题是可以妥善解决的,如果出现时间紧任务重的情况,随之而来的 压力会持续在开发和测试之间来回横跳

解决过相关业务场景的研发都知道,重构加持续集成能力,结合严谨的测试,可以应对业务的不断变化;但是在版本兼容的过程中,依然会导致工程中的代码膨胀到飞起,特别是出现中场换人的情况,都会让接手的人员在被埋和离开中,产生一次剧烈的心态挣扎。

3、问题分析

在MVC的架构模式中,工程通常会进行如下的分层管理:控制层、服务层、持久层、存储层;服务层在特定复杂的场景中会做细化拆分,比如第三方对接、常用中间件的二次封装:

微服务与领域驱动设计,架构实践总结

对于在复杂业务线上争渡的选手来说,对Mvc分层模式的缺陷是深有体会的,Service层聚焦大量复杂的逻辑,通常核心业务块中总会存在几个代码过千行的实现逻辑,不管用什么思路和模式去拆分封装,都很难解决该层不断扩展带来的膨胀问题。

4、面向过程

在MVC分层中,过程式的代码极其明显,通常以数据库表和关系为基础,映射构建相关实体对象,这些实体对象并没有具体的行为和逻辑,只是作为数据和结构的载体:

微服务与领域驱动设计,架构实践总结

从面向对象中类的定义去看:属性和行为;而在MVC模式中,绝大多数实体都只是作为数据的入参出参的结构定义,可以理解为数据容器,在MVC的各层之间不断搬运和加工。

三、领域驱动设计

相比MVC的分层设计,领域驱动设计(Domain-Driven-Design简称DDD)对于复杂业务系统的实现,提出了更加合理的解决方案,DDD模式中涉及大量专业术语和抽象概念,可以参考 EricEvans的相关书籍,本文只描述实践中的核心概念。

1、分离模式

DDD模型在分层设计上,划分出核心的四层:接入层、应用层、领域层、基础设施层;注意这里只是单纯站在服务端的常规架构角度去看,很明显分离MVC模式中的服务实现层的逻辑:

微服务与领域驱动设计,架构实践总结

其中领域层是关键所在,用来封装复杂的业务,对应用层提供业务管理的核心支撑;整个模型也更具备纵向思维,有效的缓解单层复杂度过高的现象;单从模型设计上看,在工程中基于该分层去管理代码包,也可以使每层的设计更加清晰和独立。

2、设计思想

领域驱动设计并不是简单的分层管理模型,涉及诸多抽象逻辑与专业术语,例如:领域、界限上下文、实体、聚合、值对象等等;

2.1 领域

领域可以理解为业务场景中需要解决的问题合集,是具有范围和边界的约束;领域可以拆分多个子域,通常描述为:核心域、支撑域、通用域:

微服务与领域驱动设计,架构实践总结

关于子域的划分也是参考业务属性,可以把核心域理解为最关键的业务场景,并且需要资源倾斜以应对其不断的发展;支撑域可以理解为相对稳定的业务;通用域偏向系统架构层面的公共能力;通过对领域的拆分实现业务分治,这与微服务的拆分思想相符合,两种模式在业务角度是比较统一的;

2.2 界限上下文

DDD中最晦涩难懂的一个抽象概念,特定模型的限界应用,不过可以借用原文的比喻会意一下:细胞之所以能够存在,是因为细胞膜限定了什么在细胞内,什么在细胞外, 并且确定了什么物质可以通过细胞膜:

微服务与领域驱动设计,架构实践总结

界限上下文的定义涉及粒度的思想,即每个粒度要具备独立性;如上图仓储业务,可以将服务部署与仓储子域、仓储上下文做成一一对应的关系,或者在仓储子域中分别定义:仓库和货架两个上下文;这里具有极大的灵活性,没有真正意义上的标准可以参考。

2.3 映射关系

做好界限上下文的划分,理清各个上下文之间的关系,明确业务场景中的依赖顺序,这样可以更好的推动开发流程的落地;对于上下文的关系描述也远不止图中的这些,还有共享内核、合作等等:

微服务与领域驱动设计,架构实践总结
  • 上下游(U-上游,D下游):描述上下文调用时的关系,服务调用方为D,服务提供方为U;
  • 防腐层(Anticorruption-Layer,简写ACL):上下文交互时封装的一层,提供对动作的校验、适配、转换等;
  • 开放主机服务,发布语言(Open-Host-Service简写OHS,Published-Language简写PL):定义访问协议;

在上下文交互时,防腐层可以维护上下文的隔离和独立,确保调用方不直接依赖服务提供方,从而实现不同上下文之间的依赖解耦;同时这也会带来大量的对象转换动作;

2.4 建模设计

子域和界线上线文完成对业务的拆分切块,从而进行分治;基于防腐层降低各个界限上下文的耦合程度;聚合思想保证了业务问题的解决方案内聚;严格的分层模型实现服务支撑能力的分散;

微服务与领域驱动设计,架构实践总结
  • 防腐层(Anticorruption-Layer):上下文交互时封装的一层;
  • 领域层(Domain-Layer):在分层架构中负责领域逻辑的设计和实现;
  • 领域服务(Domain-Service):行为无法识别归属的实体时,封装到领域服务;
  • 聚合(Aggregate):相关对象的集合,描述核心领域,通常把聚合作为数据修改的单元;
  • 实体(Entity):通过标识来定义的对象,而不是基于属性,比如Uid标识用户实体;
  • 值对象(Value-Object):描述特征或属性但没有标识的对象;
  • 工厂(Factory):封装对象复杂的创建逻辑与类型;
  • 存储库(Repository):把存储、缓存、搜索等资源封装的机制,对应领域模型;

领域模型的核心追求目标:高内聚、低耦合;更加抽象的、复杂的设计思想,也同样意味着落地实现的难度更高,但不可否认领域模型作为复杂业务的解决方案,逻辑上的确更加合理。

3、工程实践

领域模型在代码工程的实践中,可以将不同的子域集成到各自的服务中,也可以在一个服务中,通过多个模块(Module)进行隔离维护,即一个模块对应一个界限上下文;

微服务与领域驱动设计,架构实践总结

将业务问题进行分模块分层分包的方式进行隔离,是代码工程中的基本手段,这里只是对组织方式进行描述,在实际的开发中,要根据依赖顺序进行类库拆包管理;

在程序的执行过程中,并不是所有的交互命令都需要经过领域层,实际上大部分业务中的查询命令都是超过增删改命令的,所以在纯读取数据的请求中,应用层可以绕开领域层直接访问基础设施层,减少一层数据处理逻辑。

四、实践总结

最后来讨论一些架构实践的经验,随着技术的不断发展和更新换代,为解决业务问题提供了极大的便利,不管是单服务中各种成熟的组件,又或者分布式中的微服务体系,或者聚焦业务管理的领域模型;每种架构选型都有其适用的场景,不同的选型意味着不一样的实现成本;

实际上在做架构选型时,成熟有经验的主导者,都极其擅长做折中处理,也就是常说的退一步海阔天空;通常需要考虑团队的综合水平与业务需求和产品设计,当然在实际的协作流程中多方都是需要相对让步的,但是对质量的要求以及核心业务的实现逻辑上是不能打折的。

五、参考源码

编程文档:
https://gitee.com/cicadasmile/butte-java-note

应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent

Original: https://www.cnblogs.com/cicada-smile/p/16188648.html
Author: 知了一笑
Title: 微服务与领域驱动设计,架构实践总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/610801/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 数组常见操作

    8.19 day7 数组常见操作 获取数组最值 public static int maxElement(int[] arr) { // 假设第一个元素的值就是最大值 int ma…

    Linux 2023年6月7日
    090
  • 生成符合chrome要求的自签名HTTPS证书

    按照文章给Nginx配置一个自签名的SSL证书中给出的代码生成自签名证书后,发现使用chrome浏览器访问会报 Invalid self signed SSL cert &#821…

    Linux 2023年6月6日
    079
  • NewReplacer使用技巧

    上次写博客至今有段时间了,这些日子,认真过,努力过,职场中不管有哪些让人失意或不快的事,终归到底,是自己不够强大。。。 好吧,新的一年,不磨磨唧唧了,一般处理xss漏洞使用正则匹配…

    Linux 2023年6月6日
    0104
  • 对比nushell和powershell

    2021-07-17 第一版 有些对比领域缺失,这篇文章会持续更新。 这是一篇对比powershell和nushell的文章。我是powerhsell专家,又是nushell新手,…

    Linux 2023年6月14日
    0110
  • Linux高可用之Keepalived

    注意: 各节点时间必须同步 确保各节点的用于集群服务的接口支持MULTICAST通信(组播); 安装 从CentOS 6.4开始keepalived随系统base仓库提供,可以使用…

    Linux 2023年5月27日
    0139
  • idea 运行 tyarn 命令提示系统禁止运行脚本

    无法加载文件D:……….(报错信息。。。),因为在此系统上禁止运行脚本,有关详细信息,请参阅 https:/go.microsoft.com/f…

    Linux 2023年6月13日
    092
  • lvs

    1.lvs简介 2.结构体系 3.lvs工作模式及原理 4.配置lvs 4.1 部署lvs-nat模式的httpd负载集群—http协议 4.2 部署lvs-dr模式的…

    Linux 2023年6月13日
    093
  • DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色

    本文将告诉大家如何使用 Vortice 底层库从零开始,从一个控制台项目,开始搭建一个最简单的使用 Direct2D1 的 DirectX 应用。本文属于入门级博客,期望本文能让大…

    Linux 2023年6月6日
    092
  • rsync

    rsync简介 rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或者与其他SSH、rsync主机同步。 rsy…

    Linux 2023年6月6日
    088
  • 容器编排,跨集群部署(脚踩2只船)问题研究

    —【前言】— https://www.cnblogs.com/cmt/p/14306142.html 问题来自于博客园,讨论容器编排,跨集群部署(脚踩2只船…

    Linux 2023年6月14日
    0112
  • Linux 网络分析必备技能:tcpdump 实战详解

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    086
  • 软件工程 软件需求与软件需求规约 第1篇随笔

    2、软件需求与软件需求规约 1. 何为需求? 定义问题的基本要素是 “需求” 一个需求是一个有关”要予构造”的陈述,用以描述待开发产…

    Linux 2023年6月7日
    0103
  • 快速删除指定文件夹下的.DS_Store文件

    清除当前文件夹中 .DS_store 文件: find "." -name .DS_Store find "." -name .DS_Sto…

    Linux 2023年6月14日
    076
  • sed高阶用法

    a 追加 [root@localhost ~]# cat test hello world jjjd aaaaaaa //向第二行后面追加’hi world’ [root@loca…

    Linux 2023年6月13日
    0103
  • 性能优化,实践浅谈

    当经历了无数的日日夜夜,朝九晚九,攻克了无数难关,终于将系统预定功能开发完成,通过测试,部署上线后。你是否会感觉志得意满,到达了人生巅峰,高唱无敌是多么寂寞。 现实情况是,如果你这…

    Linux 2023年6月13日
    0122
  • 零成本搭建个人博客之图床和cdn加速

    本文属于零成本搭建个人博客指南系列 为什么要使用图床 博客文章中的图片资源文件一般采用本地相对/绝对路径引用,或者使用图床通过外链进行引用展示。本地引用的弊端我认为在于: 图片和博…

    Linux 2023年6月7日
    0118
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球