第九章 软件架构设计

9.1 软件架构概述

9.1.1 软件架构的定义

定义1:软件或计算机系统的软件架构是该系统的一个(或多个)结构,而结构有软件元素、元素的外部可见属性及他们之间的关系组成。
定义2:软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构成系统的元素的描述、这些元素的相互作用、指导元素集成的模式及这些模式的约束组成。
定义3:软件架构是指一个系统的基础组织,它具体体现在:系统的构件,构建之间、构件和环境之间的关系,以及知道其设计和烟花的原则上。
为更好的理解软件架构的定义,特作如下说明:

  1. 架构是对系统的抽象,它通过描述元素、元素的外部可见属性,以及元素之间的关系来反映这种抽象。因此,仅与内部具体实现有关的细节是不属于架构的,即定义强调元素的“外部可见”属性。
  2. 架构有多个结构组成,结构是从功能角度来描述元素之间的关系的,具体的结构传达了架构某方面的信息,但是个别结构一般不能代表大型软件架构。
  3. 任何软件都存在架构,但不一定有对盖家沟的具体表述文档。即架构可以独立于架构的描述而存在。如文档已过时,则该文档不能反映架构。
  4. 元素及其行为的集合构成架构的内容。体现系统由哪些元素组成,这些元素各有哪些功能(外部可见),以及这些元素间如何连接与互动。即在两个方面进行抽象:在静态方面,关注系统的大粒度(宏观)总体结构(如分层);在动态方面,关注系统内关键行为的共同特征。
  5. 架构具有“基础”性:它通常涉及解决各类关键的重复问题的通用方案(复用性),以及系统设计中影响深远(架构敏感)的各类重要决策(一旦贯彻,更改的代价昂贵)。
  6. 架构隐含有“决策”,即架构是由架构设计师根据关键的功能和非功能性需求(质量属性即项目相关的约束)进行设计和决策的结果。不同的架构设计师设计出来的架构是不一样的,为了避免架构设计师考虑不周,重大决策应该经过评审。特别是架构设计师自身的水平是一种约束。

在设计软件架构时也必须考虑硬件特性和网络特性。架构设计师通常将架构的重点放在软件部分。

  1. 影响架构的因素。软件系统的项目干系人(客户、用户、项目经理、程序员、测试人员、市场人员等)对软件系统有不同的要求,开发组织(项目组)有不同的人员知识结构、架构设计师的素质和经验、当前技术环境等方面都是影响架构的因素。
    这些因素通过功能性需求、非功能性需求、约束条件及相互冲突的要求,影响架构设计师的决策,从而影响架构。
  2. 架构对上述诸因素具有反作用。系统的示范性、架构的可复用性及团队开发经验的提升,同时,成熟的系统将影响客户对下一个系统的要求等。这种反馈机制构成了架构的商业周期。

    9.1.2 软件架构的重要性

    从技术角度看,软件架构的重要性表现为如下几个方面:

  3. 项目关系人之间交流的平台。

  4. 早期设计决策。从软件生命周期来看,软件架构是所开发系统的最早设计决策的体现,主要表现为:
  • 架构明确了对系统实现的约束条件:架构是架构设计师对系统实现的各方面进行权衡的结果,是总体设计的体现,因此,在具体实现时必须按架构的设计进行。
  • 架构影响着系统的质量属性。
  • 架构可以用来预测系统的质量。
  • 架构为维护的决策提供依据。在架构层次上能为日后的更改决策提供推理、判断的依据。
  • 架构有助于原型开发。可以按照架构构造一个骨架系统。
  • 借助于架构进行成本和进度的估计。
  1. 在较高层面上实现软件复用。软件架构作为系统的抽象模型,可以在多个系统间进行传递(复用),特别是比较容易的应用到具有相似质量属性和功能需求的系统中。产品线通常可以共享一个脚骨。
  2. 架构对于开发的指导和规范意义不容忽略。

从软件开发过程来看,如果采用传统的软件开发模型(生命周期模型),则软件架构的建立应位于概要设计之前、需求分析之后。
基于架构的软件开发模型则明确的把整个软件过程划分为架构需求、设计、文档化、评审(评估)、实现、演化等6个子过程。

9.1.3 架构的模型

软件架构可以归纳为5种模型:结构模型、框架模型、动态模型、过程模型和功能模型。最常用的是结构模型和动态模型。

  1. 结构模型。是一个最直观、最普遍的建模方法。这种方法以加过的构件、连接件和其他概念来刻画结构,并力图通过结构来反映系统的重要语义内容,包括系统的配置、约束、隐含的假设条件、风格、性质。研究结构模型的核心是架构描述语言。
  2. 框架模型。与结构模型类似,但它不太侧重描述结构的细节而更侧重于整体的结构。框架模型主要以一些特殊的问题为目标建立只针对和适应该问题的结构。
  3. 动态模型。是对结构或框架模型的补充,研究系统“大颗粒”的行为性质。例如,描述系统的重新配置或演化。动态可能指系统总体结构的配置、建立或拆除通信通道或计算的过程。
  4. 过程模型。研究构造系统的步骤和过程。因而结构是遵循某些过程脚本的结果。
  5. 功能模型。该模型认为架构是由一组功能构件按层次组成,且下层向上层提供服务。可以看做是一种特殊的框架模型。

“4+1”的视图模型从5个不同的侧面,即逻辑视图、进程视图、物理视图、开发视图和场景来描述软件架构。每一个视图只关心系统的一个侧面,5个视图结合在一起才能反映系统的软件架构的全部内容。

  1. 逻辑视图:主要支持系统的功能需求,即系统提供给最终用户的服务。在逻辑视图中,系统分解成一系列的功能抽象,这些抽象主要来自问题领域。这种分解不仅可以用来进行功能分析,而且可以用作标识在整个系统的各个不同部分的通用机制和设计元素。在面向对象技术中,通过抽象、封装和继承,可以用对象模型来代表逻辑视图,用类图来描述逻辑视图。逻辑视图中使用的风格为面向对象的风格,逻辑视图设计中要注意的主要问题是要保持一个单一的,内聚的对象模型贯穿整个系统。
  2. 进程视图:侧重于系统的运行特性,主要关注一些非功能性的需求,例如系统的性能和可用性。进程视图强调并发性、分布性、系统集成性和容错能力,以及逻辑视图中的主要抽象的进程结构。它也定义逻辑视图中的各个类的操作具体是在哪一个线程中被执行的。进程视图可以描述成多层抽象,每个级别分别关注不同的方面。
  3. 物理视图:主要考虑如何把软件映射到硬件上,它通常要考虑到解决系统拓扑结构、系统安装、通信等问题。当软件运行于不同的节点上时,各视图中的构件都直接或间接的对应于系统的不同节点上。因此,从软件到节点的映射要有较高的灵活性,当环境改变时,对系统其它视图的影响最小。
  4. 开发视图:也称为模块视图,主要侧重于软件模块的组织和管理。软件可通过程序库或子系统进行组织。这样一个软件系统就可以由不同的人进行开发。开发视图要考虑软件内部的需求,如软件的容易醒、软件的重用性和通用性,要充分考虑由于具体开发工具的不同而带来的局限性。开发视图通过系统输入输出关系的模型图和子系统图来描述,可以在确定了软件包含的所有元素之后描述完整的开发角度,也可以在确定每个元素之前,列出开发视图原则。
  5. 场景:可以看做是那些重要活动的抽象,它是四个视图有机的联系起来,从某种意义上说,场景是最重要的需求抽象。在开发架构中,它可以帮助设计者找到架构的构件和它们之间的作用关系。同时,也可以用场景来分析一个特定的视图,或描述不同视图构件间是如何相互作用的。场景可以用文本表示,也可以用该图形小时。

    9.2 架构需求与软件质量属性

    软件属性包括功能属性和质量属性。但是,软件架构师重点关注的是质量属性。

    9.2.1 软件质量属性

    软件质量特性包括功能性、可靠性、易用性、效率、可维护性、可移植性等六个方面,每个方面都包含若干子特性。
  • 功能性:适合性、准确性、互操作性、依从性、安全性;
  • 可靠性:成熟性、容错性、易恢复性;
  • 易用性:易理解性、易学性、易操作性;
  • 效率:时间特性、资源特性;
  • 可维护性:易分析性、易改变性、稳定性、易测试性;
  • 可移植性:适应性、易安装性、遵循性、易替换性;

    1. 运行期质量属性

  • 性能: 指软件系统及时提供相应服务的能力。包括速度、吞吐量和持续高速性三个方面的要求。

  • 安全性:指软件系统同时兼顾向合法用户提供服务,以及阻止非授权使用的能力。
  • 易用性:指软件系统易于被使用的程度。
  • 可伸缩性:指当用户数和数据量增加时,软件系统维持高服务质量的能力。例如,通过增加服务器来提高能力。
  • 互操作性:指本软件系统和其他软件系统交换数据和相互调用服务的难易程度。
  • 可靠性:软件系统在一定的时间内无故障运行的能力。
  • 持续可用性:指系统长时间无故障运行的能力。与可靠性相关联,常将其纳入可靠性中。
  • 鲁棒性:指软件系统在一些非正常情况下(如用户进行了非法操作、相关的软硬件系统发生了故障等)下仍能正常运行的能力,也称健壮性或容错性。

    2. 开发期质量属性

  • 易理解性:指设计被开发人员理解的难易程度。

  • 可扩展性:软件因适应新需求或需求变化而增加新功能的能力。也称为灵活性。
  • 可重用性:指重用软件系统或某一部分的难易程度。
  • 可测试性:对软件测试以证明其满足需求规范的难易程度。
  • 可维护性:当需求修改缺陷、增加功能、提供质量属性时,定位修改点并实施修改的难易程度。
  • 可移植性:将软件系统从一个运行环境转移到另一个不同的运行环境的难易程度。

