典籍翻译:Architectural Styles and the Design of Network-based Software Architectures

最近周末帮外甥女"小雪"补习英语,遴选了Fielding博士的毕业论文作文课外阅读资料,也借这个机会来重新梳理一下软件架构设计的相关理论。

译者序

本文拟对Fielding的博士论文<Architectural Styles and the Design of Network-based Software Architectures>进行翻译,按照"信、达、雅"的原则,在翻译过程中,力求尊重原文原意,同时兼顾语言的简洁通顺。

这是笔者第一次尝试去翻译国外经典论文典籍,作为力学专业、但从事CAx软件开发的技术工作者,笔者深感前辈们呕心沥血的成果来之不易,对文中每句话都反复研究良久,力求不会误解前辈们的谆谆教导。但限于个人水平与从业经历,难免有不当之处,欢迎批评指正。

引言

正如Perry与Wolf所述,架构设计是上世纪90年代研究的焦点。现在的软件系统化更加注重系统组件化:将系统分成独立的组件,通过组件协作来满足系统需求。软件架构主要研究如何划分系统组件、组件间如何通信、信息如何传输、系统单元如何独立演进、如何表述概念等问题。

优秀的架构并不是凭空产生的。所有的设计决策均为满足系统需求为目标的,这条原则在传统建筑行业与软件行业都是一样的。“功能决定形式”的原则来源于建筑行业数百年的经验教训,但软件从业人员却经常忽略这一原则。在短句"Monty Python"中有一段搞笑段子,说是有的建筑师会按照屠宰场结构来设计公寓,这或许能够将建造最好屠宰场,但是对于以后居住在这里的租户来说,他们定会感觉不适。

这看起来有点滑稽,但事实上,很多软件项目会盲目使用很多流行的架构,到最好才发现可能并不需要这种架构。造成这种现象的原因是由于对架构涉及的约束并不了解,实际上就是采用这些架构的设计者并不清楚优秀架构的原理。

本论文研究计算机科学的两个前沿问题:软件和网络。长期以来,软件研究主要关注设计方法的分类、设计方法的演化等问题,但很少讨论设计决策对系统的影响。相反,网络研究主要关注通信的性能,却没有意识到交互方式的改变可能会更重要。本文使用架构约束来探究网络应用程序的架构设计,用以实现期望的架构属性。可以一组自洽的约束集合称之为架构风格。

前三章介绍了使用软件风格来研究软件架构的框架,揭示了架构风格是如何指导网络应用程序架构设计的。对常见的架构风格进行调研,依据架构风格对网络超媒体系统的作用,将这些架构风格进行了分类。分类的目的是为了找出那些可用于WWW软件架构设计的约束。

需要理解Web应用的需求,才能更好的为这类应用程序设计架构。Web应用实际上是一种Internet级别的超媒体系统。Internet将各种信息服务连接在一起,信息服务必须能够弹性伸缩、独立部署等特点。分布式超媒体通过页面内的控件来实现访问信息。Web架构设计需要考虑如何在高延迟的网络撒花姑娘传输大块数据。

针对分布式超媒体系统,第五章引入了一套由许多约束构成的REST架构。REST架构注重组件交互的伸缩性、接口的通用性、组件独立部署、使用中间件来降低延迟等。给出了REST架构的原则及约束,并与其他架构风格进行了比较。

在第六章中,将会说明REST架构在过去的六年时间里已被用于现代Web应用的设计与开发。其中,HTTP与URI则定义了Web应用中组件通信的接口。

在实现过程中,通常并不会完全遵循架构设计里面的约束。REST架构也可以用于识别实现过程中那些违背REST约束的问题,在第六章中,也会对实现过程中的问题进行总结。

简单说,本文主要做了以下工作:

  • 使用架构模式来研究软件架构的方法,同时给出了软件架构的定义。
  • 依据架构模式对分布式超媒体系统的作用,对网络应用程序的架构模式进行了分类。
  • 针对分布式超媒体系统,提出了REST架构
  • 验证REST架构可用于现代Web应用设计与开发。

Chapter 1 Software Architecture

软件架构没有公认的定义。这也导致了,许多研究会忽略架构设计的某些方面。本章依据文献研究与对网络应用程序的理解,给出了一种软件架构定义。

1.1 Run-time Abstraction

software architecture is an abstraction of the run-time elements of a software system during some phase of its operation. A system may be composed of many levels of abstraction and many phases of operation, each with its own software architecture.

软件架构的核心是抽象,隐藏实现细节,同时向外暴露接口。一些复杂的系统通常会有多层抽象,每一层可以有一套架构。每层架构对应该层的抽象,向外暴露接口以供本层的其他元素使用;在每个元素内部,子元素也可使用其他架构来实现父元素的接口,直到最基本的元素。

除了架构的层次性,软件系统通常包含启动、初始化、业务处理、重新初始化及关闭等阶段,每个阶段也可以由不同的架构。比如说,配置文件用于系统启动,因而系统启动架构需要将其作为一个构成元素,但是对于业务处理阶段来说,由于配置信息已经分发给系统,此时不会再把配置文件作为业务处理架构的元素。一个完整的架构不仅需要能够描述系统各个阶段的行为,还需要更够涉及不同阶段的转换。

