当前位置:主页 > 技术文章 >

技术文章

Technical articles

服务的拆分计谋

时间:2021-04-28 00:21 点击次数:
  本文摘要:2.1微服务架构到底是什么第1章形貌了微服务架构的关键思想是如何举行功效剖析。你可以将应用法式构建为一组服务,而不是开发一个大行的单体应用法式。一方面,将微服务架构形貌为一种功效剖析是有用的。 但另一方面,它留下了几个未解决的问题,包罗:微服务架构如何与更广泛的软件架构观点相联合?什么是服务?服务的规模有多重要?为了回覆这些问题,我们需要退后一步,看看软件架构的寄义。软件的架构是一种抽象的结构,它由软件的各个组成部门和这些部门之间的依赖关系组成。

华体会官网

2.1微服务架构到底是什么第1章形貌了微服务架构的关键思想是如何举行功效剖析。你可以将应用法式构建为一组服务,而不是开发一个大行的单体应用法式。一方面,将微服务架构形貌为一种功效剖析是有用的。

但另一方面,它留下了几个未解决的问题,包罗:微服务架构如何与更广泛的软件架构观点相联合?什么是服务?服务的规模有多重要?为了回覆这些问题,我们需要退后一步,看看软件架构的寄义。软件的架构是一种抽象的结构,它由软件的各个组成部门和这些部门之间的依赖关系组成。正如你将在本节中看到的,软件的架构是多维的,因此有多种方法可以对其举行形貌。架构很重要的原因是它决议了应用法式的质量属性或能力。

传统上,架构的目的是可扩展性、可靠性和宁静性。可是今天,该架构能够快速宁静地交付软件,这一点很是重要。你将相识微服务架构是一种架构气势派头,可为应用法式提供更高的可维护性、可测试性和可部署性。

我将通过形貌软件架构的观点及其重要性来开始本节。接下来,我将讨论架构气势派头的观点。

然后我将微服务架构界说为特定的架构气势派头。让我们从明白软件架构的观点开始。2.1.1软件架构是什么,为什么它如此重要架构显然很重要。

至少有两个专门讨论该主题的集会:Oreilly的软件架构集会和SATURN集会。许多开发人员的目的是成为一名架构师。但什么是架构,为什么它如此重要?为了回覆这个问题,我首先界说术语软件架构的寄义。

之后,我将讨论应用法式的架构是多维的,并使用一组视图或蓝图举行形貌。然后我将强调软件架构的重要性,因为它对应用法式的质量属性有显著的影响。软件架构的界说软件架构有许多界说。

例如,维基百科上枚举了大量的界说。我最喜欢的界说来自卡耐基梅隆大学软件工程研究所(www.sei.cmu.edu)的Len Bass及其同事,他们在使软件架组成为一门学科方面发挥了关键作用。他们界说的软件架构如下:盘算机系统的软件架构是构建这个系统所需要的一组结构,包罗软件元素、它们之间的关系以及两者的属性。—Bass等著《Documenting Software Architectures: Views and Beyond》这显然是一个很是抽象的界说。

但其实质是应用法式的架构是将软件剖析为元素(element)和这些元素之间的关系(relation)。由于以下两个原因,剖析很重要:它促进了劳动和知识的分工。

它使具有特定专业知识的人们(或多个团队)能够就应用法式高效地协同事情。它界说了软件元素的交互方式。

将软件剖析成元素以及界说这些元素之间的关系,决议了软件的能力。软件架构的4+1视图模型从更详细的角度而言,应用法式的架构可以从多个视角来看,就像修建架构,一般有结构、管线、电气等多个架构视角。

Phillip Krutchen在他经典的论文《Architectural Blueprints —The 4+1 View Model of Software Architecture》中提出了软件架构的4+1视图。图2-1展示的这套视图界说了四个差别的软件架构视图,每一个视图都只形貌架构的一个特定方面。每个视图包罗一些特定的软件元素和它们相互之间的关系。

每个视图的目的如下:逻辑视图:开发人员建立的软件元素。在面向工具的语言中,这些元素是类和包。

它们之间的关系是类和包之间的关系,包罗继续、关联和依赖。实现视图:构建编译系统的输出。

此视图由表现打包代码的模块和组件组成,组件是由一个或多个模块组成的可执行或可部署单元。在Java中,模块是JAR文件,组件通常是WAR文件或可执行JAR文件。它们之间的关系包罗模块之间的依赖关系以及组件和模块之间的组合关系。

历程视图:运行时的组件。每个元素都是一个历程,历程之间的关系代表历程间通信。部署视图:历程如何映射到机械。此视图中的元素由(物理或虚拟)盘算机和历程组成。

机械之间的关系代表网络。该视图还形貌了历程和机械之间的关系。除了这四个视图以外,4+1中的+1是指场景,它卖力把视图串联在一起。每个场景卖力形貌在一个视图中的多个架构元素如何协作,以完成一个请求。

例如,在逻辑视图中的场景,展现了类是如何协作的。同样,在历程视图中的场景,展现了历程是如何协作的。4+1视图是形貌应用法式架构的绝佳方式。每一个视图都形貌了架构的一个重要侧面。

场景把视图中的元素如何协作串联在一起。现在我们来看看为什么架构是如此重要。为什么架构如此重要应用法式有两个层面的需求。

第一类是功效性需求,这些需求决议一个应用法式做什么。这些通常都包罗在用例(use case)或者用户故事(user story)中。应用的架构其实跟这些功效性需求没什么关系。

功效性需求可以通过任意的架构来实现,甚至是很是糟糕的大泥球架构。架构的重要性在于,它资助应用法式满足了第二类需求:非功效性需求。我们把这类需求也称之为质量属性需求,或者简称为“能力”。

这些非功效性需求决议一个应用法式在运行时的质量,好比可扩展性和可靠性。它们也决议了开发阶段的质量,包罗可维护性、可测试性、可扩展性和可部署性。为应用法式所选择的架构将决议这些质量属性。