下表反映了质量属性之间的相互制约关系(正相关或负相关),其中“+”代表“行属性”能促进“列属性”;而“-”则相反。
~|性能|安全性|持续可用性|可互操作性|可靠性|鲁棒性|易用性|可测试性|可重用性|可维护性|可扩展性|可移植性
—-|—-
性能||||-|-|-|-|-||-|-|-
安全性|-|||-|||-|-|-
持续可用性|||||+|+
可互操作性|-|-|||||||||+|+
可靠性|-||+|||+|+|+||+|+
鲁棒性|-||+||+||+
易用性|-|||||+||-
可测试性|-||+||+||+|||+|+
可重用性|-|-||+|-|||+||+|+|+
可维护性|-||+||+|||+|||+
可扩展性|-|-|||+|||+||+||+
可移植性|-|||+|||-|+|+|-|+

9.2.2 6个质量属性及实现

从架构关注点角度,将质量属性分为六种:可用性、可修改性、性能、安全性、可测试性、易用性。
质量属性场景由以下六个部分组成:

  • 刺激源:生成该刺激的实体(人、计算机系统或其他激励器)
  • 刺激:到达系统时可能产生的影响(即需要考虑和关注的情况)
  • 环境:该刺激在某条件内发生。如系统可能正处于过载情况。
  • 制品:系统中受刺激的部分(某个制品被刺激)
  • 响应:刺激到达后所采取的行动
  • 响应度量:当响应发生时,应能够以某种方式对其度量,用于是否满足需求的测试。

需要将一般的质量属性场景与具体的质量属性场景区别开来,前者是指独立于具体系统、适合于任何系统的一般性场景;而后者是指适合于正在考虑的某个特定系统的场景,具体场景通常是指从一般场景中抽取特定的、面向具体系统的内容。
实现这些质量属性的基本设计决策,称为”战术“,而把战术的集合称为”架构策略“。这些架构策略工架构设计师选择。

1. 可用性及其实现战术

1. 可用性的描述
场景的部分 可能的值
刺激源 系统内部、系统外部
刺激 错误:疏忽(构件对某输入未作出反应)、崩溃、时间不当(响应时间太早或太迟)、响应不当(以一个不正确的值来响应)
制品 系统的处理器、通信通道、存储器、进程
环境 正常操作、降级模式
响应 系统应检测事件,并进行如下一个或多个活动:
使其记录下来
通知合适的各方,包括用户和其他系统
根据规则屏蔽导致错误或故障的事件源
不可用(进入修理状态)
继续在正常或降级模式下运行
响应度量 可用时间、修复时间、各种情况的时间间隔

2. 可用性战术

目标是阻止错误发展成故障,至少能够把错误的影响限制在一定范围内,从而使修复称为可能。战术分为:错误检测、错误恢复、错误预防。

  1. 错误检测
  • 命令/响应:一个构件发出一个命令,并希望在预定义的时间内收到一个来自审查构件的响应,例如远程错误的检测
  • 心跳(计时器):一个构件定期发出一个信条消息,另一个构件收听到消息。如果未收到心跳消息,则嘉定构件失败,并通知错误纠正构件。
  • 异常:当出现异常时,异常处理程序开始执行。
  1. 错误恢复
  • 表决:通过冗余构件(或处理器)与表决器连接,构件按相同的输入及算法计算输出值给表决器,由表决器按表决算法(如多数规则)确定是否有构件出错,表决通常用在控制系统中。
  • 主动冗余(热重启、热备份):所有的冗余构件都以并行的方式对事件作出相应。它们都处在相同的状态,但仅使用一个构件的响应。丢弃其余构件的响应。错误发生时通过切换的方式使用另一个构件的响应。
  • 被动冗余(暖重启/双冗余/三冗余):一个构件(主构件)对事件作出响应,并通知其他构件(备用的)必须进行的状态更新(同步)。当错误发生时,备用构件从最新同步点接替主构件的工作。
  • 备件:是计算平台配置用于更换各种不同的故障构件。
  • 状态再同步:主动和被动冗余战术要求所恢复的构件在重新提供服务前更新其状态。更新方法取决于可以承受的停机时间、更新的规模以及更新的内容多少。
  • 检查点/回滚:检查点就是使状态一致的同步点,它或者是定期进行,或者是对具体事件作出响应。当在两个检查点之间发生故障时,则以这个一致状态的检查点(有快照)和之后发生的事务日志来恢复系统(数据库中常使用)。
  1. 错误预防
  • 从服务中删除:如删除进程再重新启动,以防止内存泄漏导致故障的发生。
  • 事务:使用事务来保证数据的一致性,即几个相关密切的步骤,要么全成功,要不全不成功。
  • 进程监视器:通过监视进程来处理进程的错误。

    2. 可修改性及其实现战术

    1. 可修改性的描述
    | 场景的部分 | 可能的值 | | —- | —- | | 刺激源 | 最终用户、开发人员、系统管理员 | | 刺激 | 增加/删除/修改/改变:功能、质量属性、容量 | | 制品 | 用户界面、平台、环境或关联系统 | | 环境 | 运行时、编译时、构建时、设计时 | | 响应 | 查找要修改的位置、进行修改(不影响其他功能)、进行测试、部署所修改的内容 | | 响应度量 | 对修改的成本进行度量,对修改的影响进行度量 |

2. 可修改性战术
  1. 局部化修改。在设计期间为模块分配责任,以便把预期的变更限制在一定的范围内,从而降低修改的成本。
  • 维持语义的一致性:语义的一致性指的是模块中责任之间的关系,是这些责任能够协同工作,不需要过多的依赖其他模块。耦合和内聚指标反映一致性,应该根据一组预期的变更来度量语义一致性。使用”抽象通用服务“(如应用框架的使用和其他中间软件的使用)来支持可修改性是其子战术。
  • 预期期望的变更:通过对变更的预估,进行预设、准备,从而使变更的影响最小。
  • 泛化该模块:使一个模块更通用、更广泛的功能
  • 限制可能的选择:如在更换某一模块(如处理器)时,限制为相同家族的成员。
  1. 防止连锁反应。由于模块之间有各种依赖性,因此,修改会产生连锁反应。防止连锁反应的战术如下:
  • 信息隐藏:就是把某个实体的责任分解为更小的部分,并选择哪些信息称为公有的,哪些称为私有的,通过接口获得公有责任。
  • 维持现有的接口:尽可能维持现有接口的稳定性。例如通过添加接口(通过新的接口提供新的服务)可以达到这一目的。
  • 限制通信路径:限制于一个给定的模块共享数据的模块。这样可以减少由于数据产生/使用引入的连锁反应。
  • 仲裁者的使用:在具有依赖关系的两个模块之间插入一个仲裁者,以管理与该依赖相关的活动。仲裁者有很多种类型,例如:桥、调停者、代理等就是可以提供把服务的语法从一种形式转换为另一种形式的仲裁者。
  1. 推迟绑定时间。系统具备在运行时进行绑定并允许非开发人员进行修改(配置)。
  • 运行时注册:支持即插即用
  • 配置文件:在启动时设置参数
  • 多态:在方法调用的后期绑定
  • 构件更换:允许载入时绑定

    3. 性能及其实现战术

    1. 性能的描述
    | 场景的部分 | 可能的值 | | —- | —- | | 刺激源 | 系统外部或内部 | | 刺激 | 定期事件、随机事件、偶然事件 | | 制品 | 系统 | | 环境 | 正常模式、超载模式 | | 响应 | 处理刺激、改变服务级别 | | 响应度量 | 度量等待、期限、吞吐量、缺失率、数据丢失等 |

2. 性能战术

性能与时间相关,影响事件的响应时间有两个基本因素:

  • 资源消耗:事件到达后进入一系列的处理程序,每一步处理都要占用资源,而且在处理过程中消息在各构件之间转换,这些转换也需要占用资源。
  • 闭锁时间:指对事件处理时碰到了资源争夺、资源不可用或对其他计算的依赖等情况,就产生了等待时间。

