如何构建基于 DDD 领域驱动的微服务?(1)

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 如何构建基于 DDD 领域驱动的微服务?

尽管微服务中的“微”一词表示服务的规模,但它并不是使用微服务的唯一标准。当团队转向基于微服务的架构时,他们旨在提高敏捷性以及自主且频繁地部署功能。很难确定这种架构风格的简单定义。我喜欢Adrian Cockcroft的关于微服务的简短定义: “ 面向服务的体系结构,它由松散耦合的、具有上下文边界的元素组成。”


尽管这定义了高级设计启发式技术,但微服务架构具有一些独特的特性,使其有别于以往的面向服务的架构。以下是其中一些特征。这些以及其他一些文档都有据可查-Martin Fowler的文章和Sam Newman的Building Microservices,仅举几例。


  • 服务具有围绕业务上下文而不是任意技术上抽象的明确定义的边界
  • 通过意图公开界面隐藏实现细节并公开功能
  • 服务不会共享超出其边界的内部结构。例如,不共享数据库。
  • 服务可以抵抗故障。
  • 团队独立拥有职能,并能够自主发布变更
  • 团队拥护自动化文化。例如,自动化测试,持续集成和持续交付


简而言之,我们可以将这种体系结构样式总结如下:


松耦合的面向服务的体系结构,其中每个服务都包含在定义明确的有界上下文中,从而可以快速,频繁且可靠地交付应用程序。


领域驱动设计和有界上下文


微服务的力量来自明确定义其职责并划分它们之间的边界。此处的目的是在边界内建立高凝聚力,并在边界外建立低耦合(banq注:高凝聚低耦合)。也就是说,趋于一起改变的事物应该属于同一事物。就像在许多现实生活中的问题一样,这说起来容易做起来难,业务在不断发展,逻辑的假设前提也会随之改变。因此,重构的能力是设计系统时要考虑的另一关键问题。


领域驱动设计(DDD)是关键,在我们看来,这是设计微服务时必不可少的工具,无论是打破整体还是实施未开发项目。领域驱动的设计(Eric Evans在他的书中提出)是一组思想、原理和模式,可帮助基于业务领域的基础模型设计软件系统。开发人员和领域专家共同合作,以通用的通用语言创建业务模型。然后,他们将这些模型绑定到有意义的系统,并在这些系统与从事这些服务的团队之间建立协作协议。更重要的是,他们设计了系统之间的概念轮廓或边界。


微服务设计从这些概念中汲取了灵感,因为所有这些原理都有助于构建可以相互独立变化和发展的模块化系统。


在继续进行之前,让我们快速了解一下DDD的一些基本术语。域驱动设计的完整概述超出了本博客的范围。我们强烈建议任何尝试构建微服务的人推荐Eric Evans的书籍。


领域:代表组织的工作。例如它是零售或电子商务。


子域:组织或组织内的业务部门。域由多个子域组成。


无所不在的语言:这是用于表达模型的语言。在下面的示例中,Item是一个模型,属于这些子域中每个子域的通用语言。开发人员,产品经理,领域专家和业务涉众都同意使用相同的语言,并在其工件(代码,产品文档等)中使用该语言。


有界上下文:域驱动的设计将有界上下文定义为“单词或语句能确定其含义的设置”。简而言之,这意味着模型是有意义的边界。在上面的示例中,“项目”在每种上下文中的含义不同。在目录上下文中,项目表示可售产品,而在购物车上下文中,则表示客户已将其添加到购物车中的项目。在“运输”上下文中,它表示将要运送给客户的仓库物料。这些模型中的每一个都是不同的,并且每个都有不同的含义,并且可能包含不同的属性。通过将这些模型分离并隔离在它们各自的边界内,我们可以自由地表达模型而没有歧义。


注意:必须了解子域和有界上下文之间的区别。子域属于问题空间,即您的企业如何看待问题,而受限上下文属于解决方案空间,即我们将如何实施问题的解决方案。从理论上讲,每个子域可能具有多个有界上下文,尽管我们努力为每个子域提供一个有界上下文。


微服务与有限上下文如何相关


现在,微服务在哪里适合?可以说每个有界上下文都映射到微服务吗?是的,我们将明白为什么。在某些情况下,有界上下文的边界或轮廓可能很大。


image.png


考虑上面的例子。定价绑定上下文具有三个不同的模型-价格,定价项目和折扣,每个模型负责目录项目的价格,计算项目列表的总价格并分别应用折扣。我们可以创建一个包含以上所有模型的系统,但是它可能会成为一个不合理的大型应用程序。如前所述,每个数据模型都有其不变性和业务规则。随着时间的流逝,如果我们不小心的话,系统可能会变成一个泥泞的大球,边界模糊,职责重叠,甚至可能回到我们开始的地方—一个整体。


对系统进行建模的另一种方法是将相关模型分离或分组为单独的微服务。在DDD中,这些模型(价格,定价项目和折扣)被称为聚合Aggregates。聚合是组成相关模型的独立模型。您只能通过已发布的界面更改聚合的状态,并且聚合可确保一致性,并且不变量保持良好状态。


聚合是关联对象的集群,被视为数据更改的单元。外部引用仅限于AGGREGATE的一个成员,称为根。一组一致性规则适用于AGGREGATE的边界。


image.png


同样,没有必要一定要将每个聚合建模为一个独特的微服务。图中的服务(聚合)是一对一关系,但这不一定是规则。在某些情况下,在单个服务中托管多个聚合可能是有意义的,尤其是当我们不完全了解业务领域时。需要注意的重要一点是,只能在单个聚合中保证一致性,并且只能通过已发布的界面修改聚合。任何违反这些规定的行为都有变成大泥球的风险。