Perry and Wolf将processing elements理解成数据转换器;Shaw将components定义为计算与状态单元;Shaw 与Clements将组件components为系统运行期间处理数据的单元,包括程序、对象、进程及过滤器。这里需要区分一下软件架构(software architecture)与软件结构(software structure):软件架构是系统运行时的描述,软件结构指的是软件代码的描述。软件架构与软件结构不必保持一致,架构设计与代码组织虽然相互密切相关,但是却不是一回事,很多软件架构描述却不能够认识到这种差异。

1.2 Elements

A software architecture is defined by a configuration of architectural elements--components, connectors, and data--constrained in their relationships in order to achieve a desired set of architectural properties.

Perry与Wolf对软件架构进行了深入的研究,他们认为软件架构是一组架构元素构成的集合,这些架构元素具有外观形式与设计原理,将架构元素可以分为processing、data、connecting等。架构元素的外观形式是指架构元素对外具有一定外观属性,同时可以与其他架构元素发生关系,而这些可定义为作用于架构元素上的约束。架构元素的设计原理实际上描述了架构设计过程中的一系列(非)技术决策。

关于软件架构的定义,本文中对Perry与Wolf的见解略有不同。本文认为软件架构不应当包含架构元素的设计原理,尽管架构元素的设计原理是架构研究与设计的一个重要方面,但在架构定义中包含架构元素的原理,意味着设计文档也是系统运行时的一部分。架构元素的设计原理影响架构的演进,但是一经确定,软件架构是独立于架构元素设计原理的。比如,使用反射机制,可以将一个底层架构替换成另一个底层架构,而这过程中并未引入新的架构元素设计原理。

打个比方,如果建筑的设计图纸被焚毁,因为墙体依旧可以支撑屋顶,建筑并不会坍塌。软件架构具有一些属性,忽略这些属性将会毁坏软件的架构。就像在建筑中,使用玻璃来代替承重墙,将会影响建筑的稳定性。因此,软件架构定义中应当包含架构元素的属性,而非架构元素的设计原理,架构元素设计原理是架构元素属性的因,即使没有架构元素设计原理会导致架构发生蜕变,但架构元素设计原理也不应当作为软件架构定义的一部分。

Perry与Wolf的定义中,将架构元素进行了分类,Processing elements 执行数据的变换,data elements是信息数据,connecting elements用于关联不同的元素。本文中分别使用components与connectors 来替换Processing elements、connecting elements。

Garlan与Shaw认为软件架构是由components与connectors构成,Shaw等也对软件架构定义做了补充与扩展。

令人比较诧异的的是,Shaw认为软件架构的描述才是软件软件架构,按照他的定义,软件架构就是软件架构描述文档中的框、线,而且data elements并没有被认为是软件架构元素。这是显然不适合网络应用程序的,因为data elements往往是网络程序中最为重要的。

1.2.1 Components

component is an abstract unit of software instructions and internal state that provides a transformation of data via its interface.

相对来说,比较容易圈定出哪些架构元素是components的。Perry与Wolf认为components用于处理data elements。Garlan与Shaw认为Components用于执行计算。本文中强调components与Connectors的区别。

components提供了一组接口用于处理数据。数据处理包括从二次存储中加载数据到内存、执行计算、转换数据格式、封装数据等。架构中不同组件具有不同的特性。也就是说,每个组件通过接口而非内部实现来向其他组件提供服务。按照Parnas法人说法,这实际上是该组件对其他组件的约定。

1.2.2 Connectors

connector is an abstract mechanism that mediates communication, coordination, or cooperation among components.

Perry与Wolf认为connectors是架构元素的粘合剂。Shaw与Clements则认为connector提供了一种机制用于组件间的通信、互操作等。比如,shared representations、RPC、message-passing protocols以及data streams。

可以将connectors与components做下对比。connectors将数据从一个components传递到另一个components,但不会改变数据内容。当然,connectors内部实现在传输数据之前,可能会修改数据格式,最后会将数据还原成数据的原有格式,这样便于数据传输。从外观行为上来看,不需要关注connectors这种内部实现细节。与之不同,components大多数情况下会修改数据。

1.2.3 Data

datum is an element of information that is transferred from a component, or received by a component, via a connector.

与Perry、Wolf的架构模型相比,不少研究均认为软件架构应当包含data elements。Boasson认为现在软件架构过于注重组件结构与开发工具,建议要重视以数据为中心的架构模型。

data element用于表示一段数据信息,connector会将data element从一个component传递到另一个component。常见的data element包括byte-sequences、messages、marshalled parameters等,但那些永久存在于组件内的数据通常不被看做是data element。像是传感器等component也可以产生数据。

1.3 Configurations

configuration is the structure of architectural relationships among components, connectors, and data during a period of system run-time.

Abowd认为架构由components、connectors、configurations等组成。components负责计算;connectors负责连接不同的components;configurations用于配置components与connectors。可以用不同的符号来表示它们,进而描述软件架构。

或许可以把configurations看作是对components的一组约束。比如,Perry与Wolf在他们的架构模型中引入了topology,用以更加方便地区分 active configuration与其他约束。Medvidovic 与Taylor也对架构中的configurations进行了研究。

1.4 Properties

软件架构的属性是通过编排components、connectors与data来获得的。这些属性可分为功能性属性与非功能性属性。非功能性属性也被乘坐质量属性,包括可维护性、易用性、性能、动态扩展性等。