性能的战术有如下几种:

  1. 资源需求
  • 减少处理事件流所需的资源:提高计算效率(如改进算法)、减少计算开销(如在可修改性与性能之间权衡,减少不必要的代理构件)。
  • 减少所处理事件的数量:管理事件屡,控制采样频率。
  • 控制资源的使用:限制执行时间(如减少迭代次数)、限制队列大小。
  1. 资源管理
  • 引入并发
  • 维持数据或计算的多个副本:C/S结构中客户机C就是计算的副本,他能减少服务器计算的压力;高速缓存可以存放数据副本(在不同速度的存储器之间的缓冲)。
  • 增加可用资源:在成本允许时,尽量使用速度更快的处理器、内存和网络。
  1. 资源仲裁
    资源仲裁战术是通过如下调度策略来实现的
  • 先进/先出FIFO
  • 固定优先级调度:先给事件分配特定的优先级,再按优先级高低顺序分配资源。
  • 动态优先级调度:轮转调度、时限时间最早邮线
  • 静态调度;可以离线确定调度。

    4. 安全性及其实现战术

    1. 安全性的描述
    | 场景的部分 | 可能的值 | | —- | —- | | 刺激源 | 对敏感资源进行访问的人或系统(合法的、非法的) | | 刺激 | 试图:显示数据、改变/删除数据、访问系统服务、降低系统服务的可用性 | | 制品 | 系统服务,系统中的数据 | | 环境 | 在线或离线、联网或断网、有或无防火墙 | | 响应 | 对用户身份验证;阻止或允许对数据或服务的访问;授予可回收访问权;加密信息;限制服务的可用性;通知用户或系统 | | 响应度量 | 增加安全性的成本;检测或确定攻击的可能性;降低服务级别后的成功率;恢复数据/服务 |

2. 安全性战术

包括抵抗攻击、检测攻击和从攻击中恢复。

  1. 抵抗攻击
  • 对用户进行身份验证:包括动态密码、一次性密码、数字证书及生物识别码
  • 对用户进行授权:即对用户的访问进行控制管理
  • 维护数据的机密性:一般通过对数据和通信链路进行加密来实现
  • 维护完整性:对数据添加校验或哈希值
  • 限制暴露的信息
  • 限制访问:如用防火墙,DMZ策略。
  1. 检测攻击。一般通过“入侵检测”系统进行过滤、比较通信模式与历史基线等方法。
  2. 从攻击中恢复
  • 恢复:与可用性中的战术相同
  • 识别攻击者:作为审计追踪,用于预防性或惩罚性目的。

    5. 可测试性及其实现战术

    1. 可测试性的描述
    | 场景的部分 | 可能的值 | | —- | —- | | 刺激源 | 各类测试人员(单元测试、集成测试、验收、用户) | | 刺激 | 一种测试 | | 制品 | 设计、代码段、完整的应用 | | 环境 | 设计时,开发时、编译时、部署时 | | 响应 | 提供测试的状态值、测试环境与案例的准备 | | 响应度量 | 测试成本、出现故障的概率、执行时间等。 |

2. 可测试性战术
  1. 输入/输出
  • 记录/回放:指捕获跨接口的信息,并将其作为测试专用软件的输入
  • 将接口与实现分离:允许使用实现的替代(模拟器)来支持各种测试目的
  • 优化访问线路/接口:用测试工具来捕获或赋予构件的变量值。
  1. 内部监控。当监视器处于激活状态时,记录事件(如通过接口的信息)

    6. 易用性及其实现战术

    1. 易用性的描述
    | 场景的部分 | 可能的值 | | —- | —- | | 刺激源 | 最终用户 | | 刺激 | 学习系统特性、有效使用系统、使错误的影响最低、适配系统、对系统满意 | | 制品 | 系统 | | 环境 | 运行时或配置时 | | 响应 | 支持“学习系统特性”的响应:界面为用户所熟悉或使用帮助系统
    支持“有效使用系统”的响应:数据/命令聚合或复用;界面是导航;操作的一致性;多个活动同时进行
    支持“使错误的影响最低”的响应:撤销/取消;从故障中恢复;识别并纠正用户错误;验证系统资源
    支持“适配系统”的响应:定义能力;国际化
    支持“对系统满意”的响应:显示系统状态;与用户的节奏合拍 | | 响应度量 | 从最终用户的角度进行度量,如:学习成本、错误数量、解决问题的数量、满意度等 |

2. 易用性战术
  1. 运行时战术
  • 任务的模型:维护用户的信息,使系统了解用户试图做什么,并提供各种协助
  • 用户的模型:维护用户的信息,例如使系统以用户可以阅读页面的速度滚动页面。
  • 系统的模型:维护系统的信息,它确定了期望的系统行为,并向用户提供反馈。
  1. 设计时战术。将用户接口与应用的其余部分分离开来,预计用户接口会频繁发生变化,因此,单独维护用户接口代码将实现变更局部化。这与可修改性相关
  2. 支持用户主动操作。如支持“取消”、“撤销”、“聚合”和“显示多个视图”。

    9.3 软件架构风格

    软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式。架构风格定义了一个系统家族,即一个架构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束支出系统是如何将这些构件和连接件组合起来的。架构风格反映了领域中众多系统所共有的结构和语义特征,并指导如何将各个模块和子系统有效的组织成一个完整的系统。按这种方式理解,软件架构风格定义了用于描述系统的术语表和一组指导构件系统的规则。

    9.3.1 软件架构风格分类

    架构风格最关键的四要素内容:提供一个词汇表,定义一套配置规则,定义一套语义解释原则和定义对基于这种风格的系统所进行的分析。通用架构风格的分类:

  3. 数据流风格:批处理序列;管道/过滤器

  4. 调用/返回风格:主程序/子程序;面向对象风格;层次结构
  5. 独立构件风格:进程通信;事件系统
  6. 虚拟机风格:解释器;基于规则的系统
  7. 仓库风格:数据库系统;超文本系统;黑板系统

    9.3.2 数据流风格

    在该结构下,所有的数据按照流的形式在执行过程中前进,不存在结构的反复和重构,数据在流水点的各个结点上被加工,最终输出需要的结果。

    1. 批处理序列

    批处理风格的每一步都是独立的,并且每一步是顺序执行的。只有当前一步处理完,后一步才能开始。数据传送在步与步之间作为一个整体。(组件为一系列固定顺序的计算单元,组件间只通过数据传递交互。每个处理步骤一个独立的程序,每一步必须在前一步结束后才能开始,数据必须是完整的,以整体的方式传递)。
    批处理的典型应用:

  8. 经典数据处理

  9. 程序开发
  10. Windows下的BAT程序就是这种应用的典型案例

    2.管道和过滤器

    在该软件架构中,每个构件都有一组输入和输出,构件读输入的数据流,经过内部处理,然后产生输出流。这个过程通常通过对输入流的变换和增量计算来完成,所以输入被完全消费之前,输出便产生了。因此,这里的构件被称为过滤器。这种风格的连接件就像是数据流传输的管道,将一个过滤器的输出传到另一个过滤器的输入。过滤器必须是独立的实体,不能与其他的过滤器共享数据,而且一个过滤器不知道他上游和下游的标识。一个管道/过滤器网络输出的正确性并不依赖于过滤器进行增量计算过程的顺序。
    一个典型是以UNIX shell编写的程序,另一个例子是传统的编译器。
    管道/过滤器风格的软件架构具有很多很好的特点:

  11. 使得软构件具有良好的隐蔽性和高内聚、低耦合的特点

  12. 允许设计者将整个系统的输入/输出行为看成是多个过滤器的行为的简单合成。
  13. 支持软件重用。只要提供适合在两个过滤器之间传送的数据,任何两个过滤器都可被连接起来。
  14. 系统维护和增强系统性能简单。新的过滤器可以添加到现有系统中来;旧的可以被改进的过滤器替换掉
  15. 允许对一些如吞吐量、死锁等属性的分析
  16. 支持并行执行。每个过滤器作为一个单独的任务完成,因此可与其他任务并行执行。

但是,也存在若干不利因素

  1. 通常导致进程成为批处理的结构,这是因为虽然过滤器可增量式的处理程序,但它们是独立的,所以设计者必须将每个过滤器看成一个完整的从输入到输出的转换。
  2. 不适合处理交互的应用,当需要增量的显示改变时,这个问题尤为严重
  3. 因为在数据传输上没有通用的标准,每个过滤器都增加了解析和合成数据的工作,这样就导致了系统性能下降,并增加了编写过滤器的复杂性

    3. 批处理序列风格与管道过滤器风格对比

    共同点:把任务分成一系列固定顺序的计算单元(组件)。组件间指通过数据传递交互。
    区别:批处理是全部的、高潜伏性的,输入时可随机存取,无合作性、无交互性。而管道过滤器是递增的,数据结果延迟小,输入时处理局部化,有反馈、可交互。批处理强调数据在步与步之间作为一个整体,而管道过滤器无此要求。

    9.2.3 调用/返回风格

    1. 主程序/子程序

    是结构化时期的经典架构风格。这种风格一般采用单线程控制,把问题划分为若干处理步骤,构件即为主程序和子程序。子程序通常可合成为模块。过程调用作为交互机制,即充当连接件。调用关系具有层次性,其语义逻辑表现为子程序的正确性,取决于它调用的子程序的正确性。

    2. 面向对象风格

    这种风格建立在数据抽象和面向对象的基础上,数据的表示方法和它们的相应操作封装在一个抽象数据类型或对象中。这种风格的构件是对象,或是说是抽象数据类型的实例。对象是一种被称作管理者的构件,因为它负责保持资源的完整性。对象是通过函数和过程调用来交互的。
    这种风格的两个主要特征为:

  4. 对象负责维护其表示的完整性

  5. 对象的表示与其他对象而言是隐蔽的。因为一个对象对它的客户隐藏了自己的表示,所以这些对象可以不影响它的客户就能改变其实现方法。