上下文映射—精确划分微服务边界的一种方法


整体结构通常由不同的模型组成,大多数模型是紧密耦合的-模型可能知道彼此的亲密细节,更改一个模型可能会对另一个模型产生副作用,依此类推。分解整体时,确定这些模型(在这种情况下为集合)及其关系至关重要。上下文映射可以帮助我们做到这一点。它们用于标识和定义各种有界上下文和聚合之间的关系。在上面的示例中,有界上下文定义了模型的边界(价格,折扣等),而上下文映射定义了这些模型之间以及不同有界上下文之间的关系。


上下文映射的完整探索不在本博客的讨论范围之内,但我们将通过一个示例进行说明。下图显示了处理电子商务订单付款的各种应用程序。


购物车上下文负责订单的在线授权;订单上下文流程过帐付款后的付款流程;联络中心会处理所有例外情况,例如重试付款和更改用于订单的付款方式

为了简单起见,让我们假设所有这些上下文都是作为单独的服务实现的

所有这些上下文封装了相同的模型。

请注意,这些模型在逻辑上是相同的。也就是说,它们都遵循相同的通用域语言-付款方式,授权和结算。只是它们是不同上下文的一部分。

重新定义服务边界—将聚合映射到正确的上下文


错误案例如下图:


image.png


电子商务中所有模型都直接与单个支付聚合的网关上下文(payment gateway context)集成,支付需要保证事务性,但是由于与多个服务集成,支付的事务性就不能通过在各种服务之间强制执行不变性和一致性来实现,(banq注:当然有人就提出分布式事务的概念来在这些不同服务之间实现支付过程的事务性,这其实是在错误设计基础上的伪概念)。


请注意,支付网关中的任何更改都将迫使更改多个服务,并可能更改多个团队,因为不同的组可以拥有这些上下文。


进行一些调整并使聚合与正确的上下文对齐,我们可以更好地表示这些子域如下图。发生了很多变化。让我们回顾一下更改:


image.png


通常,整体(单体)或遗留应用程序具有许多聚合,通常具有重叠的边界。创建这些聚合及其依赖关系的上下文地图有助于我们了解将要从这些整体中摆脱出来的任何新微服务的轮廓。请记住,微服务架构的成功或失败取决于聚合之间的低耦合以及这些聚合之间的高内聚性。


同样重要的是要注意,有界上下文本身就是合适的内聚单元。即使上下文具有多个聚合,整个上下文及其聚合也可以组成一个微服务。我们发现这种启发式方法对于有些晦涩的领域特别有用-考虑组织正在涉足的新业务领域。您可能对分离的正确边界没有足够的了解,并且聚集体的任何过早分解都可能导致昂贵的重构。想象一下,由于数据迁移,不得不将两个数据库合并为一个,因为我们偶然发现两个聚合属于同一类。但是请确保通过接口将这些聚合充分隔离,以使它们不知道彼此的复杂细节。



相关文章
|
1月前
|
监控 API 开发者
深入理解微服务架构:构建可扩展的应用程序
【10月更文挑战第6天】深入理解微服务架构:构建可扩展的应用程序
43 0
|
5天前
|
运维 Kubernetes Docker
利用Docker和Kubernetes构建微服务架构
利用Docker和Kubernetes构建微服务架构
|
12天前
|
运维 持续交付 API
从零构建微服务架构:一次深度技术探索之旅####
【10月更文挑战第28天】 本文记录了作者在从零开始构建微服务架构过程中的深刻技术感悟,通过实战案例详细剖析了微服务设计、开发、部署及运维中的关键要点与挑战。文章首先概述了微服务架构的核心理念及其对企业IT架构转型的重要性,随后深入探讨了服务拆分策略、API网关选型、服务间通信协议选择、容器化部署(Docker+Kubernetes)、以及持续集成/持续部署(CI/CD)流程的设计与优化。最后,分享了在高并发场景下的性能调优经验与故障排查心得,旨在为读者提供一套可借鉴的微服务架构实施路径。 ####
49 3
|
26天前
|
监控 持续交付 API
深入理解微服务架构:构建高效、可扩展的系统
【10月更文挑战第14天】深入理解微服务架构:构建高效、可扩展的系统
77 0
|
1月前
|
消息中间件 监控 API
理解微服务架构:构建灵活和可扩展的应用
【10月更文挑战第7天】理解微服务架构:构建灵活和可扩展的应用
|
1月前
|
消息中间件 监控 API
深入理解微服务架构:构建可扩展与灵活的应用
【10月更文挑战第7天】深入理解微服务架构:构建可扩展与灵活的应用
40 0
|
2月前
|
运维 Kubernetes Cloud Native
云原生时代下,如何高效构建与部署微服务
【9月更文挑战第8天】随着云计算技术的飞速发展,云原生已成为现代软件架构的重要趋势。本文将深入浅出地介绍云原生概念、微服务架构的优势以及如何在云平台上高效构建和部署微服务。我们将通过实际的代码示例,展示在Kubernetes集群上部署一个简单的微服务应用的过程,帮助读者理解云原生环境下的微服务开发和运维实践。
|
20天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
19天前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
45 9
|
20天前
|
Kubernetes 负载均衡 Docker
构建高效微服务架构:Docker与Kubernetes的完美搭档
本文介绍了Docker和Kubernetes在构建高效微服务架构中的应用,涵盖基本概念、在微服务架构中的作用及其实现方法。通过具体实例,如用户服务、商品服务和订单服务,展示了如何利用Docker和Kubernetes实现服务的打包、部署、扩展及管理,确保微服务架构的稳定性和可靠性。
68 7