constraints是按照软件工程的原则来编排architectural elements(包括components、connectors与data等),因此架构属性实际上就是由constraints确定的。比如,uniform pipe-and-filter通过组件接口的通用性来实现可用性与可配置性,也就是说,使用通用性原则获得了可用性与可配置性。

架构设计的目标就是要设计一套架构属性能够满足系统需求的架构。至于说,哪些架构属性更加重要,这个由所研究的问题决定。在本文2.3节,针对网络应用程序,将会讨论哪些较为重要的架构属性。

1.5 Styles

An architectural style is a coordinated set of architectural constraints that restricts the roles/features of architectural elements and the allowed relationships among those elements within any architecture that conforms to that style.

软件架构包括功能性属性与非功能性属性。对不同类型的系统,很难比较它们所使用的软件架构;不同环境下的同一类型系统,也不易比较它们所使用的的架构。架构风格(架构模式)是一种对软件架构进行分类的方法,架构风格关注架构中主要方面,而忽略具体应用相关的细节。

Perry与Wolf认为架构模式是对各种architectural elements的抽象,着重分析架构的重要部分。架构模式封装了架构设计过程中关键性的决策,关注组件约束、组件间的关联等。

Garlan与Shaw等认为软件架构风格是组件间关系的一种模式。具体来说,他们认为软件架构模式给出了一些components、connectors,同时定义了一组约束用于限制这些components、connectors。架构风格来自软件架构,试想若用线、框图来表示软件架构,架构模式则是对其的抽象。Abowd认为软件架构风格可用于去理解一组软件架构的。

新兴的软件架构可能仅是某种已有架构风格的一种,架构风格描述了软件架构的不同方面,一套架构可以包含多种架构风格,一种架构风格也可由多种架构风格混合而成

有些软件架构风格被称为"银弹",能够应对各种场景。但是,一个合格的软件架构师应当明白,应当根据待研究的问题选择合适的软件架构风格。为网络应用程序选择合适的架构风格,需要理解网络应用程序的需求,了解各种相关架构风格及它们能够解决的问题,预见各种架构风格是否适合网络应用程序。

架构风格中的"风格"表示一组自洽的约束集合,这与"风格"一词的原意是不同的。Loerke认为软件架构风格是对过去架构的评价。Loerke认为风格来自建筑设计过程中的约束。把一组约束冠以一种风格,有利于交流。

1.6 Patterns and Pattern Languages

伴随着架构风格的发展,设计模式与模式语言也被应用到面向对象软件开发。设计模式是重复出现的系统结构;模式语言是由模式组成的规则系统。这两个概念源自Alexander编写的建筑结构的著作。

模式的设计空间是面向对象编程中的一些实现技巧,包括继承、组合等。有时候,架构风格描述会被改造为架构模式。但是,模式主要通过抽象来描述对象间通信接口,实际上是对具体实现施加了约束。模式可以用于处理对象间的相互作用。模式定义了解决问题的一种方法。

架构风格与软件模式虽然源自建筑领域的架构,但是它们已与建筑架构分道扬镳。Alexande所提出的模式关注于重复出现的人类活动,而非架构元素的编排,Alexande的设计原则关注于人们生活与文化。

Alexander所提出的模式与软件架构风格由许多相同之处。架构风格包含一组约束,用于满足最终的系统属性。

1.7 Views

系统可以包含多种架构及架构风格,可以从其他角度来分析系统架构。Perry与Wolf提出了三种研究研究软件架构的视角:processing、data及connection。processing着重于组件间的数据流;data着重于处理流程;connection着重于组件间的关系。

可以使用多种视角来研究架构。4+1 View Model使用了五种视角,每种视角关注于一个特定的问题。

1.8 Related Work

此处仅介绍了软件架构的定义及架构模式的描述。软件架构研究还包括架构分析技术、架构恢复和重构、架构设计的工具与环境、架构优化、软件架构案例等。在第三章中将会讨论架构风格分类、分布式处理范式、中间件等相关内容。

1.8.1 Design Methodologies

软件架构的早期研究主要关注于设计方法。比如,面向对象设计提倡基于对象组织系统。在早期的设计方法中,JSD(Jackson System Development)强调架构级设计。JSD使用了pipe-and-filter及process control等约束,但这种设计方法往往仅产生一种架构风格。

早期有一些架构分析及演化的研究。Kazman使用SAAM与ATAM对架构设计进行了研究;Shaw比较了各种汽车巡航控制系统的架构设计。

1.8.2 Handbooks for Design, Design Patterns, and Pattern Languages

Shaw提倡架构设计手册应当与传统工程学科保持同步;这“四人帮”的书、Coplien的文献较早对设计模式进行了分类。

相较于架构风格,软件设计模式更加关注待解决的问题。Shaw基于架构风格给出了8种架构模式;Buschmann深入研究了面向对象开发中的架构风格。但这些文献很少研究架构模式间的不同。

Tepfenhart与Cusick使用二维图比较了domain taxonomies, domain models, architectural styles, frameworks, kits, design patterns及applications。设计模式用于构筑软件架构;架构模式是一类架构的特征;但他们却没有给出架构的定义。

1.8.3 Reference Models and Domain-specific Software Architectures (DSSA)

Reference model给出了描述软件架构及组件间关系的概念框架;OMG提出了一种称为Object Management Architecture (OMA)的Reference model,这个模型定义了如何创建对象、如何共享对象等,OMA抢到对象的管理而非应用。