面向对象的系统优点如下:

  1. 因为对象对其他对象隐藏它的表示,所以可以改变一个对象的表示,而不影响其他的对象;
  2. 设计者可以将一些数据存取操作的问题分解成一些交互的代理程序的集合。

存在的问题如下:

  1. 为了使一个对象和另一个对象通过过程调用等进行交互,必须知道对象的标识。只要一个对象的标识改变了,就必须修改所有其他明确调用它的对象;
  2. 必须修改所有显式调用它的其他对象,并消除由此带来的一些副作用。例如,如果A使用了对象B,C也使用了对象B,那么C对B的使用所造成的对A的影响可能是料想不到的。

    3. 层次结构风格

    层次系统组织成一个层次结构,每一层为上层服务,并作为下层客户。在一些层次系统中,除了一些精心挑选的输出函数外,内部的层只对相邻的层课件。这样的系统中构件在一些层实现了虚拟机(在另一些层次结构中层是部分不透明的)。连接件通过决定层间如何交互的协议来定义,拓扑约束包括对相邻层间的交互的约束。
    这种风格支持基于可增加抽象层的设计。允许将一个复杂问题分解成一个增量步骤序列的实现。由于每一层最多只影响两层,同时只要给相邻层提供相同的接口,允许每层用不同的方法实现,同样为软件重用提供了强大的支持。
    层次结构的优点如下:

  3. 支持基于抽象程度递增的系统设计,使设计者可以吧一个复杂系统被递增的步骤进行分解。

  4. 支持功能增强,因为每一层至多和相邻的上下层交互,因此功能的改变最多影响相邻的上下层
  5. 支持重用。只要提供的服务接口定义不变,同一层的不同实现可以交互使用。这样就可以定义一组标准的接口,而允许各种不同的实现方法。

层次结构的缺点如下:

  1. 并不是每个系统都可以很容易的划分分层的模式,甚至几十一个系统的逻辑结构是层次化的。出于对系统性能的考虑,系统设计师不得不把一些低级或高级的功能综合起来;
  2. 很难找到一个合适的、正确的层次抽象方法。

    9.3.4 独立构件风格

    主要强调系统中的每个构件都是相互独立的个体,它们之间不直接通信,以降低耦合度,提升灵活性。

    1. 进程通信架构风格

    构件是独立的过程,连接件是消息传递。这种风格的特点是构件通常是命名过程,消息传递的方式可以是点到点、异步和同步方式以及远过程调用等。

    2. 事件系统风格

    基于事件的隐式调用风格的思想是构件不直接调用一个过程,而是触发或广播一个或多个事件。一同中的其他构建中的过程在一个或多个事件中注册,当一个事件被触发,系统自动调用在这个事件中注册的所有过程,这样,一个事件的触发就导致了另一模块中的过程的调用。
    从架构上来说,这种风格的构件是一些模块,这些模块既可以是一些过程,又可以是一些事件的集合。过程可以用通用的方式调用,也可以在系统事件中注册一些过程,当发生这些事件时,过程被调用。
    基于事件的隐式调用风格的主要特点是事件的触发者并不知道哪些构件会被这些事件影响,这样不能假定构件的处理顺序,甚至不知道哪些过程会被调用。因此,许多隐式调用的系统也包含显示调用作为构件交互的补充形式。
    隐式调用系统的主要优点有:

  3. 为软件重用提供了强大的支持,当需要将一个构件加入现存系统中时,只需将他注册到系统的事件中

  4. 为改进系统带来了方便,当一个构件代替另一个构件时,不会影响到其他构件的接口。

隐式调用系统的主要缺点:

  1. 构件放弃了对系统计算的控制。一个构件触发一个事件时,不能确定其他构件是否会响应它。而且即使它知道事件注册了哪些构件的过程,它也不能保证这些过程被调用的顺序。
  2. 数据交换的问题。有时数据可能被一个事件传递,但另一些情况下,基于事件的系统必须依靠一个共享的仓库进行交互。在这些情况下,全局性能和资源管理便成了问题。
  3. 既然过程的语义必须依赖于被触发事件的上下文约束,关于正确性的推理存在问题。

    9.3.5 虚拟机风格

    基本思想是人为构建一个运行环境。在这个环境之上,可以解析与运行一些自定义的一些语言,这样来增加架构的灵活性。

    1. 解释器

    一个解释器通常包括完成解释工作的解释引擎,一个包含将被解释的代码的存储区,一个记录解释引擎当前工作状态的数据结构,以及一个记录源代码被解释执行进度的数据结构。
    具有解释器风格的软件中包含有一个虚拟机,可以仿真硬件的执行过程和一些关键应用。解释器通常被用来建立一个虚拟机以弥合程序语义与硬件语义之间的差异,其缺点是执行效率过低。典型的例子是专家系统。

    2. 基于规则的系统

    基于规则的系统包括规则集、规则解释器、规则/数据选择器及工作内容。

    9.3.6 仓库风格

    在仓库风格中,有两种不同的构件:中央数据结构说明当前状态,独立构件在中央数据存储上执行,仓库与外构件间的相互作用在系统中会有大的变化。
    仓库风格包含的自风格有:数据库系统;超文本系统;黑板系统
    数据库系统构件主要有两大类:一个是中央共享数据源,保存当前系统的数据状态;另一个是多个独立处理元素,处理元素对数据元素进行操作。而超文本系统的典型代表,就是早期的静态网页。三种架构子风格中,最复杂的是黑板系统。
    黑板系统是在抽象与总结语言理解系统HEARSAY-11的基础上产生的,适合于复杂的非结构化的问题,能在求解过程中综合运用不同知识源,使得问题的表达、组织和求解都变得比较容易。黑板系统是一种问题求解模型,是组织推理步骤、控制状态数据和问题求解之领域知识的概念框架,它将问题的解,空间组织成一个或多个应用相关的分级结构,分级结构的每一层信息由一个唯一的词汇来描述,它代表了问题的部分解。领域相关的知识被分成不同知识表达方法、推理框架和控制机制的组合来实现,影响黑板系统设计的最大因素是应用问题本身的特性,但是支撑应用程序的黑板体系结构有许多相似的特征和构件。
    对于特定应用问题,黑板系统可通过选取各种黑板、知识源和控制模块中的构件来设计,也可以利用关预先定制的黑板体系结构的编程环境。黑板系统的传统应用是信号处理领域,如语言和模式识别。另一个应用是松耦合代理数据共享存取。
    黑板系统主要由三个部分组成:

  4. 知识源:知识源中包含独立的、与应用程序相关的知识,知识源之间不直接进行通信,它们之间的交互只通过黑板来完成。

  5. 黑板(共享数据):黑板数据是按照与应用程序相关的层次来组织的解决问题的数据,知识源通过不断地改变黑板上的数据来解决问题。
  6. 控制:控制完全由黑板的状态驱动,黑板状态的改变决定使用的特定知识。

    9.4 层次系统架构风格

    9.4.1 二层及三层C/S架构风格

    C/S架构是基于资源不对等,且为实现共享而提出的。将应用一分为二,服务器(后台)负责数据管理,客户机(前台)完成与用户的交互任务。
    C/S软件架构具有强大的数据操作和事务处理能力,模型西乡简单,易于人们理解和接收,但是随着企业规模的日益扩大,软件的复杂程度不断提高,传统的C/S架构存在以下几个局限:
  • 二层C/S架构为单一服务器且以局域网为中心,所以很难扩展至大型企业广域网或Internet
  • 软、硬件的组合及集成能力有限
  • 服务器的负荷太重,难以管理大量的客户机,系统的性能容易变坏
  • 数据安全性能不好,因为客户端程序可以直接访问数据库服务器,那么,在客户端计算机上的其他程序也可想办法访问数据库服务器,从而使数据库的安全性受到威胁。

三层C/S架构将应用功能分为表示层、功能层和数据层三个部分。
表示层是应用的用户接口部分,它但负责用户与应用间的对话功能,它用于检查用户从键盘等输入的数据,并显示应用输出的接口。在变更用户接口时,只需要改写控制和数据检查程序,而不影响其他两层,检查的内容也只限于数据的形式和取值的范围,不包括有关业务本身的处理逻辑。
功能层相当于应用的本体,他是将具体的业务处理逻辑编入程序中。而处理所需的数据则要从表示层或数据层取得。表示层和功能层之间的数据交往要尽可能简洁。
数据层就是数据库管理系统,负责管理对数据库数据的读写。数据库管理系统必须能迅速执行大量数据的更新和检索。因此,一般从功能层传送到数据层的要求大都使用SQL语言。

