Architectural Styles and the Design of Network-based Software Architectures(架构风格与基于网络应用软件的架构设计)是 Roy Fielding 在2000年发表的博士论文。这篇论文一经发表,就引起了关注,并且对互联网开发产生了深远的影响。论文中首次提出的REST架构风格基本上成为目前Web架构的指导规范,如果一个Web架构符合REST架构风格,我们称为RESTful架构。
大部分人只看到这篇论文提出的REST架构风格,却忽略了REST架构风格提出的背景及方法论。这篇论文前半部分给出了一种通用的架构设计评估方法,我认为是更值得学习的地方。本来想用一文章来介绍这篇论文,发现篇幅有点收不住,于是拆分成两篇:
- Part1:主要介绍论文背景、架构风格的定义、评估应用软件架构设计的方法以及基于网络应用的架构属性与架构风格。
- Part2:主要介绍Web架构面临的问题、REST架构风格以及REST在Web架构中的应用。
概述
理解这篇论文需要先了解一下作者,Roy Fielding 是HTTP和URI两个互联网规范的设计者,同时还是libwww-perl客户端库、Apache HTTP服务器项目的作者,是Web互联网发展史上中非常重要的人物。
Web的成功,很大程序上得益于其软件架构的设计满足了互联网规范的分布式超媒体系统的需求。Web是以迭代的方式不断地发展,在发展过程中需要对定义Web架构的规范做一系列修改。为了识别出Web需要改善的那些方面以及避免对架构规范进行不必要的修改,需要一种Web架构模型,用来指导Web的设计、定义和部署。这便是作者提出这篇论文的初衷。
作者所说的用来指导Web设计、定义和部署的Web构架模型就是架构风格,具体来讲,这个架构风格就是REST。整篇论文是非常结构化的,一句话概括论文在大意:
作者定义了一个通过架构风格来评估软件架构的框架,在该架构下推导出REST架构风格,并将REST成功应用于现代Web架构设计中。
这篇文章主要聚焦于论文的前半部分:一种评估软件架构的框架。简单来说,就是作者通过定义架构风格可以产生出一组预期的架构属性,然后将这些架构属性和目标架构属性(应用的架构设计产生的架构属性)进行对比,以评估应用的架构设计是否合理。
本篇主要包括以下四个方面:
- 架构风格的定义
- 评估应用软件架构设计的方法
- 基于网络应用关注的架构属性
- 基于网络应用的架构风格
架构风格的定义
架构风格是一组相互协作的架构约束,这些架构约束限制了架构元素的角色和功能,以及在任何一个遵循该架构风格的架构中允许存在的元素之间的关系。一种架构风格是一组已命名的架构元素之上的架构约束,由它产生了架构所期待的一组架构属性。
这个定义很抽象,在理解架构风格之前,需要先理解架构元素
,架构约束
和架构属性
三个关键词。
架构元素
软件架构是由一些架构元素的配置来定义的,这些元素之间的关系受到约束,以获得所期待的一组架构属性。架构元素包括:
- 组件:是软件指令和内部状态的抽象单元,通过其接口提供数据的转换能力。
- 连接器:是对组件之间的通讯、配合或者协作进行中间斡旋的一种抽象机制。
- 数据:是组件通过连接器接收或发送的信息元素。
架构属性
软件架构的架构属性集合包括了对组件、连接器和数据的选择和排列所产生的所有属性。架构属性的例子包括了由系统获得的功能属性以及非功能属性。例如,软件演进的容易程度、组件的可重用性、效率、动态扩展能力,这些常常被称作品质属性。
架构约束
架构约束往往是由在架构元素的某个方面应用软件工程原则来驱动的。
例如,统一管道和过滤器架构风格通过在其组件接口之上应用通用性原则(强迫组件实现单一的接口类型),从应用中获得了组件的可重用性和可配置性的品质。因此,架构约束是由通用性原则所驱动的“统一组件接口”,目的是获得上述两个所期待的品质,当在架构中实现了这种架构风格时,这两个品质就成为了可重用和可配置组件的架构属性。
评估应用软件架构设计的方法
当我们在为某一特定应用领域选择或创建架构时,我们希望有一种方法能够评估和指导架构的合理性。
作者在论文中提供了这样一种方法:因为架构属性是由架构约束产生的,所以有可能通过以下方式来评估和比较不同的架构设计:识别出每个架构的架构约束,评估每个架构约束所产生的一组架构属性,并将设计累积的架构属性与那些应用所要求的架构属性加以比较。
正如上面一节的定义,一种架构风格是一组相互协作的架构约束,给它取一个名称是为了便于引用。每一个架构设计决策可以被看作是对一种架构风格的应用。因为添加的一个架构约束可能是从一种新的架构风格获得的,我们可以将所有可能的架构风格的空间看作是一棵继承树(a derivation tree),这棵树的根节点是“空”风格(没有任何架构约束)。当多种架构的架构约束不存在冲突时,它们就可以进行组合,形成一种混合架构风格,最终可以形成一种代表了架构设计完整抽象的混合架构风格。
因此通过将一个架构设计的架构约束集合分解到一棵继承树上,就能够对这个架构设计进行分析,并且可以评估由这棵继承树所代表的架构约束的累积效果。如果我们理解了每种基本架构风格所产生的架构属性,那么遍历这棵继承树可以使我们理解架构设计的全部架构属性,然后就能够将应用的特定需求与架构设计的架构属性进行匹配。
这样比较不同的架构设计就变成了一件相当简单的事情:识别出哪些架构设计满足了该应用的大多数期望的架构属性。
必须意识到,一种架构约束的效果可能会抵消一些其他架构约束带来的好处。尽管如此,一个有经验的软件架构师仍然有可能为一个特定应用领域的架构约束建造一棵这样的继承树,然后使用这棵继承树来评估该领域应用的很多不同的架构设计。这样,建造一棵继承树就为架构设计提供了一种评估机制。
在一棵架构风格的继承树中对架构属性所进行的评估,是特定于一个特殊应用领域之需求的,因为特定架构约束的影响常常取决于应用的特性。例如,当我们将管道和过滤器架构风格用于要求在组件之间进行数据转换的系统中时,会产生一些积极的架构属性;但是当系统仅仅由控制消息组成时,它只会增加系统的开销,而不会带来任何好处。因为跨不同的应用领域对架构设计进行比较用处不大,因此确保一致性的最简单的方法是使这棵继承树特定于某个领域。
基于网络应用关注的架构属性
上一节中提到,在一棵架构风格的继承树中对架构属性所进行的评估时,是针对特定应用领域的。那么对于基于网络应用架构应用关注哪些架构属性呢?作者是根据调查的一组架构风格,列出那些明显受这些架构风格影响的架构属性。
性能(Performance)
聚焦于基于网络应用的架构风格的主要原因之一,是因为组件交互对于用户感知的性能和网络效率来说是一个决定性因素。由于架构风格影响到这些交互的特性,选择合适的架构风格能够决定基于网络应用部署的成败。
基于网络应用的性能首先取决于应用的需求,然后是所选择的交互风格,接下来是实现架构,最后是每个组件的实现。性能包括:网络性能,用户感知的性能和网络效率。
可伸缩性(Scalability)
可伸缩性表示通过主动的配置,一个架构支持大量的组件或大量组件之间的交互能力。
简单性(Simplicity)
通过架构风格产生简单性属性的主要方法是,对组件之间的功能分配应用分离关注点原则。如果功能分配使得单独的组件足够简单,那么理解和实现这些组件就会更加容易,同时让整体架构的推理任务变得更加容易。
可修改性(Modifiability)
可修改性是对于应用的架构作出改变的容易程度。可修改性包括:
- 可进化性(Evolvability)
- 可扩展性(Extensibility)
- 可定制性(Customizability)
- 可配置性(Configurability)
- 可重用性(Reusability)
可见性(Visibility)
通过通用性架构约束来限制交互的接口,或者提供访问功能以便于监视,架构风格也能够影响基于网络应用中交互的可见性。在这种情况下,可见性是指一个组件对于其他两个组件之间的交互进行监视或进行中间斡旋的能力。
可移植性(Portability)
如果软件能够在不同的环境下运行,软件就是可移植的。能够产生可移植性架构属性的架构风格包括那些将代码和代码处理的数据放在一起移动的架构风格,例如虚拟机架构风格和移动代理架构风格;以及那些限制只能使用标准格式的数据元素的架构风格。
可靠性(Reliability)
从应用的架构角度来说,可靠性可以被看作当在组件、连接器或数据之中出现部分故障时,一个架构容易受到系统层面故障影响的程度。
基于网络应用的架构风格
作者通过调研一些常见的架构风格,并将这些架构风格应用于基于网络的超媒体系统的架构时,产生了一系列架构属性(见上节)。在为系统设计选择架构风格时,必须与应用架构的需求相一致,而不是相抵触。因此,应用基于这些架构风格所产生的架构属性来对架构风格进行分类,这样才能提供有用的设计指导。
这个分类框架的主要展示方式是一张架构风格和架构属性的比较表。表中的数值表明了特定行中架构风格对于列中架构属性的相对影响。减号(-)表示消极影响,加号(+)表示积极影响,加减号(±)表示影响的性质取决于问题领域的某个方面。尽管对于下面各节中的细节而言,这只是一个粗略的简化,但它确实能够表明一种架构风格对架构属性所产生的正面(或负面)的影响。
另外一种展示方式,是使用一张基于架构属性的继承关系图,来对架构风格进行分类。根据各种架构风格之间的继承关系来分类,架构风格之间的弧线显示出得到或失去的架构属性。这张图的起点是“空”风格(没有约束)。这样一张图是有可能从对于架构风格的描述直接导出的。
数据流风格(Data-flow Styles)
有2种具体的数据流架构风格如下:
- 管道和过滤器(Pipe and Filter,PF)
- 统一管道和过滤器(Uniform Pipe and Filter,UPF)
架构风格对架构属性的影响如下:
风格 | 继承 | 网络性能 | 用户感知的性能 | 效率 | 可伸缩性 | 简单性 | 可进化性 | 可扩展性 | 可定制性 | 可配置性 | 可重用性 | 可见性 | 可移植性 | 可靠性 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
PF | ± | + | + | + | + | + | ||||||||
UPF | PF | - | ± | ++ | + | + | ++ | ++ | + |
复制风格(Replication Syltes)
有2种具体的复制架构风格如下:
- 复制仓库(Replicated Repository,RR)
- 缓存(Cacache,$)
架构风格对架构属性的影响如下:
风格 | 继承 | 网络性能 | 用户感知的性能 | 效率 | 可伸缩性 | 简单性 | 可进化性 | 可扩展性 | 可定制性 | 可配置性 | 可重用性 | 可见性 | 可移植性 | 可靠性 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RR | ++ | + | + | |||||||||||
$ | RR | + | + | + | + |
分层风格(Hierarchical Styles)
有8种具体的分层架构风格如下:
- 客户-服务器(Client-Server,CS)
- 分层系统(Layered System,LS)和分层-客户-服务器(Layered-Client-Server,LCS)
- 客户-无状态-服务器(Client-Stateless-Server,CSS)
- 客户-缓存-无状态-服务器(Client-Cache-Stateless-Server,C$SS)
- 分层-客户-缓存-无状态-服务器(Layered-Client-Cache-Stateless-Server,LC$SS)
- 远程会话(Remote Session,RS)
- 远程数据访问(Remote Data Access,RDA)
架构风格对架构属性的影响如下:
风格 | 继承 | 网络性能 | 用户感知的性能 | 效率 | 可伸缩性 | 简单性 | 可进化性 | 可扩展性 | 可定制性 | 可配置性 | 可重用性 | 可见性 | 可移植性 | 可靠性 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CS | + | + | + | |||||||||||
LS | - | + | + | + | + | |||||||||
LCS | CS+LS | - | ++ | + | ++ | + | + | |||||||
CSS | CS | - | ++ | + | + | + | + | |||||||
C$SS | CSS+$S | - | + | + | ++ | + | + | + | + | |||||
LC$SS | LCS+C$SS | - | ± | + | +++ | ++ | ++ | + | + | + | + | |||
RS | CS | + | - | + | + | - | ||||||||
RDA | CS | + | - | - | + | - |
移动代码风格(Mobile Code Styles)
有5种具体的移动代码架构风格如下:
- 虚拟机(Virtual Machine,VM)
- 远程求值(Remote Evaluation,REV)
- 按需代码(Code on Demand,COD)
- 分层-按需代码-客户-缓存-无状态-服务器(Layered-Code-on-Demand-Client-Cache-Stateless-Server,LCODC$SS)
- 移动代理(Mobile Agent,MA)
架构风格对架构属性的影响如下:
风格 | 继承 | 网络性能 | 用户感知的性能 | 效率 | 可伸缩性 | 简单性 | 可进化性 | 可扩展性 | 可定制性 | 可配置性 | 可重用性 | 可见性 | 可移植性 | 可靠性 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
VM | ± | + | - | + | ||||||||||
REV | CS+VM | + | - | ± | + | + | - | + | - | |||||
COD | CS+VM | + | + | + | ± | + | + | - | ||||||
LCODC$SS | LC$SS+COD | - | ++ | ++ | +4+ | +±+ | ++ | + | + | + | ± | + | + | |
MA | REV+COD | + | ++ | ± | ++ | + | + | - | + |
点对点风格(Peer-to-Peer Styles)
有4种具体的点对点架构风格如下:
- 基于事件的集成(Event-based Integration,EBI)
- C2
- 分布式对象(Distributed Objects,DO)
- 被代理的分布式对象(Brokered Distributed Objects,BDO)
架构风格对架构属性的影响如下:
风格 | 继承 | 网络性能 | 用户感知的性能 | 效率 | 可伸缩性 | 简单性 | 可进化性 | 可扩展性 | 可定制性 | 可配置性 | 可重用性 | 可见性 | 可移植性 | 可靠性 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
EBI | + | – | ± | + | + | + | + | - | - | |||||
C2 | EBI+LCS | - | + | + | ++ | + | + | ++ | ± | + | ± | |||
DO | CS+CS | - | + | + | + | + | + | - | - | |||||
BDO | DO+LCS | - | - | ++ | + | + | ++ | - | + |
从这篇论文中得到的启示
什么是架构呢?用非形式化的定义来讲架构就是在有限资源下做的折衷(Trade-offs)。我们在对特定应用领域做架构设计时,会面临着各种限制条件,比如延时、数据规模、扩展性、时间等因素。这些限制条件就是有限资源,也可以泛化理解成论文中的架构属性。
这篇论文有两点思想是值得学习的:
- 一种应用软件架构设计的评估方法,这种评估方法任何于适何应用领域的架构设计。
- 一种通用的知识结构化提炼方法:每一个领域都有前人做过的相关研究,首先需要站在巨人的肩膀上,对这个领域最杰出的人的研究成果做归纳和总结。然后针对自己面临的问题,归纳和组合应用前人的研究成果,并形成特定应用有效的解决方案(方法)。最后泛化这个解决方案,推广到更一般的场景。
参考资料
[1] Architectural Styles and the Design of Network-based Software Architectures
[2] Wikipedia: Representational state transfer
[3] Roy Fielding
[4] restfulapi.net