Hayes-Roth提出了domain-specific software architecture (DSSA) 。这种模型包括:a)特定应用领域的参考框架;b)可重用的组件库;c)应用配置。

DSSA在ADAGE、AIS等某些领域取得了成功。DSSA强调组件重用,而非为某一系统选择架构风格。

1.8.4 Architecture Description Languages (ADL)

近几年,软件架构方面的文献主要是研究architecture description languages (ADL)。Medvidovic与Taylor认为ADL是对系统概念架构模型及描述的语言,至少包括:components, component interfaces, connectors及architectural configurations。

Darwin是一种通用的描述系统结构的语言。Darwin可以对分布式架构及组件架构进行描述。

UniCon可由component、connector来构建架构。Wright提出了一个描述组件间相互作用的原则。

与设计方法一样,ADL也会引入一些假定,这些假定可能会影响其描述架构风格的能力,这些假定也可能与中间件中的假定有冲突。有时,ADL只能用于描述某一种架构风格。比如,C2SADEL是一种仅能描述C2架构的ADL;与之相反,ACME是一种较为通用的ADL,但却不适合用于架构风格分析、构建实际应用。

1.8.5 Formal Architectural Models

Abowd认为可以按照架构语义到架构描述的映射来表述架构风格。但是,这实际上是假定了架构是可描述的,而非运行时的抽象。

Inverardi与Wolf认为可以把架构元素类比成化学制品,这个模型描述了组件间如何变换数据、但对于那些不进行数据流变换的系统来说,如何使用这种模型就不太清楚。

Rapide是一种基于事件的定义、描述架构的语言。Le Métayer则提出了一种基于图的架构定义方式。

1.9 Summary

本章介绍了本文的研究背景。为了避免理解上的混淆,引入了一些软件架构定义相关的术语。特别是,在软件架构定义中,将data作为一个架构元素,同时总结了其他人在架构、架构风格方向的研究。

接下来的两章,就网络应用程序,将介绍架构风格相关的背景,如何使用架构风格来进行架构设计;然后介绍一些常见的架构模式。

Chapter 2 Network-based Application Architectures

本章继续讨论网络应用程序的架构以及如何进行架构设计。

2.1 Scope

软件系统在不同层面会有不同的架构。本文主要研究系统顶级架构,即网络应用程序的各个组件的关系。在这里,为了降低复杂性,本文仅讨论网络应用程序的架构风格。

2.1.1 Network-based vs. Distributed

与一般软件系统不同,在网络应用程序中,组件间是通过消息传递进行通信。

Tanenbaum等人比较了分布式系统与网络应用程序。分布式系统运行在不同的CPU之上,但对用户来说就像一个普通的本地程序;网络应用程序通过网络来运行,但对用户来能够觉察到网络的存在。有时,最好是能够让用户觉察到网络请求与本地请求间的区别。本文研究的网络应用程序。

2.1.2 Application Software vs. Networking Software

本文研究应用级架构,而不是操作系统、网络软件等。应用指的是系统中业务逻辑部分。

应用级软件架构是系统总体的抽象,使用架构属性来表示用户操作目的。比如说,超媒体系统关注信息页面的位置、处理请求、渲染数据流。而网络系统仅仅关注将字节流从一个位置移到另外一个位置,但并关心字节流移动的目的。在应用层面可以对系统设计进行评测。

2.2 Evaluating the Design of Application Architectures

本文的目的之一是提供一组原则用于指导应用程序架构的选择或者创建。需要牢记,架构是架构设计的实现而非架构设计。可以通过架构运行时的特征来评价架构,但我们更想在架构设计实现之前就能对架构进行评价。但架构设计是很难进行评价的,架构设计存在与架构师的头脑中,直到架构设计完成才能得到真正的架构。为了评价架构设计,需要研究架构约束背后的原理,这些约束带来的架构属性能否满足目标需求。

首先可以通过功能性需求来评价架构设计。如果架构设计不能够满足系统功能性需求,这种架构设计是没有意义的。架构属性是由架构约束决定的,因此可以通过研究架构约束来比较不同的架构设计。

在前面已经说过,架构风格实际上就是一组架构约束。每一种架构设计可以看作是一种架构风格的应用。增加一个架构约束就可以创建一种架构风格,因此可以把所有架构风格构成的集合看作是一棵架构约束树:树的根节点不包含任何的架构约束,是个空的架构风格。只要架构风格不冲突,便可通过组合多个架构风格来生成混合架构风格。因此,评价架构设计就可以通过将架构风格拆分成各种架构约束,通过研究架构约束的属性来研究最终架构的属性,进而比较哪一种架构设计满足目标需求

需要注意的是,一个架构约束可能会与其他架构约束存在冲突,但架构师也是可以通过这种架构约束树来设计架构。总之,这种架构约束树是可以用于指导架构设计的

架构属性的评价依赖于具体的应用领域。比如说,pipe-and-filter风格对需要数据变换的系统是有用的,但对于仅包含控制消息的系统是没有作用的。因此,比较不同应用领域内的架构设计是没有意义的。

架构设计的评价是个权衡的问题。Perry与Wolf提出了一种权衡架构设计的方法:对每个架构属性赋予一个权重来表征其重要性,进而可以度量各种架构设计。但这需要为每个架构属性选择合适的权重值,这个通常就比较困难。相较于这种权重值的方法,我更加倾向于把所有信息以可视化的方式展现给架构师。这将在下一章进行讲解。