9.4.2 B/S架构风格

浏览器/服务器风格就是上述三层应用结构的一种实现方式,其具体结构为:浏览器/web服务器/数据库服务器。
B/S架构主要是利用不断成熟的WWW浏览器技术,结合浏览器的多种脚本语言,用通用浏览器就实现了原来需要复杂的专用软件才能实现的强大工鞥呢,并节约了开发成本。
与C/S架构相比,B/S架构也有不足之处,例如:

  1. B/S架构缺乏对动态页面的支持能力,没有集成有效的数据库处理能力。
  2. 采用B/S架构的应用系统,在数据查询等响应速度上,要远远的低于C/S架构。
  3. B/S架构的数据提交一般是以页面为单位,数据的动态交互性不强,不利于在线事务处理应用

    9.4.3 MVC架构风格

    全名是模型-视图-控制器。
    MVC各个部分的分工与协作是这样的。

  4. Model是对应用状态和业务能力的封装,我们可以将它理解为同时包含数据和行为的领域模型。Model在接收Controller的请求并完成相应的业务处理在状态改变的时候向View发出相应的通知。

  5. View实现可视化界面的呈现并捕捉最终用户的交互操作。
  6. View捕捉到用户交互操作后悔直接转发给Controller,后者完成相应的UI逻辑,如果需要涉及业务功能的调用,Controller会直接调用Model。在完成UI处理后,Controller会根据需要控制原View或创建新的View对用户交互操作予以相应。

    9.4.4 MVP架构风格

    Model-View-Presenter。Model提供数据,View负责显示,Controller/Presenter负责逻辑的处理。MVC中允许View与Model直接交流,这在MVP模式中是不允许的。它们之间的通信是通过Presenter,所有的交互都发生在Presenter内部。
    MVP的优点包括:

  7. 模型与视图完全分离,我们可以修改视图而不影响模型。

  8. 可以更高效的使用模型,因为所有的交互都发生在一个地方——Presenter内部。
  9. 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。
  10. 如果我们将逻辑放在Presenter的中,那么我们就可以脱离用户接口来测试这些逻辑。

MVP的缺点包括:
视图和Presenter的交互会过于频繁。如果Presenter过多的渲染了视图,往往会使得他与特定视图的联系过于紧密,一旦视图需要变更,那么Presenter也需要变更。

9.5 面向服务的架构

  1. W3C的定义:SOA是一种应用程序架构,在这种架构中,所有功能都定义为独立的服务,这些服务带有定义明确的可调用接口,能够以定义好的顺序调用这些服务来形成业务流程。
  2. SA的定义:服务是精确定义、封装完善、独立于其他服务所处环境和状态的函数。SOA本质上是服务的集合,服务之间彼此通信,这种通信可能是简单的数据传递。也可能是两个或更多的服务协调进行某些活动。服务之间需要某些方法进行连接。
  3. Garner的定义:SOA是一种C/S架构的软件设计方法,应用由服务和服务使用者组成,SOA与大多数通用的C/S架构模型不同之处,在于它着重强调软件的松散耦合,并使用独立的软件接口。

    9.5.1 SOA概述

    虽然基于SOA的系统并不排除使用OOD来够简单个服务,但是其整体设计却是面向服务的。由于SOA考虑到了系统内的对象,所以虽然SOA是基于对象的,但是作为一个整体,它却不是面向对象的。
    SOA建立在XML等新技术的基础上,通过使用基于XML的语言来描述接口,服务已经转到更动态且更灵活的接口系统中。
    在SOA系统中,所有的功能都定义成了独立的服务。服务之间通过交互和协调完成业务的整体逻辑。所有的服务都通过服务总线或流程管理器来连接。各服务在交互的过程中无需考虑双方的内部实现细节,以及部署在什么平台。

    1. 服务的基本结构

    服务模型的表示层从逻辑层分离出来,中间增加了服务对外的接口层。通过服务接口的标准化描述,使得服务可以提供给在任何异构平台或任何用户接口使用。

    2. SOA设计原则

  4. 明确定义的接口。服务定义必须长时间稳定,一旦公布,不能随意更改;服务的定义应尽可能明确,减少请求者的不适当使用;不要让请求者看到服务内部的私有数据。

  5. 自包含和模块化。服务封装了那些在业务上稳定的、重复出现的活动和构件,实现服务的功能实体是完全独立自主的,独立进行部署、版本控制、自我管理和恢复。
  6. 粗粒度。服务数量不应该太多,依靠消息交互而不是远程过程调用。通常消息量较大,但是服务之间的交互频率较低。
  7. 松耦合。服务请求者可见的是服务的接口,其位置、实现技术、当前状态和私有数据等,对服务请求者而言是不可见的。
  8. 互操作性、兼容和策略声明。

    3. 服务构件和传统构件

    服务构件架构SCA是基于SOA的思想描述服务之间组合和写作的规范,它描述用于使用SOA构建应用程序和系统的模型。可以简化可用SOA进行应用程序的开发和实现工作。提供了构件粗粒度构件的机制,这些粗粒度构件由细粒度构件组装而成。SCA将传统中间件编程从业务逻辑中分离出来,从而使程序员避免受其复杂性的困扰。允许开发人员集中精力编写业务逻辑,而不必将大量的时间花费在更为底层的技术实现上。
    SCA服务构件与传统构件的主要区别在于:服务构件旺旺是粗粒度的,而传统构件以细粒度居多;服务构件的接口是标准的,主要是服务描述语言接口,而传统构件常以具体API形式出现;服务构件的实现与语言是无关的,而传统构件常绑定某种特定的语言;服务构件可以通过构件容器提供QoS的服务,而传统构件完全由程序代码控制。

    9.5.2 SOA的关键技术

    1. UDDI

    统一描述、发现和集成。提供一种服务发布、查找和定位的方法,是服务的信息注册规范,以便被需要该服务的用户发现和使用它。UDDI规范描述了服务的概念,同时也定义了一种编程接口。通过UDDI提供的标准接口,企业可以发布自己的服务供其他其他企业查询和调用,也可以查询特定服务的描述信息,并动态绑定到该服务上。
    UDDI技术规范中,主要包含下面三个部分的内容:

  9. 数据模型。是一个用于描述业务组织和服务的XML Schema

  10. API。十一组用于查找或发布UDDI数据的方法。基于SOAP
  11. 注册服务。是SOA中的一种基本设施,对应着服务注册中心的角色。

    2. WSDL

    Web语言描述对象是对服务进行描述的语言。有一套基于XML的语法定义。描述的重点是服务,包含服务实现定义和服务接口定义。
    服务接口定义就是一种抽象的、可重用的定义,行业标准组织可以使用这种抽象的定义来规定一些标准的服务类型,服务实现者可以根据这些标准定义实现具体的服务。
    服务实现定义描述了给定服务提供者如何实现特定的服务接口。服务实现定义中包含服务和端口描述。一个服务往往会包含多个服务访问入口而每个访问入口都会使用一个端口元素来描述,端口描述的是一个服务入口的部署细节。

    3. SOAP

    简单对象访问协议。定义了服务请求者和服务提供者之间的消息传输规范。使用XML来格式化消息,用HTTP来承载消息。通过SOAP,应用程序可以在网络中进行数据交换和远程过程调用RPC。SOAP主要包括以下四个部分:

  12. 封装。

  13. 编码规则,定义了一种序列化的机制,用于交换系统所定义的数据类型的实例。
  14. RPC表示。定义了一个用来表示远程过程迪奥哟经和应答的协议。
  15. 绑定。定义了一个使用底层传输协议来完成在结点之间进行交换SOAP封装的约定。

SOAP消息基本上是要从发送端到接收端的单向传输,但它们常常结合起来执行类似于请求/应答的模式。所有的SOAP消息都使用XML进行编码。SOAP消息包括以下三个部分:

  1. 封装(信封)。元素名是Envelope,在表示消息的XML文档中,封装是顶层元素,在SOAP中必须出现。
  2. SOAP头。元素名是Header,提供了向SOAP消息中添加关于这个SOAP消息的某些要素的机制。SOAP定义了少量的属性来表明这项要素是否可选以及由谁来处理。可能出现,也可能不出现,一旦出现,必须是第一个直接子元素。
  3. SOAP体。元素名是Body,是包含消息的最终接收者想要的信息的容器。必须出现,且必须是直接子元素。如果有头元素,则必须直接跟在头元素的后面,如果没有,则必须是第一个子元素。

    4. REST

    表述性状态转移。是一种只使用HTTP和XML进行基于web通信的技术,可以降低开发的复杂性,提高系统的可伸缩性。REST从根本上只支持几个操作(POST、GET、PUT和DELETE)。REST提出了如下一些设计概念和准则:

  4. 网络上的所有事物都被抽象为资源。

  5. 每个资源对应一个唯一的资源标识。
  6. 通过通用的连接件接口对资源进行操作。
  7. 对资源的各种操作不会改变资源标识。
  8. 所有的操作都是无状态的。

    9.5.3 SOA的实现方法

    1. Web Service

    一共有三种工作角色,其中服务提供者和服务请求者是必需的,服务注册中心是一个可选的角色。

  9. 服务提供者。是服务的所有者,负责定义并实现服务,使用WSDL对服务进行详细、准确、规范性描述,并将该描述发布到服务注册中心,工服务请求者查找并绑定使用。

  10. 服务请求者。是服务的使用者。从架构的角度看,服务请求者是查找、绑定并调用服务,或与服务进行交互的应用程序。服务请求者角色可以由浏览器来担当,由人或程序来控制。
  11. 服务注册中心。是连接服务提供者和服务请求者的纽带,服务提供者在此发布它们的服务描述,而服务请求者可以在服务注册中心查找它们需要的服务。如果是使用静态绑定的服务,服务提供者可以把描述直接发给服务请求者。

