2024年最全基于领域模型的微服务划分--实战案例解析(1),消息中间件的四种投递模式对比

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  1. 在限界上下文中,应用战术 DDD 模式以定义实体、聚合、领域服务。

  2. 使用前一步骤的结果标识出应用程序中的微服务。

请务必记住,DDD 是迭代的持续过程。 服务边界不是一成不变的。 随着应用程序的演变,你可以决定将某个服务分解成多个较小服务。

ℹ️ 本文未完整介绍全面的领域分析。 我们特意保留了简短内容来说明要点。 有关 DDD 的更多背景知识,我们建议阅读 Eric Evans 的 Domain-Driven Design(领域驱动设计),该书籍首次引入了该术语。 另一项优秀的参考资源是 Vaughn Vernon 撰写的《实现领域驱动设计》。

在 DDD 的战略阶段,我们要绘制业务领域的关系图,并定义领域模型的限界上下文。 在战术 DDD 阶段,需要更精确地定义领域模型。 战术模式在单个限界上下文中应用。 在微服务体系结构中,我们对实体和聚合模式特别感兴趣。 应用这些模式有助于识别应用程序中服务的自然边界。 作为一般原则,微服务应该不小于聚合,且不大于限界上下文。 首先,让我们了解战术模式。 然后,我们对无人机快递应用程序中的“交货”限界上下文应用这些模式。

战术模式概述

本部分将介绍战术 DDD 模式的简要概述,如果你已熟悉 DDD,则可以跳过本部分。 Eric Evans 著作的第 5 – 6 章,以及 Vaughn Vernon 的 Implementing Domain-Driven Design(实现域驱动的设计)一书中更详细地介绍了这些模式。

实体。 实体是一直保持唯一标识的对象。 例如,在银行应用程序中,客户和帐户就是实体。

  • 实体在系统中有唯一的标识符,使用该标识符可以查找和检索该实体。 这并不意味着,该标识符始终直接向用户公开。 它可能是数据库中的 GUID 或主键。

  • 一个标识可以跨多个限界上下文,并可能保留到应用程序生命期结束之后。 例如,银行帐号或政府颁发的身份证号不会与特定应用程序的生存期相关联。

  • 实体的属性可随时变化。 例如,某人的姓名或地址可能有变化,但他(她)仍是同一个人。

  • 一个实体可以包含对其他实体的引用。

值对象。 值对象没有标识。 它只由其属性值定义。 值对象也是不可变的。 若要更新值对象,始终需要创建一个新实例来替换旧实例。 值对象可以包含用于封装领域逻辑的方法,但这些方法不应该给对象的状态产生负面影响。 值对象的典型示例包括颜色、日期时间和货币值。

聚合。 聚合定义一个或多个实体的一致性边界。 一个聚合只包含一个根实体。 可以使用根实体的标识符执行查找。 从根开始的引用可以找到聚合中的其他任何实体。

聚合的作用是为事务一致性建模。 现实世界中的事物具有复杂的关系。 客户创建订单,订单包含产品,产品有供应商,等等。 如果应用程序修改了多个相关对象,它如何保证一致性?

传统应用程序通常使用数据库事务来实施一致性。 但是,在分布式应用程序中,这种做法通常不可行。 单个业务事务可能跨越多个数据存储、长时间运行,或者涉及第三方服务。 最终由应用程序而不是数据层来实施域所需的一致性。 这就是要为聚合建模的目的。

ℹ️ 聚合可以包含单个实体且不包含子实体。 聚合的定义由事务边界确定。

领域服务和应用服务。 在 DDD 术语中,服务是实现某种逻辑且不保存任何状态的对象。 Evans 区分 域服务(用于封装域逻辑)和 应用程序服务(提供技术功能,如用户身份验证或发送短信)。 领域服务通常用于对跨多个实体的行为建模。

ℹ️ 软件开发中广泛使用了“服务”一词。 此处的定义不直接与微服务相关。

领域事件。 发生某种情况时,可以使用领域事件来通知系统的其他部件。 顾名思义,领域事件应该表示领域中发生的某些情况。 例如,“在表中插入了记录”不是领域事件。 “已取消投递”是领域事件。 领域事件与微服务体系结构密切相关。 由于微服务为分发式且不共享数据存储,领域事件可为微服务提供相互协调的途径。

文章 服务间通信 更详细地讨论了异步消息传送。