2.3 Architectural Properties of Key Interest

本节研究用于架构风格分类的架构属性。我仅仅列举了部分架构风格的相关属性,其他的一些属性,有时也称作软件质量属性,可以参见软件工程相关的书籍。

2.3.1 Performance

网络应用程序需要关注组件间的相互作用,这将会决定用户性能体验及网络效率。因为架构风格影响组件间的相互作用,因此,架构风格选择正确与否,直接决定了网络应用程序的成功与失败。

网络应用程序的性能首先受限于应用需求,其次是架构风格的选择,再次是架构风格的实现;最后是架构组件的实现。也就是说,软件不可避免应有需求导致的开销,比如,系统需要把本地A的数据传输到远程B进行处理. 同样的,系统性能也不大可能超过其架构风格的设定,比如从A到B的多个数据传输,不会比从A到B的单个数据传输的性能更高。最后,不管软件架构的属性如何,如果具体实现时,如果不采用组件间交互,而是组件产生数据并处理处理数据,性能肯定要更快一些。

2.3.1.1 Network Performance

2.3.1.2 User-perceived Performance

2.3.1.2 Network Efficiency

2.3.2 Scalability

Scalability指的是架构中支持多个组件及其相互作用,通过简化组件、将服务分散到各个组件等可以提高系统Scalability。软件架构风格通过组件间的耦合度等影响系统的Scalability。

Scalability也受组件间相互作用的频率的影响。

2.3.3 Simplicity

Simplicity主要使用关注点分离将功能分散到不同的组件,这样更加容易的理解、维护组件,这也更加有助于理解软件架构。本文把complexity、understandability、verifiability统称为Simplicity。

架构元素的通用性有助于提升Simplicity。

2.3.4 Modifiability

Modifiability指的是修改软件架构的难易程度。Modifiability可进一步分为evolvability、extensibility、customizability、configurability、reusability。网络应用程序更加关注动态Modifiability,即不需要重启系统来实现对系统的修改。

实现满足用户需求的系统相对比较简单,但是用户的需求是不断变化的。网络应用程序的组件分散在各处,因此系统组件必须要能够适应未来的变化。

2.3.4.1 Evolvability

2.3.4.2 Extensibility

2.3.4.3 Customizability

2.3.4.4 Configurability

2.3.4.5 Reusability

2.3.5 Visibility

Visibility是系统组件可以监控组件间相互作用的能力,mobile agent style就是一种缺乏Visibility而导致安全问题的风格。

2.3.6 Portability

如果软件可以在多种环境下运行,则软件就是可移植的。支持移植性的风格包括那些将数据与代码打包在一起的风格,比如virtual machine、mobile agent styles;也包括那些使用标准数据格式的架构风格。

2.3.7 Reliability

Reliability是系统内部分components,、connectors、data等失效后,系统能否正常运行。避免单点故障、系统冗余等可用于提高系统的可靠性。

2.4 Summary

本章说明了本文的研究范围,讲述了如何使用架构风格来指导架构的设计,同时也给出了一些架构属性。

下一章将会研究网络应用程序中常见的架构风格,并对这些架构风格的属性进行分析。

Chapter 3 Network-based Architectural Styles

本章依据架构属性对网络应用程序中常见的架构风格进行分类。

3.1 Classification Methodology

编写软件不是为了创建一种(组件)交互的拓扑,也不是为了使用某某种组件,而是为了满足特定的需求。为了指导架构设计,需要依据软件属性对这些架构风格进行分类。

3.1.1 Selection of Architectural Styles for Classification

分类中所包含的架构风格仅是网络应用程序相关的部分架构风格。实际上,通过引入新的架构约束,可以在已有架构风格的基础之上形成新的架构风格。本文描述了一些软件架构文献中提到的架构风格,并且给出了如何进行架构风格进行分类。

本文主要针对网络应用程序,因此不关注那些非通信类的架构风格。比如说,blackboard架构包含一个中心repository及一组components,通过将components分布在不同主机上,可以将blackboard改造成网络应用程序,但是这种扩展实际上是取决于所使用的的分布式架构风格。因此,尽管blackboard架构可以扩展为网络应用系统,把这种架构风格放在此处讨论是没有意义的。

3.1.2 Style-induced Architectural Properties

本文使用架构属性来对软件架构风格进行分类。需要注意的是,架构属性依赖于所研究的系统类型增加一个架构约束,可以提高/降低系统的某一质量属性(或者是质量属性的某些方面)

尽管本文会讨论网络系统中的多种架构,但我们主要研究网络超媒体系统相关的架构风格。通过聚焦于某一特定的系统,可以更好的对架构风格进行评价。因为本文不想研究某种普适性的架构风格,把讨论集中在某一类型系统,可以减少评价架构风格的影响因素。可以在未来,研究同一种架构风格在不同类型的应用。

3.1.3 Visualization

本文使用一张架构风格-架构属性的表格来对架构风格进行分类。在这张表格中,每一行对应一种架构风格,每一列表示表示一种架构属性。负号"-"表示表示对某类属性起副作用;正号"+"表示对某类属性起正作用;正负号"\pm"表示可能产生正作用,也可能产生副作用。尽管这种方法比较粗糙,但是却可以或多或少的反应架构属性。