2.1.2什么是架构的气势派头在物理世界中,修建物的修建通常遵循特定的气势派头,例如维多利亚式、美国工匠式或装饰艺术式。每种气势派头都是一系列设计决议,限制了修建的特征和修建质料。修建气势派头的观点也适用于软件。

David Garlan和Mary Shaw(An Introduction to Software Architecture,January 1994)这两位软件架构学科的先驱界说了如下架构气势派头 :因此,架构气势派头凭据结构组织模式界说了一系列此类系统。更详细地说,架构气势派头确定可以在该气势派头的实例中使用的组件和毗连器的词汇表,以及关于如何组合它们的一组约束。特定的架构气势派头提供了有限的元素(组件)和关系(毗连器),你可以从中界说应用法式架构的视图。

应用法式通常使用多种架构气势派头的组合。例如,在本节的后面,我将形貌单体架构是如何将实现视图结构为单个(可执行与可部署)组件的架构样式。微服务架构将应用法式结构为一组松散耦合的服务。

分层式架构气势派头架构的典型例子是分层架构。分层架构将软件元素按“层”的方式组织。

每个层都有明确界说的职责。分层架构还限制了层之间的依赖关系。每一层只能依赖于紧邻其下方的层(如果严格分层)或其下面的任何层。

可以将分层架构应用于前面讨论的四个视图中的任何一个。盛行的三层架构是应用于逻辑视图的分层架构。它将应用法式的类组织到以下层中:体现层:包罗实现用户界面或外部API的代码。- 业务逻辑层:包罗业务逻辑。

数据持久化层:实现与数据库交互的逻辑。分层架构是架构气势派头的一个很好的例子,但它确实有一些显着的毛病:- 单个体现层:它无法展现应用法式可能不仅仅由单个系统挪用的事实。

单一数据持久化层:它无法展现应用法式可能与多个数据库举行交互的事实。将业务逻辑层界说为依赖于数据持久化层:理论上,这样的依赖性会故障你在没有数据库的情况下测试业务逻辑。此外,分层架构错误地表现了经心设计的应用法式中的依赖关系。

业务逻辑通常界说数据会见方法的接口或接口库。数据持久化层则界说了实现存储库接口的DAO类。换句话说,依赖关系与分层架构所形貌的相反。

让我们看一下克服这些毛病的替代架构:六边形架构。关于架构气势派头的六边形六边形架构是分层架构气势派头的替代品。

如图2-2所示,六边形架构气势派头选择以业务逻辑为中心的方式组织逻辑视图。应用法式具有一个或多个入站适配器,而不是表现层,它通过挪用业务逻辑来处置惩罚来自外部的请求。同样,应用法式具有一个或多个出站适配器,而不是数据持久化层,这些出站适配器由业务逻辑挪用并挪用外部应用法式。此架构的一个关键特性和优点是业务逻辑不依赖于适配器。

相反,种种适配器都依赖业务逻辑。业务逻辑具有一个或多个端口(port)。端口界说了一组操作,关于业务逻辑如何与外部交互。例如,在Java中,端口通常是Java接口。

有两种端口:入站和出站端口。入站端口是业务逻辑公然的API,它使外部应用法式可以挪用它。入站端口的一个实例是服务接口,它界说服务的公共方法。

出站端口是业务逻辑挪用外部系统的方式。出站端口的一个实例是存储库接口,它界说数据会见操作的荟萃。业务逻辑的周围是适配器。

与端口一样,有两种类型的适配器:入站和出站。入站适配器通过挪用入站端口来处置惩罚来自外部世界的请求。入站适配器的一个实例是Spring MVC Controller,它实现一组REST接口(endpoint)或一组Web页面。

另一个实例是订阅消息的消息署理客户端。多个入站适配器可以挪用相同的入站端口。出站适配器实现出站端口,并通过挪用外部应用法式或服务处置惩罚来自业务逻辑的请求。

出站适配器的一个实例是实现会见数据库的操作的数据会见工具(DAO)类。另一个实例是挪用远程服务的署理类。出站适配器也可以公布事件。六边形架构气势派头的一个重要利益是它将业务逻辑与适配器中包罗的表现层和数据会见层的逻辑分散开来。

业务逻辑不依赖于表现层逻辑或数据会见层逻辑。由于这种分散,单独测试业务逻辑要容易得多。另一个利益是它更准确地反映了现代应用法式的架构。

可以通过多个适配器挪用业务逻辑,每个适配器实现特定的API或用户界面。业务逻辑还可以挪用多个适配器,每个适配器挪用差别的外部系统。

六边形架构是形貌微服务架构中每个服务的架构的好方法。分层架构和六边形架构都是架构气势派头的实例。每个都界说了架构的构建块(元素),并对它们之间的关系施加了约束。六边形架构和分层架构(三层架构)组成了软件的逻辑视图。

现在让我们将微服务架构界说为组成软件的实现视图的架构气势派头。2.1.3微服务架构是一种架构气势派头前面已经讨论过4+1视图模型和架构气势派头,所以现在可以开始界说单体架构和微服务架构。

它们都是架构气势派头。单体架构是一种架构气势派头,它的实现视图是单个组件:单个可执行文件或WAR文件。

这个界说并没有说明其他的视图。例如,单体应用法式可以具有六边形架构气势派头的逻辑视图。

微服务架构也是一种架构气势派头。它的实现视图由多个组件组成:一组可执行文件或WAR文件。它的组件是服务,毗连器是使这些服务能够协作的通信协议。

每个服务都有自己的逻辑视图架构,通常也是六边形架构。图2-3显示了FTGO应用法式可能的微服务架构。此架构中的服务对应于业务功效,例如订单治理和餐馆治理。在本章后面,我将形貌业务能力(business capability)的寄义。

服务之间的毗连器使用历程间通信机制(如REST API和异步消息)实现。第3章将更详细地讨论历程间通信。微服务架构强加的一个关键约束是服务松耦合。

因此,服务之间的协作方式存在一定限制。为相识释这些限制,我将实验界说什么是服务,解释松耦合意味着什么,并告诉你为什么这很重要。什么是服务服务是一个单一的、可独立部署的软件组件,它实现了一些有用的功效。