还有其他几种 DDD 模式未在此处列出,包括工厂、Repository和模块。 开发微服务时,这些模式可能十分有用;但是,在微服务之间设计边界时,它们作用不大。

从领域模型到微服务

微服务的适当大小是什么? 我们经常听到有人说,“不要太大,也不要太小”— 这句话绝对正确,但实际上没有太大意义。 但是,如果从一个精心设计的领域模型着手,则规划出微服务就容易得多。

在为限界上下文标识了一组实体、聚合和领域服务之后,我们可以从领域模型转到应用程序设计。 下面是一个用于从域模型派生微服务的方法。

  1. 从限定上下文开始。 通常,微服务中的功能不应跨多个限定上下文。 根据定义,限界上下文标记特定领域模型的边界。 如果你发现微服务混用了不同的领域模型,可能意味着需要重新进行领域分析以优化领域模型。

  2. 接下来,查看领域模型中的聚合。 聚合通常是微服务的适当候选项。 合理设计的聚合能够体现一个设计优良的微服务的许多特征,例如:

  • 聚合派生自业务要求,而不是数据访问或消息传递等技术因素。

  • 聚合应具有较高的功能内聚性。

  • 聚合是持久性的边界。

  • 聚合应为松散耦合。

  1. 域服务也是微服务的适当候选项。 域服务是跨多个聚合的无状态操作。 典型的示例是涉及多个微服务的工作流。 我们将在无人机快递应用程序中看到此示例。

  2. 最后,考虑非功能性要求。 分析团队规模、数据类型、技术、可伸缩性、可用性和安全性需求等因素。 这些因素可能导致需要进一步将微服务分解成两个或更多个较小服务,或者相反的,将多个微服务合并成一个。

在应用程序中标识微服务之后,请根据以下条件验证设计:

  • 每个服务承担单一责任

  • 服务之间不存在琐碎的调用。 如果将功能拆分成两个服务会导致它们过度琐碎,该症状的原因可能是这些功能属于同一个服务。

  • 每个服务足够小,独立工作的小团队即可构建它。

  • 两个或更多个服务的部署不应该存在相互依赖的关系。 应该始终可以在不重新部署其他任何服务的情况下部署某个服务。

  • 服务未紧密耦合,可独立演变。

  • 服务边界不会造成数据一致性或完整性方面的问题。 有时,必须通过将功能放入单个微服务来保持数据一致性。 话虽如此,但应该是否确实需要强一致性。 可通过某些策略来解决分布式系统中的最终一致性,分解服务的好处通常比管理最终一致性所存在的挑战更具效益

最重要的是,必须追求实用,并记住领域驱动的设计是一个迭代过程。 如果有疑问,可以从粗粒度的微服务入手。 相比跨多个现有的微服务进行功能重构,将现有的微服务拆分成较小服务更加容易。

实战案例:无人机快递


Fabrikam, Inc. 正在推出无人机快递服务。 该公司经营无人机群。 各商家注册该服务,用户可以请求无人机收取要投递的商品。 当用户安排取件时,后端系统会分配一架无人机,并将估计的投递时间告知用户。 在投递过程中,用户可以通过持续更新的 ETA(Estimated time of arrival,预计到达时间) 跟踪无人机的位置。

此方案涉及到一个相当复杂的领域。 部分业务难题包括安排无人机、跟踪包裹、管理用户帐户,以及存储和分析历史数据。 此外,Fabrikam 希望快速投放市场扩张业务,同时添加新功能。 该应用程序需要在云环境运行,并附带较高的服务级别目标 (SLO)。 此外,Fabrikam 预期系统的不同部件在数据存储和查询方面具有截然不同的要求。 所有这些考虑因素促使 Fabrikam 为无人机快递应用程序选择了微服务体系结构。

分析领域 Analyze Domain


借助 DDD 方法设计微服务,可以使每个服务都能符合业务功能要求。 此方法有助于避免组织边界或技术选择左右你的设计。

在编写任何代码之前,需要获取所创建的系统的鸟瞰图。 DDD 首先构建业务领域并创建 域模型。 领域模型是业务领域的抽象模型。 它可以提取和组织领域知识,并为开发人员和领域专家提供通用语言。

首先,映射所有业务功能及它们之间的连接。 这可能需要领域专家、软件架构师和其他利益干系人的互相协作。 无需使用任何特定的形式。 可以直接草绘或者在白板上绘制关系图。