也可以使用基于架构属性的图来对架构风格进行分类,这种方法通过架构风格见得派生关系来对架构风格进行分类,架构风格间的弧线表示增加/较少某种架构属性。这个架构属性图的根节点是一个空的架构风格(不包含任何的架构约束)。

3.2 Data-flow Styles

 3.2.1 Pipe and Filter (PF)

在PF(pipe and filter)风格中,component(也被称为filter)读取数据流、进行处理、输出数据流。这种架构风格是一种单向数据流,filter之间必须完全独立,不能够共享状态、控制线程等。

Abowd适应Z语言给出了一种PF的描述。Khoros 是使用PF风格构造了很多应用。

Garlan与Shaw总结了PF架构风格的优点:首先,PF风格可以让设计者把系统输入输出当作filter组合;第二,PF格式支持重用,任意两个filter可以连接起来,只要它们之间的数据流保持一致;第三,PF格式易于维护与扩展,可以加入新的新的filter,同时可以替换旧的filter;第四,PF格式支持throughput、deadlock等分析;最后,适合于并行。

PF风格的缺点包括:传播延迟、批量顺序处理、不支持交互等。

PF格式一个不大太明显的问题是,需要按照某种配置来编排filters来实现系统功能。需要依据不同的任务与数据流,编排这些filters。而这种控制功能可以看作是系统的另一个运行状态。

3.2.2 Uniform Pipe and Filter (UPF)

在UPF(uniform pipe and filter)架构风格中,所有的filter必须有相同的接口。可以在Unix系统中发现很多这种例子,每个filter有一个输入: stdin,两个输出:stderr与stdout。通过接口的限制可以开发不同的filter,这也有助于理解每个filter是如何工作的。

UPF风格的缺点是,如果不同filter之间需要进行数据格式的转换,这种风格可能会降低系统性能。

3.3 Replication Styles

 3.3.1 Replicated Repository (RR)

RR(replicated repository)风格用于改进数据的可用性及服务的伸缩性。这些服务器对外看起来像仅有一台中心化服务器。XMS分布式系统与CVS远程版本管理系统就是使用了这种架构风格。

这种架构风格通过降低请求延迟与提高服务可用性来改进用户的体验。这种架构风格难易成都一般,要点在于保持一致性。

3.3.2 Cache ($)

作为RR风格的变种,Cache风格通过缓存请求结果来加快后续相同请求的响应。这种缓存方法主要用于服务端数据远多于客户端的情形,比如WWW;也适用于不需要访问整个数据仓库的情形。Lazy replication依据引用与关注度将本地没有的响应放到缓存中;Active replication依据预测来装填响应缓存。

相较于RR风格,Cache风格对系统性能的提升并不大,这是因为不一定能够在缓存中找到对应的响应。另一方面,Cache风格比较容易实现。当与client-stateless-server风格结合使用时,Cache风格也可以用于网络应用。

3.4 Hierarchical Styles

 3.4.1 Client-Server (CS)

Client-Server风格是网络应用程序最为常见的架构风格。Sever组件用于对外提供服务,监听并处理客户端请求。Client发送请求到Server。Server将会处理请求或者拒绝请求。Sinha与Umar对一系列Client-Server风格变体进行了研究。

Andrews对Client-Server风格进行了如下描述:客户端发起请求,服务端处理请求,因此客户端根据自己的选择来触发请求,指导请求处理完毕Client才算完成响应。另一方面,服务端处理请求,服务端一直持续工作,并且可以为多个客户端提供服务。

关注点分类是Client-Server风格背后的架构约束。合理的功能分离能够提高Server的伸缩性,通常将用户交互部分移到Client端。只要接口不变,这种分离允许客户端、服务端独自演化。

Client-Server风格并没有限定应用程序状态如何在Client与Server间分布,而这主要受connector实现影响,比如 remote procedure call与message-oriented middleware。

3.4.2 Layered System (LS) and Layered-Client-Server (LCS)

LS(layered system)将系统按照层次进行组织。每一层为上层提供服务,同时使用下层提供的服务。尽管LS模式通常与Client-Server风格一起使用,实现layered-client-server。

LS风格通过隐藏层内实现来提升evolvability与reusability,比如TCP/IP协议栈。LS风格主要缺点是会降低系统响应的性能,进而影响用户体验。

Layered-client-server风格在LS风格的基础之上增加了proxy、gateway等组件。proxy接收Client请求,并将转发请求;gateway将请求转发给内部的Server,对外看起来像是一个Server。也可以通过增加mediator组件来实现负载均衡、安全性检查等功能。

文献中常将 layered-client-server 成为两层、三层、多层架构。

LCS也可用于大规模分布式系统的身份管理。在这类系统中,熟知所有的Server的成本令人望而生畏,那些很少用到的服务将会有intermediaries处理。

3.4.3 Client-Stateless-Server (CSS)

作为CS风格的变种,CSS(client-stateless-server)风格不会在Server端存储会话状态。每次请求都必须包含足够的信息以使Server能够理解请求,而不能使用Server端存储的上下文信息。会话状态完全存储在Client端。

这个架构约束有利于提升系统的visibility、reliability、scalability等。

CSS风格的缺点是可能降低系统性能,因为由于Server端不保存会话状态,Client连续的请求需要发送若干重复的数据。

3.4.4 Client-Cache-Stateless-Server (C$SS)

