架构设计则为知足架构需求的质量属性寻找适当的战术。对如何实现特定的质量属性感兴趣。质量需求指定了软件的响应,以实现业务目标。咱们感兴趣的是设计使用设计模式、架构模式或架构策略建立设计的“战术”。算法
是什么使一个设计具备了可移植性,一个设计具备了高性能,而另外一个设计具有了可集成性?实现这些质量属性依赖于基本的设计策略。咱们将对这些称之为“战术”的设计决策进行分析。战术就是影响质量属性响应控制的设计决策。战术集合称为“架构策略”。架构模式以某种方式将战术打包在一块儿。设计模式
系统设计是由决策集合组成。对设计师来讲,每一个战术都是一个设计选择。例如,其中一个战术引入了冗余,以提升系统的可用性。这是提升可用性的一个选择可是不是惟一选择。服务器
咱们将每一个系统质量属性的战术组织为层次形式,可是每一个层次只是为了说明一些战术,并且任何战术列表都确定是不完成的。架构
1. 可用性战术框架
恢复和修复是可用性的重要方面,为了阻止错误发展成故障,至少可以把错误限制在必定的范围内,从而使修复成为可能。维持可用性的全部方法包括某种类型的冗余,用来检测故障的某种类型的健康监视,以及当检测到故障时某种类型的恢复。有些状况下,监视或恢复是自动进行的,有时须要手动。性能
咱们事项考虑错误检测,而后分析错误恢复,最后讨论错误预防。测试
1> 错误检测线程
用于识别错误的3个战术是命令/响应、心跳和异常架构设计
⑴命令/响应。一个组件发出一个命令,并但愿在预约义的时间内收到一个来自审查组件的响应。能够把该战术用在共同负责某项任务的一组组件内。客户机也可使用这种战术,以确保服务器对象和到服务器的通讯路径在指望的性能边界内操做。能够用一种层级形式组织“命令/响应”错误探测器,其中最底层的探测器对与其共享一个处理器的软件进程发出命令,较高层的错误探测器对较低层的探测器发出命令。与全部进程发出命令的远程错误探测器相比,这种战术所使用的通讯带宽更少。设计
⑵心跳。一个组件按期发出一个心跳消息,另外一个组件接收听该信息。若是心跳失败,则假定最初的组件失败,并通知错误纠正组件。心跳还能够传递数据。例如,自动柜员机按期向服务器发送一次交易日志。该消息不只起到心跳的做用,并且传送了要处理的数据。
⑶异常。识别错误的一个方法就是遇到了异常。
命令/响应和心跳战术在不一样的进程中操做,异常战术在一个进程中操做。异常处理程序一般将错误在语义上转换为能够被处理的形式。
2> 错误恢复
错误恢复由准备恢复和修复系统两部分组成。
⑴表决。运行在冗余处理器上的每一个进程都具备相同的输入,它们计算发送给表决者的一个简单的输出值。若是表决者检测到单处理器的异常行为,那么就停止这一行为。表决算法能够是“多数规则”或“首选组件“或其余算法。该方法用于纠正算法的错误操做或者处理器的故障,一般用在控制系统。每一个冗余组件的软件能够由不一样的小组开发,而且在不一样平台上执行。稍微好一点状况是在不一样平台上开发一个软件组件,可是这样的开发和维护费用很是昂贵。
⑵主动冗余(热重启)。全部的冗余组件都以并行的方式对事件作出响应。所以他们都处在相同的状态。仅使用一个组件的响应,丢弃其余组件的响应。错误发生时,使用该战术的系统停机时间一般是几毫秒,由于备份是最新的,因此恢复所须要的时间就是切换时间。
⑶被动冗余(暖重启/双冗余/三冗余)
一个组件(主要的)对事件作出响应,并通知其余组件(备用的)必须进行状态更新。当错误发生时,在继续提供服务前,系统必须首先确保备用状态是最新的。该方法也用在控制系统中,一般状况是在输入信息经过通讯通道或传感器到来时,若是出现故障必须从主组件切换到备用组件时使用。
⑷备件
备用件是计算平台配置用于更换各类不一样的故障组件。出现故障时,必须将其从新启动为适当的软件配置,并对其状态进行初始化。按期设置持久设备的系统状态的检查点,并记录持久设备的全部状态变化可以使备件设置为适当的状态。这一般用做备用客户机工做站,出现故障时,用户能够离开。该战术的停机时间一般是几分钟。
⑸Shadow操做。之前出现故障的组件能够在短期内以“shadow模式”运行,以确保在恢复该组件前,模仿工做组件行为。
⑹状态再同步。主动和被动冗余战术要求恢复的组件在从新提供服务前更新其状态。更新的方法取决于能够承受的停机时间、更新的规模以及更新所要求的消息的数量。
⑺检查点/回滚。检查点就是记录所建立的一致状态,或者是按期进行,或者是对具体事件作出响应。有时系统会以一种不一样寻常的方式出现故障,可检测到其状态不一致。在这种状况下,应该使用上一个一致状态检查点和拍了快照后所发生的事务日志来恢复系统。
3> 错误预防
⑴从服务中删除。该战术从操做中删除了系统的一个组件,以执行某些活动来防止预期发生的故障。一个示例就是从新启动组件,以防止内存泄露致使故障的发生。若是从服务中删除是自动的,则能够设计架构策略来支持它。若是是人工进行的,则必须对系统进行设计以对其提供支持。
⑵事务。事务就是绑定几个有序的步骤,以可以马上撤销整个绑定。若是进程中的一个步骤失败的话,可使用事务来防止任何数据受到影响,还可使用事务来防止访问相同数据的几个同时线程之间发生冲突。
⑶进程监视器。一旦检测到进程中存在着错误,监视进程就能够删除非执行进行,并为该进程建立一个新的实例,就像在备件战术中同样,初始化为某个适当的状态。
总结了上面讨论的战术。
2. 可修改性战术
可修改战术的目标是控制实现、测试和部署变动的时间和成本。把可修改性战术根据其目标进行分组。一组可修改性战术目标是减小由某个变动直接影响的数量。这组称为“局部化修改”。另外一组可修改战术的目标是限制对局部化的模块的修改。这组称为“防止连锁反应”。两组之间的差异是有直接受变动影响的模块(那些调整其责任来完成变动的模块)间接受变动影响的模块(那些责任保持不变,但必须改变其实现来适应直接受影响的模块)。第三组战术的目标是控制部署时间和成本。咱们把这组战术叫作“延迟绑定时间”。
1> 局部化修改。
目标是在设计期间为模块分配责任,以把预期的变动限制在必定范围内。其战术有:维持语义的一致性、预期指望的变动、泛化该模块、限制可能的选择。
⑴维持语义的一致性。语义的一致性是在模块中责任之间的关系。目标是确保全部这些责任都可以协同工做,不须要过多地依赖其余模块。该目标是经过选择具备语义一致性的责任来实现的。耦合和内聚指标是度量语义一致性的尝试,但它们遗漏了变动的上下文。相反根据一组预期的变动来度量语义一致性。其中一个子战术就是“抽象通用服务”。经过专门的模块提供通用服务一般被视为支持重用。可是抽象通用服务也支持可修改性。若是已经抽象出了通用服务,那么对这些通用服务的修改只须要进行一次,而不须要在使用这些服务的每一个模块中都进行修改。此外,对使用这些服务的模块的修改不会影响到其余用户。不只支持局部化修改,并且还可以防止连锁反应。抽象通用服务的示例就是应用框架的使用和其余中间件软件的使用。
⑵预期指望的变动。考虑所预想的变动的集合提供了一个评估特定的责任分配的方法。基本的问题是“对于每次变动,所建议的分解是否限定了为完成变动所须要修改的模块的集合?”一个相关的问题是“根本不一样的变动会影响相同模块吗?”这与语义一致性有什么不一样呢?根据语义一致性分配责任,假按期望的变动在语义上是一致的。预测指望变动的战术不关心模块责任的一致性,它所关心的是使变动的影响最小。在实际中很难单独使用该战术,由于不可能预期全部变动。基于此缘由,咱们一般结合语义一致性来使用该战术。
⑶泛化该模块。使一个模块更通用可以使它根据输入计算更普遍的功能。能够该输入看做是为该模块定义了一种语言,这可能会如同使常数成为输入参数同样简单;也可能如同把该模块实现为解释程序,并使输入参数成为解释程序的语言中的程序同样复杂。模块越通用,越有可能经过调整语言而非修改模块来进行请求变动。
⑷限制可能的选择。修改(尤为是在产品线中的修改)的范围可能很是大,所以可能会影响不少模块。限制可能的选择将会下降这些修改所形成的影响。例如,产品线的某个变化点可能容许处理器的变化。将处理器变动限制为相同家族的成员就限制了可能的选择。
2> 防止连锁反应。
修改所产生的一个连锁反应就是须要改变该修改并无直接影响到的模块。例如,改变了模块A以完成某个特定的修改,那么必须改变模块B,这仅仅是由于改变了A,在某种意义上来讲,是由于它依赖于模块A。