在绘制关系图时,可以开始标识离散的子域。 哪些功能密切相关? 哪些功能是业务的核心?哪些功能提供辅助服务? 什么是依赖项关系图? 在此初始阶段,不需要考虑技术或实施细节。 也就是说,应该注意应用程序要在哪个位置与 CRM、付款处理系统或计费系统等外部系统集成。

完成一些初始域分析之后,Fabrikam 团队绘制了一份描绘无人机快递领域的草图。

  • 送货 (Shipping)位于关系图的中心,因为它是业务的核心。 关系图中的其他任何元素都是为了支持此功能。

  • 无人机管理 (Drone Management)也是业务的核心。 与无人机管理密切相关的功能包括 无人机维修,以及使用 预测分析 来预测无人机何时需要检修和维护。

  • ETA 分析 提供取件和投递的估计时间。

  • 如果包裹无法完全由无人机投递,则应用程序可以通过 第三方运输 来安排替代的运输方式。

  • 无人机共享 是核心业务的可能扩展。 公司的无人机在某些时段可能容量过剩,在这种情况下,可以出租无人机,以避免闲置。 初始版本未包括此功能。

  • 视频监督 (Video surveillance)是公司以后可以拓展到的另一个领域。

  • 用户帐户开票 (Invoicing)和 呼叫中心 是支持核心业务的子域。

请注意,在此阶段,我们尚未做出有关实施或技术的任何决策。 某些子系统可能涉及到外部软件系统或第三方服务。 即便如此,应用程序也需要与这些系统和服务进行交互,因此,必须将它们包含在领域模型中。

ℹ️ 如果应用程序依赖于外部系统,则存在一种风险:外部系统的数据架构或 API 会渗入应用程序,最终暴露了体系结构设计。 不遵循最佳实践,并使用复杂数据架构或过时 API 的旧式系统尤其如此。 在这种情况下,必须在这些外部系统与应用程序之间妥善定义边界。 出于此目的,请考虑使用 扼杀者模式 或 防腐层模式 。

定义限界上下文 Define Bounded Context


领域模型将包含现实世界中事物的表示形式 — 用户、无人机、包裹等等。 但这并不意味着系统的每个部分都需要对相同的事物使用相同的表示形式。

例如,处理无人机维修和预测分析的子系统将需要表示无人机的许多物理特征,例如,其维护历史记录、里程、生产年份、型号、性能特征等。 但是,在安排投递时,我们并不需要关心这些方面。 计划子系统只需知道无人机是否可用,以及取件和交货的 ETA。

如果尝试为这两个子系统创建了单个模型,则会不必要地增大复杂性。 此外,模型会更难得到发展,因为任何更改都需要满足处理不同子系统的多个团队的要求。 因此,更好的做法通常是设计不同的模型,用于在两种不同的上下文中呈现相同的真实实体(在本例中为无人机)。 每个模型仅包含其特定上下文中相关的功能和属性。

这就是DDD限界上下文的 概念 发挥作用的地方。 限界上下文只是应用特定领域模型的领域中的边界。 在下图中,我们可以根据各种功能是否共享单个领域模型将功能分组。

限界上下文不一定相互独立。 在此图中,连接限界上下文的实线表示两个限界上下文交互的位置。 例如,“送货”依赖于“用户帐户”来获取有关客户的信息,并依赖于“无人机管理”来安排机群中的无人机。

在 Domain Driven Design(领域驱动设计)一书中,Eric Evans 描述了当某个领域模型与另一个限界上下文交互时,保持该模型完整性的多种模式。 微服务的主要原则之一是服务通过完善定义的 API 进行通信。 此方法对应于两种模式,即 Evans 所说的“开放主机服务(Open Host Service)”和“发布语言(Published Language)”。 “开放主机服务”的思路是子系统针对与它通信的其他子系统定义一个正式协议 (API)。 “发布语言”扩展了这种思路,以特定格式发布 API,其他团队可以直接用来编写客户端。 比如使用OpenAPI规范 ((以前称为 Swagger) )为 REST API 定义与语言无关的接口说明(以 JSON 或 YAML 格式表示)。

以下部分侧重于“送货”限界上下文。

定义实体、聚合及服务 Define Entities, Aggregates & Services


首先,我们探讨“送货”限界上下文必须处理的场景。

总结

上述知识点,囊括了目前互联网企业的主流应用技术以及能让你成为“香饽饽”的高级架构知识,每个笔记里面几乎都带有实战内容。

很多人担心学了容易忘,这里教你一个方法,那就是重复学习。

打个比方,假如你正在学习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。

从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值