C$SS(client-cache-stateless-server)风格基于CSS风格与Cache风格,C$SS在Client-Server之间引入了Cache组件用于请求/响应的缓存。典型的例子是Sun Microsystems的NFS。

增加Cache组件的好处是可以在某种程度上消除某些交互,进而提升用户体验。

3.4.5 Layered-Client-Cache-Stateless-Server (LC$SS)

LC$SS(layered-client-cache-stateless-server)风格基于 layered-client-server与client-cache-stateless-server,引入了proxy/gateway组件。DNS(domain name system)便使用了LC$SS风格。

LC$SS具有LCS风格与C$SS风格的优缺点。

3.4.6 Remote Session (RS)

RS(remote session)风格基于CS风格,旨在降低Client的复杂性、同时提升Client的可重用性。Client向Server发起会话,触发一系列服务请求,然后退出。应用状态完全存储在Server。在TELNET、FTP中就是用这种架构风格。

RS风格有利于维护Server接口、降低Client的不一致性、提高系统性能等。但RS风格不利于Server的可伸缩性及交互的可见性。

3.4.7 Remote Data Access (RDA)

作为CS风格的一个变种,RDA(remote data access)风格将应用状态分散在Client与Server。Client发送一个SQL查询请求,Serverf分配工作空间进行查询。Client可以进一步获取数据,Client必须要知道服务的数据结构。

RDA风格可以提升系统的efficiency与visibility,但不利于simplicity、scalability、reliability。

3.5 Mobile Code Styles

Mobile code风格通过mobility来减少数据到业务处理之间的距离。Fuggetta对这类风格进行了深入的研究。在这类架构中,引入了site用于处理不同组件的位置;引入location用于处理组件间的相互作用。同一位置的组件间的交互成本要比不同位置的组件狡猾的成本小很多。改变组件的位置,可能减少交互成本,进而提升用户体验。

在所有的Mobile code风格中,data element会被当做一个组件。Fuggetta依据data element尺寸分析了mobility是否适用于某个action,如果架构不包含data element,这是做不到的。

 3.5.1 Virtual Machine (VM)

所有mobile code风格的基础是VM(virtual machine)风格。代码必须在一定环境下运行,这正是VM风格提供的功能。VM风格通常与CS风格搭配使用。

VM经常用作Perl、PostScript等脚本语言的引擎。主要好处实现了指令与具体实现的分离,提升了portability、extensibility,但不利于Visibility、simplicity。

3.5.2 Remote Evaluation (REV)

REV(remote evaluation)风格基于CS风格与VM风格,Client决定是否发起请求,但缺少CPU等资源,因此,Client发送请求到Server,Server完成请求处理,并将结果返回给Client。来自不同客户端的请求在同一Servers上执行不会相互影响。

REV风格有利于系统的extensibility、customizability;但不利于simplicity、scalability、visibility。

3.5.3 Code on Demand (COD)

在COD(code-on-demand)风格中,client具备一些计算资源,但是并不知道如何处理业务请求,client发送一个请求码给server,server返回需要执行的代码,client在本地执行这些代码。

COD风格有利于extensibility、configurability、scalability;但不利于simplicity、visibility。

3.5.4 Layered-Code-on-Demand-Client-Cache-Stateless-Server (LCODC$SS)

LCODC$SS(Layered-Code-on-Demand-Client-Cache-Stateless-Server)风格是 LC$SS风格与COD风格的结合。HotJava Web browser就是用了这种风格。

LCODC$SS具有LC$SS风格与COD风格的优缺点。

3.5.5 Mobile Agent (MA)

在MA(mobile agent)风格中,计算组件被移到site中,可以看作是REV风格与COD风格的结合。

MA风格最大的优点是可以动态选择代码的移动,同时提高了reliability。

3.6 Peer-to-Peer Styles

 3.6.1 Event-based Integration (EBI)

EBI(event-based integration)风格可以降低组件间的耦合度。一个组件可以触发一个或者多个事件,其他的组件可以注册感兴趣的事件,当一个组件触发一个事件之后,其他的组件将会调用对应的事件处理。这种风格的例子包括Smalltalk-80的Model-View-Controller、许多应用中的集成机制。

EBI风格很容易添加新的组件以监听某个事件,通过通用接口,不仅可以实现重用性,也可以实现组件的独立开发。与PF风格类似,EBI风格也需要预先依据接口配置组件。许多EBI系统也支持显示调用,对于那些数据监控类的应用,EBI可以避免轮询,进而提高系统性能。

EBI实际上就是多个组件通过一个事件总线来监控事件。但EBI风格存在scalability问题,使用分层系统与事件过滤,可以在某种程度上改善EBI风格。

另外,EBI风格存在较差的understandability,也不适合大粒度的数据。当发生故障之后,也缺少一种恢复机制。

3.6.2 C2

C2风格基于EBI风格与LCS风格,主要用于大粒度地重用代码与灵活地组合组件。异步通知消息与异步请求消息是C2风格的核心,这改善了组件间的耦合,同时保留了EBI风格绝大数的优势。

当组件状态发生变化时便会发出通知消息,C2风格并没有规定通知消息应当包含哪些数据,使用connector进行消息的路由与广播,connector也可以用于消息的过滤。通过在EBI风格引入LCS风格,可以改善系统的scalability、evolvability、reusability,采用轻量级的connector可以改善visibility、reliability。

