架构是什么
首先看下软件架构的含义。
计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、它们之间的关系以及两者的属性。
—Bass等著《Documenting Software Architectures: Views and Beyond》
其实质是应用程序的架构是将软件分解为元素(element)和这些元素之间的关系(relation)。
怎么了解一个架构
从更具体的角度而言,应用程序的架构可以从多个视角来看。Phillip Krutchen在他经典的论文《Architectural Blueprints —The 4+1 View Model of Software Architecture》中提出了软件架构的4+1视图。
- 逻辑视图:开发人员创建的软件元素。在面向对象的语言中,这些元素是类和包。它们之间的关系是类和包之间的关系,包括继承、关联和依赖。
- 实现视图:构建编译系统的输出。此视图由表示打包代码的模块和组件组成,组件是由一个或多个模块组成的可执行或可部署单元。在Java中,模块是JAR文件,组件通常是WAR文件或可执行JAR文件。它们之间的关系包括模块之间的依赖关系以及组件和模块之间的组合关系。
- 进程视图:运行时的组件。每个元素都是一个进程,进程之间的关系代表进程间通信。
- 部署视图:进程如何映射到机器。此视图中的元素由(物理或虚拟)计算机和进程组成。机器之间的关系代表网络。该视图还描述了进程和机器之间的关系。
4+1中的+1是指场景,它负责把视图串联在一起。
每一个视图都描述了架构的一个重要侧面。场景把视图中的元素如何协作串联在一起。
为什么架构重要?
应用程序有两个层面的需求。功能性需求和非功能性需求。
第一类是功能性需求,这些需求决定一个应用程序做什么。这些通常都包含在用例(use case)或者用户故事(user story)中。应用的架构其实跟这些功能性需求没什么关系。功能性需求可以通过任意的架构来实现,甚至是非常糟糕的大泥球架构。
架构的重要性在于,它帮助应用程序满足了第二类需求:非功能性需求。我们把这类需求也称之为质量属性需求,或者简称为“能力”。这些非功能性需求决定一个应用程序在运行时的质量,比如可扩展性和可靠性。它们也决定了开发阶段的质量,包括可维护性、可测试性、可扩展性和可部署性。为应用程序所选择的架构将决定这些质量属性。
什么是架构的风格
架构风格根据结构组织模式定义了一系列此类系统。
更具体地说,架构风格确定可以在该风格的实例中使用的组件和连接器的词汇表,以及关于如何组合它们的一组约束。
特定的架构风格提供了有限的元素(组件)和关系(连接器),你可以从中定义应用程序架构的视图。
例如:分层式架构风格
分层架构将软件元素按“层”的方式组织。每个层都有明确定义的职责。分层架构还限制了层之间的依赖关系。每一层只能依赖于紧邻其下方的层(如果严格分层)或其下面的任何层。三层架构是应用于逻辑视图的分层架构,可以分为表现层,业务逻辑层,数据持久化层。
六边形架构是分层架构风格的替代品。六边形架构风格选择以业务逻辑为中心的方式组织逻辑视图。
应用程序具有一个或多个入站适配器,而不是表示层,它通过调用业务逻辑来处理来自外部的请求。
分层架构和六边形架构都是架构风格的实例。
微服务架构是一种架构风格
单体架构:将应用程序构建为单个可执行和可部署组件。
微服务架构:将应用程序构建为松耦合、可独立部署的一组服务。
服务是一个单一的、可独立部署的软件组件,它实现了一些有用的功能。微服务架构中的每项服务都有自己的架构,可能还有独特的技术栈。但是典型的服务往往都具有六边形架构。
微服务架构的松耦合
微服务架构的最核心特性是服务之间的松耦合性 。
服务之间的交互采用API完成,以此
- 封装了服务的实现细节
- 可以在不影响客户端的情况下,对实现方式做出修改。
共享类库的角色
最简单的方式是,在微服务架构中使用共享库。如此,似乎是减少服务中代码重复的好方法。但是可能,会意外地在服务之间引入耦合。
应该努力使用共享库来实现不太可能改变的功能。例如,在典型的应用程序中,在每个服务中都实现一个通用的Money类(例如用来实现币种转换等固定功能)没有任何意义。相反,你应该创建一个供所有服务使用的共享库。
服务的大小并不重要
实际上,服务大小不是一个重要的考虑因素。
更好的目标是将精心设计的服务定义为能够由小团队开发的服务,并且交付时间最短,与其他团队协作最少。
如何定义微服务架构
第一步是将应用程序的需求提炼为各种关键请求。不是根据特定的进程间通信技术(如REST或消息)来描述这些请求,而是使用系统操作这个概念。系统操作(system operation)是应用程序必须处理的请求的一种抽象描述。它既可以是更新数据的命令,也可以是检索数据的查询。
第二步是确定如何分解服务。有几种策略可供选择。
- 一种源于业务架构学派的策略是定义与业务能力相对应的服务。
- 另一种策略是围绕领域驱动设计的子域来分解和设计服务。
但这些策略的最终结果都是围绕业务概念而非技术概念分解和设计的服务。
第三步是确定每个服务的API。为此,你将第一步中标识的每个系统操作分配给服务。服务可以完全独立地实现操作。或者,它可能需要与其他服务协作。
识别系统操作
起点是应用程序的需求,包括用户故事及其相关的用户场景。
第一步,创建由关键类组成的抽象领域模型,这些关键类提供用于描述系统操作的词汇表。可以使用名为事件风暴(Event Storming)的技术定义领域模型。
创建领域模型会采用一些标准的技术,例如通过与领域专家沟通后,分析用户故事和场景中频繁出现的名词。
第二步,确定系统操作,并根据领域模型描述每个系统操作的行为。系统操作可以创建、更新或删除领域对象,以及创建或破坏它们之间的关系。
可以把系统操作分为两种类型:
命令型:创建、更新或删除数据的系统操作。
查询型:查询和读取数据的系统操作。
不必在意这些实现细节,识别系统指令的切入点是分析用户故事和场景中的动词。多数与系统操作是命令。查询虽然仅仅是简单地获取数据,但是也同样重要。
抽象的领域模型和系统操作能够回答这个应用“做什么”这一问题。
根据业务能力进行服务拆分
有多种拆分策略可供识别应用服务。但是殊途同归,这些策略的结果都是一样的:一个包含若干服务的架构,这样的架构是以业务而不是技术概念为中心。
我们先来看看第一个策略:使用业务能力来定义服务。
业务能力是指一些能够为公司(或组织)产生价值的商业活动。特定业务的业务能力取决于这个业务的类型。例如,保险公司业务能力通常包括承保、理赔管理、账务和合规等。
组织的业务能力通常是指这个组织的业务是做什么,它们通常都是稳定的。与之相反,组织采用何种方式来实现它的业务能力,是随着时间不断变化的。
一个组织有哪些业务能力,是通过对组织的目标、结构和商业流程的分析得来的。每一个业务能力都可以被认为是一个服务。业务能力规范包含多项元素,比如输入和输出、服务等级协议(SLA)。
业务能力通常集中在特定的业务对象上。例如,理赔业务对象是理赔管理功能的重点。能力通常可以分解为子能力。例如,理赔管理能力具有多个子能力,包括理赔信息管理、理赔审核和理赔付款管理。
从业务能力到服务
某些顶级能力(如会计记账能力)将映射到服务。在其他情况下,子能力映射到服务。决定将哪个级别的能力层次结构映射到服务是一个非常主观的判断。
围绕能力组织服务的一个关键好处是,因为它们是稳定的,所以最终的架构也将相对稳定。
根据子域进行服务拆分
领域模型以解决具体问题的方式包含了一个领域内的知识。它定义了当前领域相关团队的词汇表,DDD也称之为通用语言(Ubiquitous language)。
在微服务架构的设计层面,DDD有两个特别重要的概念,子域和限界上下文。
识别子域的方式跟识别业务能力一样:分析业务并识别业务的不同专业领域,分析产出的子域定义结果也会跟业务能力非常接近。
拆分单体应用为服务的难点
- 网络延迟。
- 同步进程间通信导致可用性降低。
- 在服务之间维持数据一致性。
- 获取一致的数据视图。
- 上帝类阻碍了拆分,更好的方法是应用DDD并将每个服务视为具有自己的领域模型的单独子域。