Web service模型中的操作如下,这些操作可以单次或反复出现;

  1. 发布。服务提供者发布服务描述
  2. 查找。服务请求者直接检索服务描述或在服务注册中心查询所要求的服务类型。对服务请求者来说,可能会在生命中秋的两个不同阶段中涉及查找操作,首先是在设计阶段,为了程序开发而查找服务的接口描述;其次是在运行阶段,为了调用而查找服务的位置描述。
  3. 绑定。服务请求者使用服务描述中的绑定细节来定位、联系并调用服务,从而在运行时与服务进行交互。绑定可以分为动态绑定和静态绑定。在动态绑定中,服务请求者通过服务注册中心查找服务描述,并动态的与服务交互;在静态绑定中,服务请求者已经与服务提供者达成默契,通过本地文件或其他方式直接与服务进行绑定。

在采用Web service作为SOA的实现技术时,应用程序大致可以分为六个层次,如下:

  1. 底层传输层。主要负责消息的传输机制,HTTP、JMS和SMTP都可以作为服务的消息传输协议,其中HTTP使用最广。
  2. 服务通信协议层。主要功能是描述并定义服务之间进行消息传递所需的技术标准,常用的标准是SOAP和REST协议。
  3. 服务描述层。主要以一种统一的方式描述服务的接口与消息交换方式,相关的标准是WSDL。
  4. 服务层。主要功能试讲遗留系统进行包装,并通过发布的WSDL接口描述被定位和调用。
  5. 业务流程层。主要功能是支持服务发现,服务调用和点到点的服务调用,并将业务流程从服务的底层调用抽象出来。
  6. 服务注册层。主要功能是使服务提供者能够通过WSDL发布服务定义,并支持服务请求者查找所需的服务信息,相关的标准是UDDI。

    2. 服务注册表

    虽然也有运行时的功能能,但主要在SOA设计时使用。它提供了一个策略执行点PEP,在这个点上,服务可以在SOA中注册,从而可以被发现和使用。从理论上来说,任何帮助服务注册、发现和查找服务合约、元数据和策略的信息库、数据库、目录或其他节点都可以被认为是一个注册表。

  7. 服务注册。指服务提供者向服务注册表发布服务的功能(服务合约),包括服务身份、位置、方法、绑定、配置、方案和策略等描述性属性。

  8. 服务位置。指服务使用者,帮助它们查找已注册的服务,寻找符合自身要求的服务。
  9. 服务绑定。服务使用者利用查找到的服务合约来开发代码,开发的代码将与注册的服务进行绑定,调用注册的服务,以及与他们实现互动。

    3. 企业服务总线

    ESB,是一种为连接服务提供的标准化的通信基础结构,基于开放的标准,为应用提供一个可靠的、可度量和高度安全的环境,并可帮助企业对业务流程进行设计和模拟,对每个业务流程进行控制和跟踪、分析、并改进流程和性能。
    ESB是由中间件技术实现并支持SOA的一组基础架构,是传统中间件技术与XML、Web Service等技术结合的产物,是在整个企业集成环境下的面向服务的企业应用集成机制。具体来说,ESB具有以下功能

  10. 支持异构环境中的服务、消息和基于事件的交互,并且具有适当的服务级别和可管理性。

  11. 通过使用ESB,可以在几乎不更改代码的情况下,以一种无缝的非侵入方式使现有系统具有全新的服务接口,并能够在部署环境中支持任何标准。
  12. 充当缓冲器的ESB(负责在诸多服务之间转换业务逻辑和数据格式)与服务逻辑相分离,从而使不同的系统可以同时使用同一个服务,不用在系统或数据发生变化时,改动服务代码。
  13. 在更高的层次,ESB还提供诸如服务代理和协议转换等功能,允许在多种形式下通过向HTTP、SOAP和JMS总线的多种传输方式,主要是以网络服务的形式,为发表、注册、发现和使用企业服务或界面提供基础设施。
  14. 提供可配置的消息转换翻译机制和基于消息内容的消息路由服务,传输消息到不同的目的地。
  15. 提供安全和拥有者机制,以保证消息和服务使用的认证、授权和完整性。

    9.5.4 微服务

    微服务架构是一种架构模式,提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通。每个服务都围绕着具体业务进行构件,并且能够被独立的部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构件。
    核心特点是:小,且专注做一点事情、轻量级的通信机制、松耦合、独立部署。

    1. 微服务的优势

    1. 技术异构性

    在微服务架构中,每个服务都是一个相对独立的个体,每个服务都可以选择适合于自身的技术去实现。

    2. 弹性

    主要讲的是系统中的一部分出现故障,会引起多大问题。微服务架构中,每个服务都可以内置可用性的解决方案与功能降级方案。

    3. 扩展

    可以针对单个服务进行扩展

    4. 简化部署

    微服务架构中,每个服务的部署都是独立的。可以更快的对特定部分的代码进行部署。

    5. 与组织结构相匹配

    微服务架构可以将架构与组织结构相匹配,避免出现过大的代码库,从而获得理想的团队大小及生产力。

    6. 可组合型

    在微服务架构中,系统会开放很多接口供外部使用。当情况发生改变时,可以使用不同的方式构件应用。

    7. 对可替代性的优化

    在微服务架构中,我们可以在需要时轻易的重写服务,或删除不再使用的服务。

    2. 微服务面临的挑战

  16. 分布式系统的复杂度

  17. 运维成本
  18. 部署自动化
  19. DevOps与组织结构
  20. 服务间依赖测试
  21. 服务间依赖管理

    3. 微服务与SOA

    | 微服务 | SOA | | —- | —- | | 能拆分的就拆分 | 是整体的,服务能放到一起的都放到一起 | | 纵向业务划分 | 是水平分多层 | | 由单一组织负责 | 按层级划分不同部门的组织负责 | | 细粒度 | 粗粒度 | | 两句话可以解释明白 | 几百字只相当于SOA的目录 | | 独立的子公司 | 类似大公司里面划分了一些业务单元 | | 组件小 | 存在较复杂的组件 | | 业务逻辑存于每一个服务中 | 业务逻辑横跨多个业务领域 | | 采用轻量级的通信方式,如HTTP | 企业级服务充当了ESB充当了服务之间通信的角色 |
微服务架构实现 SOA实现
团队级,自底向上开展实施 企业级,自顶向下开展实施
一个系统被拆分成多个服务,粒度细 服务由多个子系统组成,粒度大
无集中式总线,松散的服务架构 企业服务总线,集中式的服务架构
集成方式简单(HTTP/REST/JSON) 集成方式复杂(ESB/WS/SOAP)
服务能独立部署 单块架构系统,相互依赖、部署复杂

9.6 架构设计

1. 演变交付生命周期

在生命周期模型中,架构设计就是从初步的需求分析开始逐步进行循环迭代。即:一方面在了解系统需求前,不能开始设计架构;另一方面,刚开始设计架构时并不需要等到全部需求都收集到。

2. 属性驱动设计法