图2-4显示了服务的外部视图,在此示例中是Order Service。服务具有API,为其客户端提供多功效的会见。有两种类型的操作:下令和查询。

API由下令、查询和事件组成。下令如createOrder()执行操作并更新数据。

查询,如findOrderById()检索数据。服务还公布由其客户端使用的事件,例如OrderCreated。

服务的API封装了其内部实现。与单体架构差别,开发人员无法绕过服务的API直接会见服务内部的方法或数据。因此,微服务架构强制实现了应用法式的模块化。

微服务架构中的每项服务都有自己的架构,可能另有奇特的技术栈。可是典型的服务往往都具有六边形架构。

其API由与服务的业务逻辑交互的适配器实现。操作适配器挪用业务逻辑,事件适配器对外公布业务逻辑发生的事件。

API界说了由客户端挪用的操作。有两种类型的操作:下令用来更新数据,查询用来检索数据。当服务的数据发生更改时,服务会公布可供客户端订阅的事件在第12章讨论部署技术时,你将看到服务的实现视图可以接纳多种形式。

该组件可以是独立历程,在容器中运行的Web应用法式或OSGI包、云主机或Serverless技术,等等。可是,一个基本要求是服务具有API而且可以独立部署。什么是松耦合微服务架构的最焦点特性是服务之间的松耦合性(https://en.wikipedia.org/wiki/Loose_coupling)。

服务之间的交互接纳API完成,这样做就封装了服务的实现细节。这允许服务在不影响客户端的情况下,对实现方式做出修改。松耦合服务是改善开发效率、提升可维护性和可测试性的关键。小的、松耦合的服务更容易被明白、修改和测试。

我们通过API来实现松耦合服务之间的协调挪用,这样就制止了外界对服务的数据库的直接会见和挪用。服务自身的持久化数据就如同类的私有属性一样,是差池外的。保证数据的私有属性是实现松耦合的前提之一。

这样做,就允许开发者修改服务的数据结构,而不用提前与其他服务的开发者相互协商。这样做在运行时也实现了更好的隔离。例如,一个服务的数据库加锁不会影响另外的服务。可是你稍后就会看到在服务间不共享数据库的毛病,特别是处置惩罚数据一致性和跨服务查询都变得更为庞大。

共享类库的角色开发人员经常把一些通用的功效打包到库或模块中,以便多个应用法式可以重用它而无须复制代码。究竟,如果没有Maven或npm库,我们今天的开发事情都市变得更难题。你可能也想在微服务架构中使用共享库。

从外貌上看,它似乎是淘汰服务中代码重复的好方法。可是你需要确保不会意外地在服务之间引入耦合。

例如,想象一下多个服务需要更新Order业务工具的场景。一种选择是将该功效打包为可供多个服务使用的库。

一方面,使用库可以消除代码重复。另一方面,如果业务需求的变换影响了Order业务工具,开发者需要同时重建和重新部署所有使用了共享库的服务。更好的选择是把这些可能会更改的通用功效(例如Order治理)作为服务来实现,而不是共享库。

你应该努力使用共享库来实现不太可能改变的功效。例如,在典型的应用法式中,在每个服务中都实现一个通用的Money类(例如用来实现币种转换等牢固功效)没有任何意义。相反,你应该建立一个供所有服务使用的共享库。服务的巨细并不重要微服务这个术语的一个问题是会将你的关注点错误地聚焦在微上。

它表示服务应该很是小。其他基于巨细的术语(如miniservice或nanoservice)也是如此。

实际上,巨细不是一个重要的思量因素。更好的目的是将经心设计的服务界说为能够由小团队开发的服务,而且交付时间最短,与其他团队协作最少。理论上,团队可能只卖力单一服务,因此服务绝不是微小的。

相反,如果服务需要大型团队或需要很长时间举行测试,那么拆分团队或服务可能是有意义的。另外,如果你因为其他服务的变换而不停需要同步更新自己卖力的服务,或者你所卖力的服务正在触发其他服务的同步更新,那么这讲明服务没有实现松耦合。你构建的甚至可能是一个漫衍式的单体。

微服务架构把应用法式通过一些小的、松耦合的服务组织在一起。效果,这样的架构提升了开发阶段的效率,特别是可维护性、可测试性和可部署性,这也就让组织的软件开发速度更快。微服务架构也同时提升了应用法式的可扩展性,只管这不是微服务的主要目的。为了使用微服务架构开发软件,你首先需要识别服务,并确定它们之间如何协作。

现在我们来看看如何界说一个应用法式的微服务架构。2.2为应用法式界说微服务架构那么如何界说一个微服务架构呢?跟所有的软件开发历程一样,一开始我们需要拿到领域专家或者现有应用的需求文档。

跟所有的软件开发一样,界说架构也是一项艺术而非技术。本节我们将先容一种界说应用法式架构的三步式流程,如图2-5所示。

世界上并没有一个机械化的流程可以遵循,然后指望这个流程输出一个合理的架构。我们只能先容一个或许的方法,现实世界中,这是一个不停迭代和连续创新的历程。

应用法式是用来处置惩罚客户端请求的,因此界说其架构的第一步是将应用法式的需求提炼为种种关键请求。可是,不是凭据特定的历程间通信技术(如REST或消息)来形貌这些请求,而是使用更抽象的系统操作这个观点。系统操作(system operation)是应用法式必须处置惩罚的请求的一种抽象形貌。

它既可以是更新数据的下令,也可以是检索数据的查询。每个下令的行为都是凭据抽象领域模型界说的,抽象领域模型也是从需求中派生出来的。系统操作是形貌服务之间协作方式的架构场景。

该流程的第二步是确定如何剖析服务。有几种计谋可供选择。一种源于业务架构学派的计谋是界说与业务能力相对应的服务。

另一种计谋是围绕领域驱动设计的子域来剖析和设计服务。但这些计谋的最终效果都是围绕业务观点而非技术观点剖析和设计的服务。界说应用法式架构的第三步是确定每个服务的API。

为此,你将第一步中标识的每个系统操作分配给服务。服务可以完全独立地实现操作。或者,它可能需要与其他服务协作。

在这种情况下,你可以确定服务的协作方式,这通常需要服务来支持其他操作。你还需要确定选用第3章中形貌的哪种历程间通信机制来实现每个服务的API。

服务的剖析有几个障碍需要克服。首先是网络延迟。你可能会发现,由于服务之间的网络往返太多,特定的剖析将是不切实际的。

剖析的另一个障碍是服务之间的同步通信降低了可用性。你可能需要使用第3章中形貌的自包罗服务的观点。第三个障碍是需要维护跨服务的数据一致性。

你需要使用第4章中讨论的Saga。剖析的第四个也是最后一个障碍是所谓的上帝类(God Class),它广泛应用在整个应用法式中。

幸运的是,你可以使用领域驱动设计中的观点来消除上帝类。本节首先先容如何识别应用法式的系统操作。之后,会研究将应用法式剖析为服务的计谋和指南、剖析的障碍以及如何解决它们。

最后,将形貌如何界说每个服务的API。2.2.1识别系统操作界说应用法式架构的第一步是界说系统操作。起点是应用法式的需求,包罗用户故事及其相关的用户场景(请注意,这些与架构场景差别)。

使用图2-6中所示的两步式流程识别和界说系统操作。这个流程的灵感来自Craig Larman的名著《Applying UML and Patterns》(Prentice Hall,2004)中先容的面向工具设计历程(www.craiglarman.com/wiki/index.php?title=Book_Applying_UML_and_Patterns)。第一步建立由关键类组成的抽象领域模型,这些关键类提供用于形貌系统操作的词汇表。

第二步确定系统操作,并凭据领域模型形貌每个系统操作的行为。第一步是建立一个抽象领域模型。

第二步是界说系统操作,这些操作是凭据领域模型界说的领域模型主要源自用户故事中提及的名词,系统操作主要来自用户故事中提及的动词。你还可以使用名为事件风暴(Event Storming)的技术界说领域模型,我将在第5章中讨论。

每个系统操作的行为都是凭据它对一个或多个领域工具的影响以及它们之间的关系来形貌的。系统操作可以建立、更新或删除领域工具,以及建立或破坏它们之间的关系。

我们来看看如何界说抽象领域模型。之后,我将凭据领域模型界说系统操作。建立抽象领域模型界说系统操作的第一步是为这个应用法式描绘一个抽象的领域模型。

注意这个模型比我们最终要实现的简朴许多。应用法式自己并不需要一个领域模型,因为我们在稍后会学到,每一个服务都有它自己的领域模型。只管很是简朴,抽象的领域模型仍旧有助于在开始阶段提供资助,因为它界说了形貌系统操作行为的一些词语。建立领域模型会接纳一些尺度的技术,例如通过与领域专家相同后,分析用户故事和场景中频繁泛起的名词。

例如Place Order用户故事,我们可以把它剖析为多个用户场景,例如这个:在这个用户场景中的名词,如Consumer、Order、Restaurant和CreditCard,表示了这些类都是需要的。同样,Accept Order用户故事也可以剖析为多个场景,如下:这个场景表示需要Courier类和Delivery类。在经由频频迭代分析之后,效果显然就是这个领域模型应该包罗一些类,如MenuItem和Address等。图2-7显示了焦点类的类图。

每一个类的作用如下:Consumer:下订单的用户。Order:用户下的订单,它用来形貌订单并跟踪状态。OrderLineItem:Order中的一个条目。

DeliveryInfo:送餐的时间和地址。Restaurant:为用户准备生产订单的餐馆,同时也要提倡送货。MenuItem:餐馆菜单上的一个条目。Courier:送餐员卖力把订单送到用户手里。

可跟踪送餐员的可用性和他们的位置。Address:Consumer或Restaurant的地址。Location:Courier当前的位置,用经纬度表现。

类似图2-7这种类图形貌了应用法式架构的一个方面。但如果没有对应的场景,这个图也就是仅仅悦目而已,并不实用。下一步开始界说对应架构场景的系统操作。

界说系统操作当界说了抽象的领域模型之后,接下来就要识别系统必须处置惩罚的种种请求。我们并不讨论详细的用户界面,可是你能够想象在每一个用户场景下,前端的用户界面向后端的业务逻辑发出请求,后端的业务逻辑举行数据的获取和处置惩罚。

FTGO是一个Web应用,这意味着它的大部门请求都是基于HTTP的。但也有可能一些客户端会使用消息。相比绑定到详细的通信协议,使用抽象的词汇来形貌跟系统操作有关的请求更为合理。

有以下两种类型的系统操作。下令型:建立、更新或删除数据的系统操作。查询型:查询和读取数据的系统操作。从基础上说,这些系统操作都市对应到详细的REST、RPC或消息端口。

但现阶段我们不必在意这些实现细节。让我们先开始识别一些指令。识别系统指令的切入点是分析用户故事和场景中的动词。

例如Place Order用户故事,它很是明确地告诉架构师,这个系统必须提供一个Create Order操作。许多用户故事都市直接对应或映射为系统下令。

表2-1列出了一些关键的系统下令。下令规范界说了下令对应的参数、返回值和领域模型类的行为。行为规范中包罗前置条件(即当这个操作被挪用时必须满足的条件)和后置条件(即这个操作被挪用后必须满足的条件)。

例如,以下就是createOrder()系统操作的规范。前置条件对应着Place Order用户场景中的givens,后置条件对应着场景中的Then。当系统操作被挪用时,它会检查前置条件,执行操作来完成和满足后置条件。

下面是acceptOrder()的系统操作规范:前置条件和后置条件对应着之前用户场景中的形貌。多数与系统操作相关的架构元素是下令。查询虽然仅仅是简朴地获取数据,可是也同样重要。

应用法式除了实现指令以外,也必须实现查询。查询为用户决议提供了用户界面。在现在阶段,我们并没有开始为FTGO应用法式构想任何用户界面,可是需要注意,当消费者下订单时往往是如下所示的历程。

1.用户输入送餐地址和期望的送餐时间;2.系统显示当前可用的餐馆;3.用户选择餐馆;4.系统显示餐馆的菜单;5.用户点餐并结账;6.系统建立订单。这个用户场景包罗了以下的查询型操作:findAvailableRestaurants(deliveryAddress,deliveryTime):获取所有能够送餐到用户地址并满足送餐时间要求的餐馆。findRestaurantMenu(id):返回餐馆信息和这家餐馆的菜单项。

在这两项查询中,findAvailableRestaurants()也许是在架构层面尤其重要的一个。它是一个包罗了地理位置等信息的庞大查询。

地理查询的组件卖力找到送餐地址周围所有满足要求的餐馆位置。同时它也需要过滤那些在订单准备和送餐时间规模内没有营业的餐馆。另外,这个查询的性能尤其重要,因为执行这个查询时,客户多数都是“在线急等”的状态,延长不得。抽象的领域模型和系统操作能够回覆这个应用“做什么”这一问题。

这有助于推动应用法式的架构设计。每一个系统操作的行为都通过领域模型的方式来形貌。

每一个重要的系统操作都对应着架构层面的一个重大场景,是架构中需要详细形貌和特别思量的地方。现在我们来看看如何界说应用法式的微服务架构。

系统操作被界说后,下一步就是完成应用服务的识别。如之前提到的,这并不是一个机械化的流程,相反,有多种拆分计谋可供选择。每一种都是从一个侧面来解决问题,而且使用它们独占的一些术语。可是殊途同归,这些计谋的效果都是一样的:一个包罗若干服务的架构,这样的架构是以业务而不是技术观点为中心。

我们先来看看第一个计谋:使用业务能力来界说服务。2.2.2凭据业务能力举行服务拆分建立微服务架构的计谋之一就是接纳业务能力举行服务拆分。业务能力是一个来自于业务架构建模的术语。

业务能力是指一些能够为公司(或组织)发生价值的商业运动。特定业务的业务能力取决于这个业务的类型。例如,保险公司业务能力通常包罗承保、理赔治理、账务和合规等。在线商店的业务能力包罗:订单治理、库存治理和发货,等等。

业务能力界说了一个组织的事情组织的业务能力通常是指这个组织的业务是做什么,它们通常都是稳定的。与之相反,组织接纳何种方式来实现它的业务能力,是随着时间不停变化的。

这个准则在今天尤其显着,许多新技术在被快速接纳,商业流程的自动化水平越来越高。例如,不久之前你还通过把支票交给银行柜员的方式来兑现支票,现在许多ATM机都支持直接兑现支票,现在,人们甚至可以使用智能手机照相的方式来兑现支票。正如你所见,“兑现支票”这个业务能力是稳定稳定的,可是这个能力的实现方式正在发生戏剧性的变化。

识别业务能力一个组织有哪些业务能力,是通过对组织的目的、结构和商业流程的分析得来的。每一个业务能力都可以被认为是一个服务,除非它是面向业务的而非面向技术的。业务能力规范包罗多项元素,好比输入和输出、服务品级协议(SLA)。例如,保险承保能力的输入来自客户的应用法式,这个业务能力的输出是完成核保并报价。

业务能力通常集中在特定的业务工具上。例如,理赔业务工具是理赔治理功效的重点。

能力通常可以剖析为子能力。例如,理赔治理能力具有多个子能力,包罗理赔信息治理、理赔审核和理赔付款治理。把FTGO的业务能力逐一列出来似乎也并不太难题,如下所示。

供应商治理。Courier management:送餐员相关信息治理;Restaurant information management:餐馆菜单和其他信息治理,例如营业地址和时间。消费者治理:消费者有关信息的治理。订单获取和推行。

Order management:让消费者可以建立和治理订单。Restaurant order management:让餐馆可以治理订单的生产历程。

送餐。Courier availability management:治理送餐员的实时状态。Delivery management:把订单送到用户手中。

会计记账。Consumer accounting:治理跟消费者相关的会计记账。Restaurant accounting:治理跟餐馆相关的会计记账。

Courier accounting:治理跟送餐员相关的会计记账。其他。顶级能力包罗供应商治理、消费者治理、订单获取和推行以及会计记账。

可能另有许多其他顶级能力,包罗与营销相关的能力。大多数顶级能力都市剖析为子能力。例如,订单获取和推行被剖析为五个子能力。

这个能力条理的有趣方面是有三个餐馆相关的能力:餐馆信息治理、餐馆订单治理和餐馆会计记账。那是因为它们代表了餐馆运营的三个截然差别的方面。接下来,我们将相识如何使用业务能力来界说服务。

从业务能力到服务一旦确定了业务能力,就可以为每个能力或相关能力组界说服务。图2-8显示了FTGO应用法式从能力到服务的映射。某些顶级能力(如会计记账能力)将映射到服务。

在其他情况下,子能力映射到服务。决议将哪个级此外能力条理结构映射到服务是一个很是主观的判断。我对这种特定映射的理由如下:我将供应商治理的子能力映射到两种服务,因为餐馆和送餐员是很是差别类型的供应商。

我将订单获取和推行能力映射到三个服务,每个服务卖力流程的差别阶段。我将送餐员可用性治理(Courier availability management)和交付治理(Delivery management)能力联合起来,并将它们映射到单个服务,因为它们交织在一起。

我将会计记账能力映射到自己的独立服务,因为差别类型的会计记账看起来很相似。之后将针对餐馆和送餐员的用度支付和针对消费者的订单收款离开是有意义的。围绕能力组织服务的一个关键利益是,因为它们是稳定的,所以最终的架构也将相对稳定。

架构的各个组件可能会随着业务的详细实现方式的变化而生长,但架构仍保持稳定。话虽如此,重要的是要记着图2-8中显示的服务仅仅是界说架构的第一次实验。

随着我们对应用法式领域的相识越来越多,它们可能会随着时间的推移而变化,特别是架构界说流程中的一个重要步骤是观察服务如何在每个关键架构服务中协作。例如,你可能会发现由于过多的历程间通信而导致特定的剖析效率低下,导致你必须把一些服务组合在一起。

相反,服务可能会在庞大性方面增长到值得将其拆分为多个服务的水平。此外,在2.2.5节中将形貌可能导致你重新审视当前剖析决议的几个障碍。

现在让我们看看基于领域驱动设计剖析应用法式的方法。2.2.3凭据子域举行服务拆分Eric Evans在他的经典著作中(Addison-Wesley Professional,2003)提出的领域驱动设计是构建庞大软件的方法论,这些软件通常都以面向工具和领域模型为焦点。

领域模型以解决详细问题的方式包罗了一个领域内的知识。它界说了当前领域相关团队的词汇表,DDD也称之为通用语言(Ubiquitous language)。领域模型会被精密地映射到应用的设计和实现环节。

在微服务架构的设计层面,DDD有两个特别重要的观点,子域和限界上下文。传统的企业架构建模方式往往会为整个企业建设一个单独的模型,DDD则接纳了完全差别的方式。在这样的模型中,会有适用于整个应用全局的业务实体界说,例如客户或订单。

这类传统建模方式的挑战在于,让组织内的所有团队都对全局单一的建模和术语界说告竣一致是很是难题的。另外,对于组织中的特定团队而言,这个单一的业务实体界说可能过于庞大,超出了他们的需求。此外,这些传统的领域模型可能会造成杂乱,因为组织内有些团队可能针对差别的观点使用相同的术语,而也有些团队会针对同一个观点使用差别的术语。DDD通过界说多个领域模型来制止这个问题,每个领域模型都有明确的规模。

领域驱动为每一个子域界说单独的领域模型。子域是领域的一部门,领域是DDD中用来形貌应用法式问题域的一个术语。识别子域的方式跟识别业务能力一样:分析业务并识别业务的差别专业领域,分析产出的子域界说效果也会跟业务能力很是靠近。

FTGO的子域包罗:订单获取、订单治理、餐馆治理、送餐和会计。正如你所见:这些子域跟我们之前界说的业务能力很是靠近。DDD把领域模型的界限称为限界上下文(bounded context)。

衔接上下文包罗实现这个模型的代码荟萃。当使用微服务架构时,每一个链接上下文对应一个或者一组服务。换一种说法,我们可以通过DDD的方式界说子域,并把子域对应为每一个服务,这样就完成了微服务架构的设计事情。图2-9展示了子域和服务之间的映射,每一个子域都有属于它们自己的领域模型。

DDD和微服务架构简直就是天生一对。DDD的子域和限界上下文的观点,可以很好地跟微服务架构中的服务举行匹配。

而且,微服务架构中的自治化团队卖力服务开发的观点,也跟DDD中每个领域模型都由一个独立团队卖力开发的观点吻合。更有趣的是,子域用于它自己的领域模型这个观点,为消除上帝类和优化服务拆分提供了好措施。

按子域剖析和按业务能力剖析是界说应用法式的微服务架构的两种主要模式。可是,也有一些有用的拆分指导原则源于面向工具的设计。我们来详细讨论这些原则。

2.2.4拆分的指导原则到现在为止,在本章中,我们已经相识了界说微服务架构的主要方法。在应用微服务架构模式时,我们还可以采取和使用面向工具设计中的一些原则。

面向工具设计的一些原则也可以用于指导微服务架构的设计事情。这些原则由Robert C. Martin在他的著作《Designing Object Oriented C++ Applications Using The Booch Method》(Prentice Hall,1995)中提出。第一个原则就是在界说类的职责时,应该遵循单一职责原则(Single Responsibility Principle,SRP)。第二个原则是把类组成包时,应该遵循闭包原则(Common Closure Principle,CCP)。

让我们来看看这些原则如何应用到微服务架构。类所承载的每一个职责都是对它举行修改的潜在原因。如果一个类承载了多个职责,而且相互之间的修改是独立的,那么这个类就会变得很是不稳定。

遵照SRP原则,你所界说的每一个类都应该只有一个职责,因此也就只有一个理由对它举行修改。我们在设计微服务架构时应该遵循SRP原则,设计小的、内聚的、仅仅含有单一职责的服务。这会缩小服务的巨细并提升它的稳定性。新的FTGO架构是应用SRP的一个例子。

为客户获取餐食的每一个方面(订单获取、订单准备、送餐等)都由一个单一的服务承载。闭包原则另外一个有用的原则是闭包原则(CCP):在包中包罗的所有类应该是对同类的变化的一个荟萃,也就是说,如果对包做出修改,需要调整的类应该都在这个包之内。—Robert C. Martin这就意味着,如果由于某些原因,两个类的修改必须耦合先后发生,那么就应该把它们放在同一个包内。也许,这些类实现了一些特定的业务规则的差别方面。

这样做的目的是当业务规则发生变化时,开发者只需要对一个交付包做出修改,而不是大规模地修改(和重新编译)整个应用。接纳闭包原则,极大地改善了应用法式的可维护性。在微服务架构下接纳CCP原则,这样我们就能把凭据同样原因举行变化的服务放在一个组件内。

这样做可以控制服务的数量,当需求发生变化时,变换和部署也越发容易。理想情况下,一个变换只会影响一个团队和一个服务。

CCP是解决漫衍式单体这种恐怖的反模式的法宝。单一职责原则和闭包原则是Bob Martin制定的十一项原则中的两项。

它们在开发微服务架构时特别有用。在设计类和包时可以使用其余的九个原则。有关单一职责原则、闭包原则和其他面向工具设计原则的更多信息,请参阅Bob Martin网站上的文章《面向工具设计的原则》。

按业务能力和子域以及单一职责原则和闭包原则举行剖析是将应用法式剖析为服务的好方法。为了应用它们并乐成开发微服务架构,你还必须解决一些事务治理和历程间通信问题。

2.2.5拆分单体应用为服务的难点从外貌上看,通过界说与业务能力或子域相对应的服务来建立微服务架构的计谋看起来很简朴。可是,你可能会遇到几个障碍:网络延迟。同步历程间通信导致可用性降低。

在服务之间维持数据一致性。获取一致的数据视图。上帝类阻碍了拆分。

让我们来看看每个问题,先从网络延迟开始。网络延迟网络延迟是漫衍式系统中一直存在的问题。

你可能会发现,对服务的特定剖析会导致两个服务之间的大量往返挪用。有时,你可以通过实施批处置惩罚API在一次往返中获取多个工具,从而将延迟淘汰到可接受的数量。但在其他情况下,解决方案是把多个相关的服务组合在一起,用编程语言的函数挪用替换昂贵的历程间通信。同步历程间通信导致可用性降低另一个需要思量的问题是如那边理历程间通信而不降低系统的可用性。

例如,实现createOrder()操作最常见的方式是让Order Service使用REST同步伐用其他服务。这样做的毛病是REST这样的协议会降低Order Service的可用性。如果任何一个被挪用的服务处在不行用的状态,那么订单就无法建立了。

有时候这可能是一个不得已的折中,可是在第3章中学习异步消息之后,你就会发现其实有更好的措施来消除这类同步伐用发生的紧耦合并提升可用性。在服务之间维持数据一致性另一个挑战是如何在某些系统操作需要更新多个服务中的数据时,仍旧维护服务之间的数据一致性。例如,当餐馆接受订单时,必须在Kitchen Service和Delivery Service中同时举行更新。

Kitchen Service会更改Ticket的状态。Delivery Service摆设订单的交付。

这些更新都必须以原子化的方式完成。传统的解决方案是使用基于两阶段提交(two phase commit)的漫衍式事务治理机制。但正如你将在第4章中看到的那样,对于现今的应用法式而言,这不是一个好的选择,你必须使用一种很是差别的方法来处置惩罚事务治理,这就是Saga。

Saga是一系列使用消息协作的当地事务。Saga比传统的ACID事务更庞大,但它们在许多情况下都能事情得很好。Saga的一个限制是它们最终是一致的。如果你需要以原子方式更新某些数据,那么它必须位于单个服务中,这可能是剖析的障碍。

获取一致的数据视图剖析的另一个障碍是无法跨多个数据库获得真正一致的数据视图。在单体应用法式中,ACID事务的属性保证查询将返回数据库的一致视图。相反,在微服务架构中,纵然每个服务的数据库是一致的,你也无法获得全局一致的数据视图。

如果你需要一些数据的一致视图,那么它必须驻留在单个服务中,这也是服务剖析所面临的问题。幸运的是,在实践中这很少带来真正的问题。上帝类阻碍了拆分剖析的另一个障碍是存在所谓的上帝类。

上帝类是在整个应用法式中使用的全局类(http://wiki.c2.com/?GodClass)。上帝类通常为应用法式的许多差别方面实现业务逻辑。它有大量字段映射到具有许多列的数据库表。

大多数应用法式至少有一个这样的上帝类,每个类代表一个对领域至关重要的观点:银行账户、电子商务订单、保险政策,等等。因为上帝类将应用法式的许多差别方面的状态和行为捆绑在一起,所以将使用它的任何业务逻辑拆分为服务往往都是一个不行逾越的障碍。Order类是FTGO应用法式中上帝类的一个很好的例子。这并不奇怪:究竟FTGO的目的是向客户提供食品订单。

系统的大多数部门都涉及订单。如果FTGO应用法式具有单个领域模型,则Order类将是一个很是大的类。它将具有与应用法式的许多差别部门相对应的状态和行为。图2-10显示了使用传统建模技术建立的Order类的结构。

如你所见,Order类具有与订单处置惩罚、餐馆订单治理、送餐和付款相对应的字段及方法。由于一个模型必须形貌来自应用法式的差别部门的状态转换,因此该类还具有庞大的状态模型。

在现在情况下,这个类的存在使得将代码支解成服务变得极其难题。一种解决方案是将Order类打包到库中并建立一其中央Order数据库。

处置惩罚订单的所有服务都使用此库并会见会见数据库。这种方法的问题在于它违反了微服务架构的一个关键原则,并导致我们特别不愿意看到的紧耦合。

例如,对Order模式的任何更改都要求其他开发团队同步更新和重新编译他们的代码。另一种解决方案是将Order数据库封装在Order Service中,该服务由其他服务挪用以检索和更新订单。该设计的问题在于这样的一个Order Service将成为一个纯数据服务,成为包罗很少或没有业务逻辑的贫血领域模型(anemic domain model)。这两种解决方案都没有吸引力,但幸运的是,DDD提供了一个好的解决方案。

更好的方法是应用DDD并将每个服务视为具有自己的领域模型的单独子域。这意味着FTGO应用法式中与订单有关的每个服务都有自己的领域模型及其对应的Order类的版本。Delivery Service是多领域模型的一个很好的例子。如图2-11所示为Order,它很是简朴:取餐地址、取餐时间、送餐地址和送餐时间。

此外,Delivery Service使用更合适的Delivery名称,而不是称之为Order。Delivery Service对订单的任何其他属性不感兴趣。

Kitchen Service有一个更简朴的订单视图。它的Order版本就是一个Ticket(后厨工单)。

如图2-12所示,Ticket只包罗status、requestedDeliveryTime、prepareByTime以及告诉餐馆准备的订单项列表。它不体贴消费者、付款、交付等这些与它无关的事情。Order Service具有最庞大的订单视图,如图2-13所示。

纵然它有相当多的字段和方法,它仍然比原始版本的谁人Order上帝类简朴得多。每个领域模型中的Order类表现同一Order业务实体的差别方面。FTGO应用法式必须维持差别服务中这些差别工具之间的一致性。

例如,一旦Order Service授权消费者的信用卡,它必须触发在Kitchen Service中建立Ticket。同样,如果Kitchen Service拒绝订单,则必须在Order Service中取消订单,而且为客户退款。在第4章中,我们将学习如何使用前面提到的事件驱念头制Saga来维护服务之间的一致性。除了造成一些技术挑战以外,拥有多个领域模型还会影响用户体验。

应用法式必须在用户体验(即其自己的领域模型)与每个服务的领域模型之间举行转换。例如,在FTGO应用法式中,向消费者显示的Order状态来自存储在多个服务中的Order信息。这种转换通常由API Gateway处置惩罚,将在第8章中讨论。只管存在这些挑战,但在界说微服务架构时,必须识别并消除上帝类。

我们现在来看看如何界说服务API。2.2.6界说服务API到现在为止,我们有一个系统操作列表和一个潜在服务列表。下一步是界说每个服务的API:也就是服务的操作和事件。

存在服务API操作有以下两个原因:首先,某些操作对应于系统操作。它们由外部客户端挪用,也可能由其他服务挪用。另次,存在一些其他操作用以支持服务之间的协作。

这些操作仅由其他服务挪用。服务通过对外公布事件,使其能够与其他服务协作。

第4章将形貌如何使用事件来实现Saga,这些Saga可以维护服务之间的数据一致性。第7章将讨论如何使用事件来更新CQRS视图,这些视图支持有效的查询。应用法式还可以使用事件来通知外部客户端。

例如,可以使用WebSockets将事件通报给浏览器。界说服务API的起点是将每个系统操作映射到服务。之后确定服务是否需要与其他服务协作以实现系统操作。如果需要协作,我们将确定其他服务必须提供哪些API才气支持协作。

华体会

首先来看一下如何将系统操作分配给服务。把系统操作分配给服务第一步是确定哪个服务是请求的初始入口点。

许多系统操作可以清晰地映射到服务,但有时映射会不太显着。例如,思量使用noteUpdatedLocation()操作来更新送餐员的位置。

一方面,因为它与送餐员有关,所以应该将此操作分配给Courier Service。另一方面,它是需要送餐所在的Delivery Service。在这种情况下,将操作分配给需要操作所提供信息的服务是更好的选择。

在其他情况下,将操作分配给具有处置惩罚它所需信息的服务可能是有意义的。表2-2显示了FTGO应用法式中的哪些服务卖力哪些操作。

把操作分配给服务后,下一步是确定在处置惩罚每一个系统操作时,服务之间如何交互。确定支持服务协作所需要的API某些系统操作完全由单个服务处置惩罚。例如,在FTGO应用法式中,Consumer Service完全独立地处置惩罚createConsumer()操作。

可是其他系统操作跨越多个服务。处置惩罚这些请求之一所需的数据可能疏散在多个服务周围。例如,为了实现createOrder()操作,Order Service必须挪用以下服务以验证其前置条件并使后置条件建立:Consumer Service:验证消费者是否可以下订单并获取其付款信息。Restaurant Service:验证订单行项目,验证送货地址和时间是否在餐厅的服务区域内,验证订单最低要求,并获得订单行项目的价钱。

Kitchen Service:建立Ticket(后厨工单)。Accounting Service:授权消费者的信用卡。同样,为了实现acceptOrder()系统操作,Kitchen Service必须挪用Delivery Service来摆设送餐员交付订单。表2-3显示了服务、修订后的API及协作者。

为了完整界说服务API,你需要分析每个系统操作并确定所需的协作。到现在为止,我们已经确定了每项服务实现的服务和操作。但重要的是要记着,我们勾勒出的架构很是抽象。

我们没有选择任何特定的历程间通信技术。此外,纵然术语操作讲明某种基于同步请求和响应的历程间通信机制,你也会发现异步消息起着重要作用。

在本书中,我将会先容可能影响这些服务协作方式的架构和设计观点。第3章将先容特定的历程间通信技术,包罗REST等同步通信机制和使用消息署理的异步消息。我将讨论同步通信如何影响可用性并引入自包罗服务的观点,该服务不会同步伐用其他服务。

实现自包罗服务的一种方法是使用第7章中先容的CQRS模式。例如,Order Service可以维护Restaurant Service所拥有的数据的副本,以便消除同步伐用Restaurant Service举行订单验证的需要。

通过订阅Restaurant Service在其数据发生更新时对外公布的事件,Order Service可以维护Restaurant Service的一份数据副本。第4章将先容Saga观点以及它如何使用异步消息来协调到场Saga的服务。除了可靠地更新疏散在多个服务中的数据之外,Saga也是实现自包罗服务的一种方式。例如,我将形貌如何使用Saga实现createOrder()操作,该Saga使用异步消息挪用服务,例如Consumer Service、Kitchen Service和Accounting Service。

第8章将形貌API Gateway的观点,它将API公然给外部客户端。API Gateway可以使用第7章中形貌的API组合模式实现查询操作,而不是简朴地将其路由到服务。API Gateway中的逻辑通过挪用多个服务并组合效果来收集查询所需的数据。

在这种情况下,系统操作被分配给API Gateway而不是服务。服务需要实现API Gateway所需要的查询操作。

本章小结架构决议了软件的种种非功效性因素,好比可维护性、可测试性、可部署性和可扩展性,它们会直接影响开发速度。微服务架构是一种架构气势派头,它给应用法式带来了更高的可维护性、可测试性、可部署性和可扩展性。

微服务中的服务是凭据业务需求举行组织的,根据业务能力或者子域,而不是技术上的考量。有两种剖析模式:按业务能力剖析,其起源于业务架构。基于领域驱动设计的观点,通过子域举行剖析。可以通过应用DDD并为每个服务界说单独的领域模型来消除上帝类,正是上帝类引起了阻碍剖析的交织依赖项。


本文关键词:华体会,服务,的,拆分,计谋,2.1,微,服务,架构,到底

本文来源:华体会-www.bjthhk.com

Copyright © 2002-2021 www.bjthhk.com. 华体会科技 版权所有 备案号:ICP备81302774号-2

在线客服 联系方式 二维码

服务热线

035-908095460

扫一扫,关注我们