目录
前言:
逻辑视图架构风格
一、分层式架构风格
二、六边形架构
如何定义微服务架构
微服务的拆分
业务能力进行服务拆分
子域进行服务拆分
拆分的原则
单一职责
闭包原则
前言:
我们在软件开发的时候一直在谈论架构,那么什么是架构呢?计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、它们之间的关系以及两者的属性,简单来说就是元素和元素之间的关系。它的目标是可扩展性、可靠性、安全性、可维护性、可测试性以及可部署性并且可以快速的交付,为了实现上述目标,分解就特别的重要。接下来将详细阐述微服务的拆分。
说到软件架构不得不提到软件架构的4+1视图模型:
每个视图有以下的目的:
逻辑视图:开发人员创建的软件元素。在面向对象的语言中,这些元素是类和包。它们之间的关系是类和包之间的关系,包括继承、关联和依赖
实现视图:构建编译系统的输出。此视图由表示打包代码的模块和组件组成,组件是由一个或多个模块组成的可执行或可部署单元。
进程视图:运行时的组件。每个元素都是一个进程,进程之问的关系代表进程问通信。
部署视图:进程如何映射到机器。此视图中的元素由(物理或虚拟)计算机和进程组成。机器之间的关系代表网络。该视图还描述了进程和机器之间的关系。
除了这四个视图以外,4+1 中的+1是这场景,它负责把视图串联起来。是从不同维度去考虑的,每个场景负责描述在一个视图中的多个架构元素如何协作,以完成一个请求。
逻辑视图有两种经典的架构风格
逻辑视图架构风格
一、分层式架构风格
分层架构将软件元素按“层”的方式组织。每个层都有明确的职责。分层架构还限制了层之间的依赖关系。分层架构应用于前面讨论的四个视图中的任何一个。今天我们提到的三层架构是应用于逻辑视图的分层架构。它将应用程序的类组织到以下层中。
表现层:包括实现用户界面或外部API的代码 业务逻辑层:包含业务逻辑 数据持久化层:实现和数据库交互的逻辑
这种架构模式也就是我们常说的MVC,V就是表现层,C就是业务逻辑层,M就是model 层,这种架构有什么缺点呢?
我们先从表现层来说,它无法实现多个系统调用的事实。单一数据持久化层,无法展现应用程序与多个数据库进行交互的事实同时由于C依赖于M,将妨碍你在没有数据库的情况下测试业务逻辑。
二、六边形架构
六边形架构风格选择以业务逻辑为中心的方式组织逻辑视图。应用程序具有一个或多个人站适配器,而不是表示层,它通过调用业务逻辑来处理来自外部的请求。同样,应用程序具有一个或多个出站适配器,而不是数据持久化层,这些出站适配器由业务逻辑调用并调用外部应用程序。此架构的一个关键特性和优点是业务逻辑不依赖适配器,相反适配器依赖于业务逻辑。
对于业务逻辑来说它有两种端口:入站和出站端口。入站端口是业务逻辑公开的API,它使外部应用程序可以调用它。主要是入站适配器调用它完成一次请求,出站端口的一个实例是存储库接口,调用出站适配器比如说DAO层完成数据的存储。
业务逻辑的周围是适配器。与端口一样,有两种类型的程配器:人站和出站。人站适配器通过调用入站端口来处理来自外部世界的请求。人站适配器的一个实例是 MVCController,它实现一组 REST接口 (endpoint)或一组-Web 页面。另一个实例是订阅消息的消息代理客户端。多个人站适配器可以调用相同的人站端口。
出站适配器实现出站端口并通过调用外部应用程序或服务处理来自业务逻辑的请求。
出站适配器的一个实例是实现访问数据库的操作的数据访问对象(DAO)类。另一个实例是调用远程服务的代理类。出站适配器可以发布事件。
六边形架构风格的一个重要好处是它将业务逻辑与适配器中包含的表示层和数据访回层的逻辑分离开来。业务逻辑不依赖于表示层逻辑或数据访问层逻辑。
由于这种分离,单独测试业务逻辑要容易得多。另一个好处是它更准确地反映了现代应用程序的架构。可以通过多个适配器调用业务逻辑,每个适配器实现特定的API 或用户界面。业务逻辑还可以调用多个适配器,每个适配器调用不同的外部系统。六边形架构是描述微服务架构中每个服务的架构的好方法。
分层架构和六边形架构都是架构风格的实例。每个都定义了架构的构建块(元素),并对它们之间的关系施加了约束。六边形架构和分层架构(三层架构)构成了软件的逻辑视图。
现在让我们将微服务架构定义为构成软件的实现视图的架构风格。
如何定义微服务架构
如何定义微服务架构可以遵循以下步骤:
-
阅读需求文档提炼关键词,定义系统操作,系统操作一般分为两大类查询数据和修改数据
-
定义服务也就是服务的拆分
-
定义服务api 以及协作方式也就是服务的通信方式
系统操作(system operation)是应用程序必须处理的请求的一种抽象描述。它既可以是更新数据的命令,也可以是检索数据的查询。每个命令的行为都是根据抽象领城模型定义的,抽象领域模型也是从需求中派生出来的。系统操作是猫述服务之间协作方式的架构场景。
该流程的第二步是确定如何分解服务。有几种策略可供选择。一种源于业务架构学派的维略是定义与业务能力相对应的服务。真一种策略是围绕领域驱动设计的子域来分解和设计服务。但这些策略的最终结果都是围绕业务概念而非技术概念分解和设计的服务。
定义应用程序架构的第三步是确定每个服务的API。为此,你将第一步中标识的每个系统操作分配给服务。服务可以完全独立地实现操作。或者,它可能需要与其他服务协作。在这种情况下,你可以确定服务的协作方式,这通常需要服务来支持其他操作。
服务的分解有几个障碍需要克服。首先是网络延返。你可能会发现,由于服务之间的网络往返太多,特定的分解将是不切实际的。分解的另一个障碍是服务之间的同步通信降低了可用性。你可能需要使用自包含服务的概念。第三个障碍是需要维护跨服务的数据一致性。你需要使用 Saga模式等分布式事务解决。分解的第四个也是最后一个障碍是所谓的上帝类(God Class),它广泛应用在整个应用程序中。幸运的是,你可以使用领域驱动设计中的概念来消除上帝类。
微服务的拆分
业务能力进行服务拆分
业务能力定义了一个组织的工作,组织的业务能力通常是指这个组织的业务是做什么,通常具有稳定性,比如说银行他有一种汇款的业务,这个业务具有稳定性,随着社会的变革现在可以通过支票到银行汇款,也可以通过银行卡到ATM 上,还可以通过app。实现能力实现的方式发生了戏剧性的变化。
一个组织有哪些业务能力呢,是通过对组织的目标、结构和商业流程的分析得来的。每一个业务能力都可以被认为是一个服务。业务能力的规范包含多项元素,不如输入和输出、服务等级协议(SLA)。
业务能力通常集中在特定的业务对象上。例如,理赔业务对象是理赔管理功能的重点。能力通常可以分解为子能力。例如,理赔管理能力具有多个年能力,包括理赔信息管理、理赔审核和理赔付款管理。
这个比较抽象我们可以拿美团外卖进行一个详细的讲解:
第一步我们要列出业务能力,业务复杂化,不仅有顶级业务能力,有二级业务能力,甚至还有三级业务能力
把FTGO 的业务能力逐一列出来似乎也并不太困难,如下所示。
-
供应商管理。
. courier management:送餐员相关信息管理;
. Restaurant information management:餐馆菜单和其他信息管理,例如营业地址和时间。
-
消费者管理:消费者有关信息的管理。
-
订单获取和履行。
. Order management:让消费者可以创建和管理订单。
. Restaurant order management:让餐馆可以管理订单的生产过程。
. 送餐。
. Courier availability management:管理送餐员的实时状态。
. Delivery management:把订单送到用户手中。
-
会计记账。
. Consumer accounting:管理跟消费者相关的会计记账。
. Restaurant accounting:管理跟餐馆相关的会计记账。
. Courier accounting:管理跟送餐员相关的会计记账。
任务列表下表示一级能力 . 表示二级能力。业务能力我们划分了,现在我们可以根据业务能力划分服务。划分方式有很多,可以把一个一级能力单独划一个服务比如说会计记账,所有的会计记账都是相似的。也可以把一级业务能力下的二级业务能力划分多个服务,比如说,我把供应商管理的子能力映射到两种服务,因为餐馆和送餐员是非常不同的供应商
围绕能力组织服务的一个关键好处是相对稳定的,除非一个组织有新的业务能力,不然业务能力是不会变化的,最终的架构也相对稳定。但是随着业务的发展会发现过多的服务之间的通信效率低下,必须把一些服务组织在一起。还有可能一些依靠业务的服务过于庞大,我们可能会拆分成多个服务。
子域进行服务拆分
领域模型会被紧密地映射到应用的设计和实现环节。
在微服务架构的设计层面,DDD 有两个特别重要的概念,子域和限界上下文。
传统的企业架构建模方式往往会为整个企业建立一个单独的模型,DDD 则采取了完全不同的方式。在这样的模型中,会有适用于整个应用全局的业务实体定义,例如客户或订单。
这类传统建模方式的挑战在干,让组织内的所有团队都对全局单一的建模和术语定义达成一致是非常困难的。另外,对于组织中的特定团队而言,这个单一的业务实体定义可能过于复杂,超出了他们的需求。此外,这些传统的领域模型可能会造成混乱,因为组织内有些因队可能针对不同的概念使用相同的术语,而也有些团队会针对同一个概念使用不同的术语。
DDD 通过定义多个领域模型来避免这个问题,每个领域模型都有明确的范围。
领域驱动为每一个子域定义单独的领域模型。子域是领域的一部分,领域是 DDD 中用来描述应用程序问题域的一个术语。识别子域的方式跟识别业务能力一样:分析业务并识别业务的不同专业领域,分析产出的子域定义结果也会跟业务能力非常接近。外卖的子域包括:订单获取、订单管理、餐馆等理、送餐和会计。正如你所见:这些子域跟我们之前定义的业务能力非常接近。
DDD 把领域模型的边界称为限界上下文 (bounded context)。限界上下文包括实现这个模型的代码集合。当使用微服务架构时,每一个限界上下文对应一个或者一组服务。换一种说法,我们可以通过 DDD的方式定义子域,并把子域对应为每一个服务,这样就完成了微服务架构的设计工作。
DDD 和微服务架构简直就是天生一对。DDD 的子域和限界上下文的概念,可以很好地跟微服务架构中的服务进行匹配。而且,微服务架构中的自治化团队负责服务开发的概念,也跟 DDD 中每个领域模型都由一个独立团队负责开发的概念吻合。更有趣的是,子域用于它自己的领域模型这个概念,为消除上帝类和优化服务拆分提供了好办法。
按子域分解和按业务能力分解是定义应用程序的微服务架构的两种主要模式。但是,也有一些有用的拆分指导原则源于面向对象的设计我们来详细讨论这些原则。
拆分的原则
拆分遵循两个原则
-
SRP(单一职责)
-
CCP (闭包原则)
下面我们详细解决这两个原则
单一职责
类所承载的每一个职责都是对它进行修改的潜在原因。如果一个类承载了多个职责,并且互相之间的修改是独立的,那么这个类就会变得非常不稳定。遵照 SRP 原则,你所定义的每一个类都应该只有一个职责,因此也就只有一个理由对它进行修改。
我们在设计微服务架构时应该遵循SRP 原则,设计小的、内聚的、仅仅含有单一职责的服务。这会缩小服务的大小并提升它的稳定性。新的外卖架构是应用SRP 的一个例子。为客户获取餐食的每一个方面(订单获取、订单准备、送餐等)都由一个单一的服务承载。
闭包原则
如果由于某些原因,两个类的修改必须耦合先后发生,那么就应该把它们放在同一个包内。也许,这些类实现了一些特定的业务规则的不同方面。这样做的目标是当业务规则发生变化时,开发者只需要对一个交付包做出修改,而不是大规模地修改(和重新编译)整个应用。采用闭包原则,极大地改善了应用程序的可维护性。
在微服务架构下采用CCP 原则,这样我们就能把根据同样原因进行变化的服务放在一个组件内。这样做可以控制服务的数量,当需求发生变化时,变更和部署也更加容易。理想情况下,一个变更只会影响一个团队和一个服务。CCP 是解决分布式单体这种可怕的反模式的法宝。