是一种定义软件架构的方法,该方法将分解过程建立在软件必须满足的质量属性智商。
ADD的步骤如下。

  1. 选择要分解的模块
  2. 根据如下步骤对模块进行求精:
  • 从具体的质量场景和功能需求集合中选择架构驱动因素。并不是同等看待所有需求,而是在满足了最重要的需求的条件下,才满足不太重要的需求,即针对架构需求有优先级。
  • 选择满足架构驱动因素的架构模式,根据前面的战术创建(或选择)模式。其目标是建立一个由模块类型组成的总体架构模式。
  • 实例化模块并根据用例分配功能,使用多个视图进行表示。
  • 定义子模块的接口。
  • 验证用例和质量场景,并对其进行求精,使他们成为子模式的限制。
  1. 对需要进一步分解的每个模块重复上述步骤。

    3. 按架构组织开发团队

    4. 开发骨架系统

    5. 利用商用软件进行开发

    9.7 软件架构文档化

    1. 架构文档的使用者

    是架构的项目关系人。编写技术文档的最基本的原则之一是要从读者的角度来编写。

    2. 合理的编档规则

  2. 从读者的角度编写文档

  3. 避免出现不要的重复
  4. 避免歧义
  5. 使用标准结构
  6. 记录基本原理
  7. 使文档保持更新,但更新频率不要过高
  8. 针对目标的适宜性对文档进行评审

    3. 视图编档

    文档组织结构包含七个部分:

  9. 视图概述:对系统进行概述性的描述,包含视图的主要元素和元素箭的关系(但并不包含所有元素和元素箭的过膝)。主要表示可用多个形式:图形、表格、文本。通常用图形形式,使用UML语言来描述。

  10. 元素目录:对主要表示中所描述的元素及其关系进行详细描述,包括:元素及其属性、关系及其属性、元素接口、元素行为。这部分是文档的主要组成部分,其中要注意:
  • 对元素及其协同工作的行为进行编档,如用UML中的顺序图和状态图描述行为;
  • 对接口进行编档
  1. 上下文图:用图形展示系统如何与其环境相关。
  2. 可变性指南:描述架构的可变化点。文档中应包含这些变化点,如各系统要作出选择的选项、作出选择的时间。
  3. 架构背景:为架构的合理性提供足够的、令人信服的论据。包括:基本原理、分析结果及设计中所反映的假定。
  4. 术语表:对文档中每个术语进行简要说明。
  5. 其他信息:描述不属于架构方面的必要信息。

    4.跨视图文档

    包括如下内容:

  6. 文档由哪些内容以及如何组织:视图目录;视图模板

  7. 架构概述:描述系统的目的、是土建的关联、元素表及索引、项目词汇
  8. 基本原理:跨视图基本原理解释了整体架构实际上是其需求的一个解决方案。及解释了作出决策的原因、方案的限制、改变决策时的影响及意义。

    5. 使用UML

    6. 软件架构重构

    软件架构重构就是研究及反向解析软件架构的工作。
    软件架构重构由以下活动组成,这些活动以迭代方式进行。

  9. 信息提取:提取目标的依赖关系;提取静态信息;提取动态信息

  10. 数据库构造:将提取的信息转化为标准的形式,并置于数据库中。
  11. 视图融合:将数据库中的信息组合在一起,生成该架构的一个内聚的视图。
  12. 重构:根据数据抽象和各种表示以生成架构表示,主要由两个活动组成:最后生成需要的架构文档。

    9.8 软件架构评估

    是在对架构分析、评估的基础航,对架构策略的选取进行决策。他可以灵活的运用于软件架构进行评审等工作中。

    9.8.1 软件架构评估的方法

  13. 基于调查问卷或检查表的方式:关键是要设计好问卷或检查表,它充分利用系统相关人员的经验和知识,获得对架构的评估。缺点是在很大程度上依赖于评估人员的主观推断。

  14. 基于场景的方式:应用在架构权衡分析法和软件架构分析方法中。通过分析软件建构对场景的支持程度,从而判断该架构对这一场景所代表的质量需求的满足程度。
  15. 基于度量的方式:建立在软件架构度量的基础上的,涉及三个基本活动,首先需要建立质量属性和度量之间的映射原则,即确定怎样从度量结果中退出系统具有什么样的质量属性;然后从软件架构文档中获取度量信息;最后根据映射原则分析推导出系统的质量属性。它能提供更为客观和量化的质量评估,对评估人员及其使用的技术有较高的要求。

    9.8.2 架构的权衡分析法

    从技术的角度对软件架构进行评估,旨在通过分析来遇见软件的质量,通过分析来创建、选择、评估与比较不同的架构。ATAM方法不但能够揭示架构如何满足特定的质量需求,而且还提供了分析这些质量需求之间交互作用的方法。使用ATAM方法评价一个软件架构的目的是理解架构设计满足系统质量需求的结果。ATAM产生如下结果。

  16. 一个简洁的架构描述

  17. 表述清楚的业务目标。
  18. 用场经济和捕捉质量需求。
  19. 架构决策到质量需求的映射。
  20. 所确定的敏感点和权衡点集合:这个集合是一些对一个或多个质量属性具有显著影响的架构。
  21. 有风险角色和无风险决策
  22. 风险主题的集合。
  23. 产生一些附属结果
  24. 还产生一些无形结果。

ATAM的九个步骤如下:

  1. ATAM方法的表述
  2. 商业动机的表述
  3. 架构的表述
  4. 对架构方法进行分类
  5. 生成质量属性效用树。
  6. 分析架构方法
  7. 集体讨论并确定场景的优先级
  8. 分析架构方法
  9. 结果的表述

    9.8.3 成本效益分析法

    CBAM是在ATAM上构建,用来对于架构设计决策的成本和收益进行建模,是优化此类决策的一种手段。CBAM协助项目管理人根据其投资回报ROI选择架构策略。CBAM在ATAM结束时开始,它实际上使用了ATAM评估的结果。步骤如下:

  10. 整理场景

  11. 对场景进行求精
  12. 确定场景的优先级
  13. 分配效用。对场景的响应级别(最坏情况、当前情况、期望情况和最好情况)确定效用表。
  14. 架构策略设计那些质量属性及相应级别,形成相关的策略——场景——响应级别的对应关系。
  15. 使用内插法确定“期望的”质量属性响应级别的效用。即根据第4步的效用表以及第5步的对应关系,确定架构策略及对应场景的效用表。
  16. 计算各架构策略的总收益。
  17. 根据受成本限制影响的投资报酬率ROI选择架构策略。

    9.9 构件及其复用。

    定义1:构件是指软件系统中可以明确辨识的构成成分。而可复用构件是指具有相对独立的功能和可复用价值的构件。
    定义2:构件是一个组成单元,具有约定规范的接口及明确的依赖环境。
    定义3:构件是软件系统中具有相对独立功能、可以明确辨识、接口由七月制定、和语境由明显依赖关系、可独立部署的可组装软件实体。

    9.9.1 商用构件标准规范

    1. CORBA

    公共对象请求代理架构。主要分为3个层次:对象请求代理、公共对象服务和公共设施。最底层的对象请求代理ORB,规定了分布对象的定义(接口)和语言映射,实现对象间的通信和互操作,是分布对象系统中的“软总线”;在ORB之上定义了很多公共服务,可以提供诸如并发服务、名字服务、事务(交易)服务、安全服务等各种各样的服务;最上层的公共设施则定义了构件框架,提供可直接为业务对象使用的服务,规定业务对象有效写作所需的协定规则。
    CORBA CCM(CORBA构件模型)是OMG组织制定的一个用于开发和配置分布式应用的服务器端构件模型规范,它主要包含以下三项内容。

  18. 抽象构件模型:泳用以描述服务器端构建结构及构件间互操作的结构。

  19. 构件容器结构:用以提供通用的构件运行和管理环境,并支持对安全、事务、持久状态等系统服务的集成。
  20. 构件的配置和打包规范:CCM使用打包技术来管理构件的二进制、多语言版本的可执行代码和配置信息,并制定了构建包的具体内容和文档内容标准

    2. J2EE

    在分布式互操作协议上,J2EE同时支持远程方法调用RMI和互联网内部对象请求代理协议IIOP。
    EJB中的Bean可以分为会话Bean和实体Bean,前者维护会话,后者处理事务,通常由Servlet负责与客户端通信,访问EJB,并把结果通过JSP产生页面返回客户端。

    3. DNA 2000

    Microsoft的COM+组件

    9.9.2 应用系统簇与构件系统

    一般情况下,构件系统只在开发单位内部使用,而应用系统提供给外部客户。与应用系统相比,构件系统具有通用性、可复用性。一个构件系统是能提供一系列可复用特性的系统产品。

    9.9.3 基于复用开发的组织结构

    与传统的开发组织结构不同,它需要有一部分用于开发可复用资产的资源,这部分资源应同具体引用系统的开发资源分开,以确保不被占用。

    9.10 产品线与系统演化

    实质上是用架构技术构建产品线,并在此基础上借用复用技术持续演化,不断的推出新产品,满足市场追求产品升级换代的需求。

    9.10.1 复用与产品线

    软件产品线是指一组软件密集型系统,它们共享一个公共的、可管理的特性及,满足某个特定市场或任务的具体需要,是以规定的方式用公共的核心资产集成开发出来的。即围绕核心资产库进行管理、复用、集成新的系统。
    可复用的资产非常广,包括以下几点:
  • 需求
  • 架构设计
  • 元素:捕获并复用设计中的可取之处,避免设计失败的地方
  • 建模与分析
  • 测试
  • 项目规划
  • 过程、方法和工具
  • 人员
  • 样本系统
  • 缺陷消除

    9.10.2 基于产品线的架构

    软件产品线架构是针对一系列产品而设计的通用框架,并在此基础上,进一步向系列产品公用的模块实现实现,供直接重用;将架构用框架的形式予以实现,供定制使用。这就是通常所说的“平台”。
    产品线架构较之单个产品架构,有如下三点特别之处:
  1. 产品线架构必须考虑一系列明确许可的变化
  2. 产品架构一定要文档化
  3. 产品架构必须提供“产品常见指南”(开发指南),描述架构的实例化过程。