3.6.3 Distributed Objects

在distributed objects风格中,整个系统被看作是由一些相互作用的组件构成。对象包括属性、方法、控制线程等。通常对象的属性对外不可见,只能通过调用对象的公有方法来修改对象的状态。这可以屏蔽对象的实现细节,进而提高了evolvability。

一个操作可能包含对多个对象的操作,可以把一组相关联的调用称之为action。状态信息可能分散在多个对象,这有利于保持对象状态始终为最新,但是却不利于visibility。

组件必须知悉其他对象,方能调用其他对象。当一个对象发生变化,它必须通知所有其他相关对象。在这个系统中需要controller对象来管理系统状态。distributed object存在以下问题:对象管理、对象交互管理、资源管理。

对象系统主要用于隔离数据,因此,通常不会支持数据流,但与MA风格相比,却提供了更好的mobility。

3.6.4 Brokered Distributed Objects

为了减少对象身份认证的影响,现代分布式对象系统使用EBI、brokered client/server等风格来帮助通信。brokered distributed object通过引入name resolver组件来帮助client找到能够处理对应请求的对象。这可以提高系统的reusability、evolvability,但却降低了efficiency。

OMG CORBA与 ISO/IEC ODP中存在许多brokered distributed object 系统。

与其他网络应用程序架构风格相比,distributed objects发展并不太成功。这种架构风格主要用于服务的远程调用。

3.7 Limitations

每一种架构风格都会提出一种组件间交互的方式,当组件分布在网络上,能否只缺使用网络将决定(架构风格)可用性。依据架构属性来描述架构风格,特别是针对网络应用程序,有助于为应用程序选择合适的架构风格。但是,这过程中是存在一些限制的。

第一个限制是所有的分类是针对网络应用程序的。比如,如果通信采用细粒度的消息,PF风格中有许多架构属性将不复存在,甚至对于交互类应用,这些架构属性可能不合适。同样的,如果客户端请求不能够进行缓存,分层缓存仅会增加延迟而已。这些东西在架构风格分类的时候并没有进行过讨论,需要针对每种架构风格进行说明。本文人文这些问题可以通过另外一个架构风格分类表解决,比如,large grain data retrieval,remote information monitoring,search,remote control systems,distributed processing。

第二个限制是关于架构属性的分类。有时,understandability、verifiability可能比simplicity更加合适。特别是有些架构风格降低了understandability却提升了verifiability。一个解决方法就是分类需要包含架构属性与汇总属性。

尽管如此,这个分类可以作为后续其他分类的基础。

3.8 Related Work

3.8.1 Classification of Architectural Styles and Patterns

本章主要是对架构风格进行了分类。

Shaw对许多架构模式进行了描述,Garlan与Shaw对这些架构风格进行了扩展。Shaw与Clements使用二维表格对这些架构风格进行了分类。

与本章不同,Shaw与Clements的分类对设计师并没有太多用处。这个问题在于构造软件的目的不在于使用某种组件,所以他们那种分类方法没有太多用。而且也混淆了架构风格与一些其他问题。再者,他没有针对特定的应用来研究架构风格。最好,他们也没研究架构风格如何进行组合。

Buschmann与Meunier依据抽象、功能等粒度提出了一种分类方法,他们把架构风格分成了三类:architectural frameworks、design patterns、idioms。这种分类方法解决了本文中的一些问题,但是仅涉及两个架构风格。Buschmann对这种分类方法进行了拓展。

Zimmer依据图研究了研究了设计模式,这样就更加容易理解GoF的设计模式,但是这不是针对的架构风格,而且这种分类也不是基于架构属性。

3.8.2 Distributed Systems and Programming Paradigms

Andrews调研了分布式系统中进程间如何通过消息进行通信。他定义了并行程序、分布式程序、分布式程序中额各种业务处理、交互范式、通信通道。交互范式指的是架构风格的通信方面,他描述了单向数据流中的范式。但是给出的是多个业务逻辑处理同一个任务,而非一种通用的网络应用程序架构风格。

Sullivan与Notkin研究了隐式调用及其对系统的影响。Barrett构建了一个框架用以研究EBI风格。Rosenblum与Wolf研究了一种针对企业通知的设计框架。这些仅是针对的是EBI风格,而非网络应用。

Fuggetta对mobile code范式进行了分类。本章基于他的工作,比较网络应用中的各种mobile code 风格。

3.8.3 Middleware

Bernstein认为middleware作为分布式服务包含一些编程接口与协议。这些服务称为middleware,middleware处于OS与网络之上、行业应用层之下。Umar深入地研究了这方面的内容。

对middleware的架构研究主要集中于集成这些middleware组件的效果。Di Nitto与Rosenblum研究了使用middleware组件对系统架构的影响,以及如何选择middleware。Dashofy就在C2风格中使用middleware进行了讨论。

Garlan等指出组件中的一些架构假定,分析了重用子系统过程中的而一些问题。他们将问题分成了四类:nature of components,nature of connectors,global architectural structure, construction process。

3.9 Summary

本章依据架构属性对网络应用程序中常见的架构风格进行了分类。整个架构风格分类可以参见表格3-6。

 下一章将基于这些调研与分类方法,研究现代Web应用的架构设计方法。

猜你喜欢

转载自blog.csdn.net/qq_26221775/article/details/130899461