通常应在识别变化时,应考虑三个方面:

  1. 确定变化点:确定变化是一项需要持续进行的活动,可以在开发过程中的任何时间确定变化。
  2. 支持变化点:对变化的支持有多种形式,例如:
  • 包含或生路额元素,如条件编译
  • 包含不同数量的复制元素:如通过添加更多的服务器产生高容量的变体。
  • 具有相同的接口但具有不同的行为或质量特性的元素版本的选择:如静态库和动态链接库的使用。
  • 在面向对象的系统中,通过特化或繁华特定的类实现变化。
  • 通过参数配置来实现变化
    3、 对产品架构的适应性进行评估
  • 评审方法
  • 评估的内容
  • 评估的时间

    9.10.3 产品线的开发模型

    开发(确定)产品线的方法有两种模型:
  1. “前瞻性”产品线:利用在应用领域的经验,对市场和技术发展趋势的了解及企业判断力等进行产品线设计,它反映了企业的战略决策。通常是自上而下的采用产品线方法。
  2. “反应性”模型:企业根据以前的产品构建产品家族,并随着新产品的开发,扩展架构和设计方案,它的核心资产库是根据“已有证明”为共有、而非“预先计划”为共有的元素构建的。通常是自下而上的采用产品线方法。

    9.10.4 特定领域软件架构

    架构的本质在于其抽象性。包括两个方面的抽象:业务抽象和技术抽象。其中业务抽象面向特定的技术领域
    特定领域软件架构DSSA可以看做开发产品线的一个方法(或理论),它的目标就是在支持在一个特定领域中有多个应用的生成。
    DSSA的必备特征有:

  3. 一个严格定义的问题域或解决域

  4. 具有普遍性,使其可以用于领域中某个特定应用的开发
  5. 对整个领域的合适程度的抽象
  6. 具备该领域固定的、典型的在开发过程中的可复用元素。

从功能覆盖的范围角度理解DSSA中领域的含义有两种方法L

  1. 垂直域。定义了一个特定的系统族,到处在该领域中可作为系统的克星解决方案的一个通用软件架构。
  2. 水平域。定义了在多个系统和多个系统族中功能区域的共有部分,在子系统级上涵盖多个系统(族)的特定部分功能。

DSSA的活动阶段如下:

  1. 领域分析:主要目标是获得领域模型。即通过分析领域中系统的需求(领域需求),确定哪些需求是被领域中的系统广泛共享的,从而建立领域模型。
  2. 领域涉及:这个阶段的目标是获得DSSA,他是一个能够适应领域多个系统的需求的一个高层次的设计。
  3. 领域实现:主要目标是依据领域模型和DSSA开发和组织可复用信息。这些复用信息可以使从现有系统中提取得到的,也可能通过新的额开发得到。这个阶段可以看做复用基础设施的实现阶段。

领域模型的主要作用如下:

  1. 领域模型为需求定义了领域知识和领域词汇,这较之单一的项目需求更有较好的大局观。
  2. 软件界面的设计往往和领域模型关系密切
  3. 领域模型的合理性将严重影响软件系统的可扩展性
  4. 在分层架构的指导下,领域模型精化后即成为业务层的骨架。
  5. 领域模型也是其数据模型的基础
  6. 领域模型是团队交流的基础,因为它规定了重要的领域词汇表,并且这些词汇的定义是严格的。

    9.10.5 架构及系统演化

    架构(系统)演化包含七个步骤:

  7. 需求变动归类

  8. 制定架构演化计划
  9. 修改、增加或删除构件
  10. 更新构件的相互作用
  11. 构件组装与测试
  12. 技术评审
  13. 产生演化后的架构

    9.11 软件架构视图

    9.11.1 软件视图的分类

    结构是元素本身的集合,而视图则是捕获和表达结构(文档描述)
    软件视图通常分为三种类型:

  14. 模块视图类型:为系统的主要模块实现单元编档

  15. 构件和连接件视图类型:为系统的构件和连接件执行单元编档
  16. 分配视图类型:为软件的开发和执行环境之间的关系编档

组别|架构风格|说明|应用于
——|————
模块视图类型|分解|大模块分解为小模块,小到容易理解|资源分配、项目结构化和规划;信息隐蔽、封装;配置控制
模块视图类型|使用|一个单元的正确性依赖于另一个单元的正确性(如版本)|设计子集;设计扩展(增量开发)
模块视图类型|分层|上层使用下层的服务;实现隐藏细节的抽象|增量式开发;基于“虚拟机”上的可移植性
模块视图类型|类或泛化|“继承自”或“是一个实例”;共享访问方法|面向对象的设计(使用公共模板)。
构件-连接器视图类型|客户机-服务器|构件是客户机和服务器,连接件是协议及共享消息|分布式操作;关注点分离(支持可修改性);负载均衡
构件-连接器视图类型|进程或通信进程|通过通信、同步或排除操作形成进程或线程之间的关联|调度分析;性能分析
构件-连接器视图类型|并发|在相同的“逻辑线程”上运行|确定资源争用;分析线程
构件-连接器视图类型|共享数据|运行时产生数据,使用数据(共享数据存储库)|性能;数据完整性;可修改性
分配视图类型|部署|软件功能分配给软件(进程)、硬件(处理器)和通信路径|性能、可用性、安全性说明。尤其是在分布式或并行系统中
分配视图类型|实现|模块映射到开发活动中|配置控制、集成、测试活动
分配视图类型|工作分配|将责任分配到适当的开发小组,特别是公共部分不是每个人去实现|项目管理、管理通用性,最好的专业技术安排。

9.11.2 模块视图类型及其风格

模块将遵循某种方式将软件系统分解成可管理的功能单元。
架构模块视图是通过文档来枚举系统的主要实现单元或模块,及这些单元之间的关系。任务完整的架构文档必须包含有模块视图,它为源代码提供蓝图。
模块视图的四种风格如下:

  1. 分解风格能展示向模块分配责任的方式
  2. 使用风格能展示模块相互依赖的方式
  3. 分层风格能将系统分割成一组虚拟机,通过“允许使用”关系相互关联,分层风格能帮助实现可移植性和可修改性。
  4. 泛化风格能展示一个模块如何成为另一个模块的泛化或特化,从而使模块之间产生关联。它广泛应用于面向对象的系统,能展示继承性,并能用来使用模块之间的共性。

    9.11.3 C&C视图类型及其风格

    能定义由具有某种运行时存在的元素模型,这些元素包括进程、对象、客机、服务器及数据存储器等。此外,它还包括作为元素的交互路径,如通信链路和协议、信息流及共享存储器访问。几种风格如下:

  5. 管道和过滤器风格中的交互模式表现出数据流连续变换的特征。数据抵达过滤器并经过转换后由管理传送给下一个过滤器

  6. 共享数据风格通过保留持久数据来支配交互模式,持久数据由多个数据存储器和至少一个储存库保留。
  7. 发布-订阅风格用于向一组未知接受者发送时间和消息。可在不修改生产者的情况下添加洗呢接受者(订阅者)。在发布-订阅风格中,构件通过事件发布进行交互,构件可以订阅一组事件
  8. 客户机-服务器风格能展示构件通过请求其他构件的服务进行交互的过程,将功能划分成客户机和服务器后即可基于运行时准则把他们单独分配给各个级。
  9. 对等连接系统能通过构件之间的直接交换支持服务交换。他是一种调用/返回风格。
  10. 通信-进程风格的特征表现在通过各种连接件机制并发执行构件的交互,如通过同步、消息传递、数据交换、启动和停止等进行交互。

    9.11.4 分配视图类型及其分割

    硬件、文件系统和团队结构都会与软件架构进行交互,将软件架构映射到其环境的一般形式称为“分配视图类型”。
    分配视图类型的常见风格如下:

  11. 布置风格体现为C&C风格(如进程-进程风格)的元素被分配到执行平台。

  12. 实现风格能将模块视图类型中的模块映射到开发基础结构,实现一个模块总会产生许多独立文件,必须对这些文件进行组织,以免失去对系统的控制及系统的完整性。通常利用配置管理技术进行文件管理。
  13. 软件项目的时间和预算估计取决于工作分解结构WBS,而工作分解结构则取决于软件架构。工作任务风格将软件架构映射到有人组成的团队之中,实现这一项目管理的目的。

    9.11.5 各视图类型间的映射关系

  14. 模块视图类型中的视图通常会映射到构件和连接件视图类型中的视图。模块实现单元将映射到运行时构件

  15. 系统中的构件和连接件视图和模块视图之间的关系可能会非常复杂。同样的代码模块可由C&C视图的许多元素执行。反之,C&C视图的单一构件可执行有许多模块定义的代码。同样,C&C构件可能会拥有许多与环境进行交互的点,每个交互点由统一模块接口定义。
  16. 分配视图类型是为有效的实现软件架构的辅助性视图,它将其他视图类型中的软件元素映射到软件环境中,即反应其他视图与软件环境之间的关系。

16人点赞

日记本

赞赏支持
更多精彩内容,就在简书APP
“如果我的文章对你有帮助,可以打赏一下,请我吃块糖吆”

作者:步积
链接:https://www.jianshu.com/p/01de54e6dfbf
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。