第5章实现质量属性

 
第4 章刻画了许多系统质量属性。该刻画是通过场景的集合进行的。理解为什么质量属性能够使您获取质量需求,但无助于理解如何实现它们。本萆就给您提供这种帮助。对 于在第4辟详细描述的6个成量属性,我们提供了如何实现每个质最属性的构架方面的指 导。这里阐述的战术并不涉及所有可能的质量属性,但我们在第8草将看到实现集成性的 战术。
 
我们现在对设计师如何实现特定的质量属性感兴趣。质量黹求指定了软件的响应,以 实现业务目标。我们感兴趣的是设计师使用设计模式、构架模式或构架策略创建设计的 “战术”。例如,业务目标可能是创建一个产品线。实现该目标的-个手段就是在功能的 特定类中允许可变性。
 
在确定实现期望的变化的一组模式前,设计师应该考虑可以应用什么样的可修改性战术组合,因为所选择的战术将会指导构架决策。构架模式或策略实现了战术的集合。质量 属性需求(已在第4章讨论)和构架决策之间的关系就是本草的主题、
5.1战术介绍
是什么使一个设计具有了可移植性,一个设计具有了高性能,而另一个设计具备了可 集成性?实现这些质量属性依赖于基本的设计决策。我们将对这些称之为“战术”的设计 决策进行分析。战术就是影响质量属性响应控制的设计决策。我们把战术的集合称为“构 架策略",第12窣将对此进行阐述。构架模式以某种方式将战术打包在了一起,5.8节将 对此方式进行讨论。
 
系统设计由决策集合组成。在这些决策中,一些可以帮助控制质量属性响应,一些可 以确保系统功能的实现。在本节中,我们将讨论被称为战术的质量属性决策。图5.1给出 了这一关系。战术就是设计师多年以来一直在使用的那些方法,我们将分别对其进行描述。 在这里我们并不是发明新战术.只是捕获设计师在实践中所使用的战术。
 
对设计师来说,每个战术都是一个设计选择。例如.其中一个战术引入了冗余,以提 高系统的可用性。这是设计师必须提高可用性的一个选择,但并不是惟的选择。通常通 过冗余实现高可用性意味着需要同步(以确保在最初的拷贝出现故障时可以使用冗余的拷 贝)。我们可以看到该示例的两个最近的分支。
 
(1)战术可以求精其他战术。      我们把冗余确定为一个战术.,同样.可以把它求精为 数据冗余(在数据库系统中)或计算冗余(在嵌入式控制系统中)。这两种类型也都是战 术。设计人员可以进一歩求精以使每种类型的冗余都更加具体。对于所讨论的每-个质量 厲性,我们都将战术组织为层级形式。
 
(2)模式可以把战术打包。支持可用性的模式很可能会使用冗余战术和同步战术。 它很可能还会使用这些战术的更具体的形式。在本节结束时,我们将给出个根据其战术 所描述的模式的示例。
 
我们将每个系统质量厲性的战术组织为层次形式,但是,每个层次只是为了说明一些 战术,而且任何战术列表都肯定是不究整的.理解这两点很重耍。第4章已经对可用性、 可修改性、性能、安全性、可测试性和易用性进行了详细说明.对于其中的每一个属性, 我们都讨论了实现该属性的战术方法。对于每一个厲性,我们都提供了战术的组织并进行 了简要讨论。组织的目的是为设计师提供-个搜索适当战术的途径。
 
5.2可用性战术
回想-下在第4章对可用性的描述。当系统不再提供与其规范一致的服务时,故障就 发生了;该系统的用户可以观察到这个故障。错误(或错误的组合)可能会导致故陣的发生。 我们还记得恢复或修复是可用性的重要方面。本节讨论的战术将会阻止错误发展成故障.至少能够把错误的影响限制在一定范围内,从而使修复成为可能。图5.2对此进行了说明。
我们讨论的许多战术在标准的执行环境中都有效,如操作系统、应丨[|服务器和数据库 管理系统。现解所使用的战术非常重要.因为只有这样才能在设计和评估中考虑使用某个 特足战术的效果。维持可用性的所有方法包括某种类型的冗余,用来检测故障的某种类型的健康监视,以及当检测到故障时某种类型的恢复。有些情况下,监视或恢复是自动进行 的,还有些悄况下是手动进行的。
 
我们首先考虑错误检测,然后分析错误恢复,最后简要讨论一下错误预防。
 
5.2.1错误检测
 
广泛用于识别错误的3个战术是命令/响应(ping/echo)、心跳和异常。
 
•    命令/响应 一个组件发出-个命令,并希望在预定义的时间内收到一个来自审 杳组件的响应。可以把该战术用在共同负责某项任务的一组组件内。客户机也可 以使用这种战术,以确保服务器对象和到服务器的通信路径在期塑的性能边界内 操作。可以用一种层级形式组织“命令/响应”错误探测器。其中最低层的探测器 对与其共亨-个处理器的软件进程发出命令,较高层的错误探测器对较低层的探 测器发出命令。与对所有进程发出命令的远程错误探测器相比,这种战术所使用 的通信带宽更少。
 
•    心跳(dead man计时器)。在这种情况下,一个组件定期发出一个心跳消息,另
 
一个组件收听该信息。如果心跳失败,则假定最初的组件失败,并通知错误纠正组件„心跳还可以传递数据。例如,自动柜员机可以定期向服务器发送上一次交 易的日志。该消息不仅起到了心跳的作用,而且传送了要处理的数据。
 
•    异常.识別错误的一个方法就是遇到了异常.当识别出了第4章所讨论的错误类 中的某-个时,就会出现异常。该异常处理程序通常在引入该异常的相同进程中 执行。
 
命令/回响和心跳战术在不同的进程中操作,异常战术在一个进程屮操作。异常处理程 序通常将错误在语义上转换为可以被处理的形式。
 
5.2.2错误恢复
 
错误恢复由准备恢复和修复系统两部分组成。下面是-些准备和修复战术。
 
•    表决。运行在冗余处理器上的每个进程都具有相等的输入,它们计算发送给表决 者的一个简单的输出值。如果表决者检测到单处理器的异常行为,那么,就中止 这一行为。表决算法可以是“多数规则”或“首选组件”或其他算法。该方法用于纠正算法的错误操作或处理器的故障,通常用在控制系统中。如果所有的处理 器都利用相同的算法。则冗余检测到的只是处理器错误而非箅法错误。因此,如 果出现故陣的后果非常严傲,如可能会丧失生命,则冗余组件可能是多种多样的。
 
多样性的一种极端情况是每个冗余组件的软件都由不同的小组开发,并在不 同的平台上执行.稍好一点的情况是在不同的平台上开发一个软件组件。多样性 的开发和维护都是很昂贵的,仅用在异常环境中,如飞行器表ifti的控制。它通常 用于这样的控制系统:发送到表决者的输出简舉直接、很容易分类为相等的或不 正常的:计算是循环的:所有的冗余组件都从传感器接收相等的输入。故障发生 时,多样性没有停机时间,因为表决者仍在继续操作。该方法的变体包括Simplex 方法,它使用“首选”组件的结果.除非这些结果偏离了所遵循的“受信”组件 的结果。冗余组件之间的同步是自动进行的.因为它们都假定是在以并行的方式 在相同的输入集上进行计箅。
 
•    主动冗余(热重启)所有的冗余组件都以并行的方式对事件做出响应。因此. 它们都处在相同的状态。仅使用一个组件的响应(通常是做出响应的第一个组 件〉,丢弃其余组件的响应。错误发生时,使用该战术的系统的停机时间通常是 几毫秒,因为备份是最新的,所以恢复所黹要的时间就是切换时间。主动冗余通 常用在客户机/服务器配置中(如数据库管理系统),在这种配置中,即使发生错 误,也必须快速做出响应,在一个可用性非常高的分布式系统中,冗余可能就在 通信路径上。例如.我们可能希望使用一个具有许多并行路径的局域网,并将毎 个冗余组件放在一个单独的路径中。在这种情况下,一个桥或路径故陣不会使所 有的系统组件都不可用。
 
通过确保将传递给任何冗余组件的每条消息都发送给所有的冗余组件来执 行同步。如果通信有可能会丢失(因为有噪声或过载的通信线路),可以使用可靠的传输协议来恢复。可靠的传输协议要求所有的接收者确认收据和一些完整性标识(如校验和)。如果发送者不能验证所有的接收者都收到了该消息,它将把 该消息重新发送给没有确认收据的组件。继续重新发送未收到的消息(可能通过不同的通信路径),直到发送者将接收者标记为已超出服务范围。
 
•    被动冗余(暖重启/双冗余/三冗余)。一个组件(主耍的)对事件做出响应,并 通知其他组件(备用的)必须进行的状态更新。当错误发生时.在继续提供服务 前,系统必须首先确保备用状态是最新的。该方法也用在控制系统中,通常的情 况是在输入信息通过通信通道或传感器到来时,如果出现故陣必须从主组件切换 到备用组件时使用。第6章描述了空中交通管制的一个示例。对使用该方法的一个系统进行了阐述。在空中交通管制系统中,备用组件决定什么时候接替主组件 的工作,但在其他系统中,可以在其他组件中做出这一决定。该战术依赖于能够可靠地接管工作的备用组件。周期性地进行切换可以提高系统的可用性,例如一天一次或一周一次。一些数据库系统要求存储器中每加入一个新的数扼项时都要 进行切换。新的数据项存储在Shadow页中,旧的页就成了用于恢复的备份。在 这种悄况'下,停机通常只有几秒的时间。同步是主组件的责任,它可以对备用组件使用原子广播,以保证同步。
 
•    备件。备用件是计箅平台配置用于更换各种不同的故障组件。出现故障时,必须将其重新启动为适当的软件配置,并对其状态进行初始化。定期设置持久设备的 系统状态的检杏点,并记录持久设备的所有状态变化能够使备件设置为适当的状 态。这通常用作备用客户机工作站.出现故障时,用户可以离开。该战术的停机 时间通常是几分钟。
 
有一些依赖于组件重新引入的修复战术。当冗余组件失畋时,可以在纠正该 组件后将其再次引入。此类战术包括shadow操作、状态的再同步以及回滚 (rollback)。
 
•    shadow操作,,以前出现故障的组件可以在短时间内以“shadow模式”运行.以 确保在恢复组件之前,模仿工作组件的行为。
 
•    状态再同步。主动和被动冗余战术要求所恢复的组件在重新提供服务前更新其状态。更新方法取决于可以承受的停机时间、更新的规模以及更新所要求的消息的数据。如果可能的话,最好用一条消息包含该状态。增量式状态更新和两个增量之间的服务周期会导致复杂的软件。
 
•    检查点/回滚。检査点就是记录所创建的一致状态,或者是定期进行.或者是对 具体事件做出响应。有时系统会以一种不同寻常的方式出现故陣,可检测到其状态不一致。在这种情况下,应该使用上一个一致状态检查点和拍了快照后所发生 的事务的日志来恢复系统。
 
5.2.3错误预防
 
下面是一些错误预防战术。
 
•    从服务中删除..该战术从操作中删除了系统的一个组件,以执行某些活动來防止 预期发生的故陣。一个示例就是重新启动组件,以防止内存泄漏导致故障的发生。 如果从服务中删除是自动的,则可以设计构架策略来支持它。如果是人工进行的, 则必须对系统进行设计以对其提供支持。(比如当内存占到多少%时,自动重启系统,以防止OOM)
 
•    事务。事务就是绑定几个有序的步骤,以能够立刻撤销整个绑定。如果进程中的一个步骤失败的话,可以使用事务来防止任何数据受到影响,还可以使用事务来 防止访问相同数据的几个同时线程之间发生冲突。
 
•    进程监视器。一旦检测到进程中存在错误,监视进程就可以删除非执行进程,并为该进程创建一个新的实例,就像在备件战术中一样,初始化为某个适当的状态。
 
图5.3总结了上面讨论的战术。
5.3可修改性战术
第4草曾讲过控制可修改性的战术,其目标是控制实现、测试和部署变更的时间和成 本。图5.4给出了这一关系。
我们把可修改性战术根据其目标进行分组。一组可修改性战术的目标是减少由某个变更直接影响的模块的数量。我们把这组可修改性战术称为“局部化修改”。另一组可修改 性战术的目标是限制对局部化的模块的修改。我们使用这组战术来“防止连锁反应”。这 两组战术之间的差别是有直接受变更影响的模块(那些调整其责任来完成变更的模块)和 间接受变更影响的模块(那些其责任保持不变.但必须改变其实现来适应直接受彫响的模 块).第三组战术的目标是控制部署时间和成本。我们把这组战术叫做“延迟绑定时间”。
 
5J.1局部化修改
尽管在-组变更所影响的模块的数量和实现这些变更的成本之间不一定有一个准确 的关系,但把修改限制在一小组模块内般会降低成本。这组战术的目标是在设计期间为 模块分配贲任,以把预期的变更限制在一定的范围内。我们标识了如下几个战术:
 
•维持语义的一致性。语义的一致性指的是模块中责任之间的关系。目标是确保所 有这些责任都能够协同工作,不需要过多地依赖其他模块。该目标是通过选择具 有语义一致性的责任来实现的。耦合和内聚指标是度量语义一致性的尝试,但它 们遗漏了变更的上下文。相反,应该根据一组预期的变更来度量语义一致性。其 中的一个子战术就是“抽象通用服务”。通过专门的模块提供通用服务通常被视 作支持重用。这是正确的,但抽象通用服务也支持可修改性。如果己经抽象出了 通用服务,那么,对这些通用服务的修改只需要进行一次,而不霈要在使用这些 服务的每个模块中都进行修改。此外,对使用这些服务的模块的修改不会影响其 他的用户.因此,该战术不仅支持局部化修改,而且还能够防止连锁反应。抽象 通用服务的示例就是应用框架的使用和其他中间件软件的使用。
 
•预期期望的变更。考虑所预想的变更的集合提供了个评估特定的责任分配的方 法。基本的问题是“对于每次变更,所建议的分解是否限定了为完成变更所需要 修改的模块的集合? ” 一个相关的问题是“根本不同的变更会影响相同的模块 吗?"这与语义一致性有什么不同?根据语义-致性分配责任.假定期望的变更 在语义上楚一致的。预测期望变更的战术并不关心模块贵任的一致性,它所关心 的是使变更的影响说小。在实际中很难黾独使用该战术,因为不可能预期所有变更。娃f此原因,我们通常结合语义一致性来使用该战术
 
•    泛化该模块.使一个模块更通用能够使它根据输入计算更广泛的功能。可以把该 输入看作是为该模块定义了 一种语言,这可能会如同使常数成为输入参数一样简 单:也可能会如同把该模块实现为解释程序,并使输入参数成为解释程序的语言 中的程序一样复杂.模块越通用.越有可能通过调整语言而非修改模块来进行请 求的变更。
 
•    限制可能的选择,,修改(尤其是在产品线中的修改,参见第14章)的范围可能非常大,因此可能会影响很多模块。限制可能的选择将会降低这些修改所造成的 影响。例如,产品线中的某个变化点可能允许处理器的变化。将处理器变更限制 为相同家族的成员就限制了可能的选择。
 
5.3.2防止连锁反应
 
修改所产生的一个连锁反应就是需要改变该修改并没有直接影响到的模块。例如,如 果改变了模块A以完成某个特定的修改,那么必须改变模块B,这仅仅是因为改变了模块 A。必须修改模块B,在某种意义上来说,是因为它依赖于模块A。
 
我们通过讨论_ 一个模块可能对另一个模块的各种依赖性,来展幵对连锁反应的讨论。 我们确定了8种类型的依赖性:
 
(1)语法
 
•    数据。要使B正确编译(或执行),由A产生并由B使用的数据的类型(或 格式)必须与B所假定的数据的类型(或格式)•致。     
 
•    服务。要使b正确编译和执行,由a提供并由B调用的服务的签名必须 与B的假定一致。
 
(2)语义
 
•    数椐.,要使B正确执行.由A产生并由B使用的数据的语义必须4 B的假定一致。
 
•    服务。耍使B正确执行,由A产生并由B使用的服务的语义必须与B的假 定-致。
 
(3)顺序
 
•    数椐.要使B正确执行,它必须以一个固定的顺序接收由A产生的数据。 例如,数据包的头部必须按接收的顺序放在其包体的前面(与在数据中具有内建序列号的协议相反)。
 
•控制。要使B正确执行.A必须在一定的时间限制内执行。例如.在B执行 前,A执行的时间不能超过5毫秒。
 
(4)    A的一个接口的身份。A可以有多个接口。耍使B正确编译和执行,该接口的身份(名称或句柄)必须与B的假定一致。
 
(5)    A的位置(运行时)。要使B正确执行,A的运行时位置必须与B的假定一致. 例如,B可能会假定A位于相同处理器的不同进程上„
 
(6)    A提供的服务/数据的质量。要使B正确执行,涉及A所提供的数据或服务的质 量的一些属性必须与B的假定一致。例如,某个特定的传感器所提供的数据必须有一定的 准确性.以使B的算法能够正常运行。
 
(7)    A的存在。要使B iE常执行,A必须存在。例如,如泶B请求对象A提供服务. 而A不存在并且不能动态创建,那么,B就不能汜常执行
 
(8) A的资源行为。要使B正常执行,A的资源行为必须与B的假定一致-这可以是A的资源使用(A使用与B相同的内存)或资源拥有(B保留了 A认为属于它的资源)。 借助对依赖性类型的这一理解,现在,我们可以讨论设计师可用于防止某些类型的连 镇反应的战术。
 
请注窓,在我们所讨论的战术中,没有任何一个战术-定能够防止语义变更的连锁反 应。我们酋先讨论与特定模块的接口相关的那些战术——信息隐藏和维持现有的接口一 然后讨论•个违反了依赖链的战术——仲裁者的使用。
 
•信息隐藏。信息隐藏就是把某个实体(一个系统或系统的某个分解)的责任分解 为更小的部分,并选择使哪些信息成为公有的.哪些信息成为私有的。可以通过 指定的接口获得公有责任。信息隐藏的目的是将变更隔离在一个模块内,防止变 更扩散到其他模块。这是防止变更扩散的最早的技术。它与“预期期望的变叟有 很大关系”,因为它使用那些变更作为分解的基础。
 
•维持现有的接口。如果B依赖于A的一个接口的名字和签名,则维持该接口其语法能够使B保持不变。当然,如对A有语义依赖性,那么该战术不 定会起作用.因为很难屏蔽对数据和服务的含义的改变。此外,也很难屏蔽对服 务质量、数据质量、资源使用和资源拥有的依赖性。还可以通过将接口与实现分 离来实现该接口的稳定性。这使得能够创建屏蔽变化的抽象接口。变化可以包含 在现有的责任中,或者可以通过用模块的一个实现代替另一个实现来包含变化。
 
实现该战术的模式包括:
 
•     添加接口.大多数编程语言都允许多个接口。可以通过新接口提供最新的可 见的服务或数据,从而使得现有的接口保持不变并提供相同的签名。
 
•    添加适配器。给A添加•个适配器,该适配器把A包装起来,并提供原始A的签名。
 
•    提供一个占位程序A。如果修改要求删除A,且B仅依赖于A的签名,那么为A提供一个占位程序能够使B保持不变。
 
•    限制通信路径。限制与一个给定的模块共享数据的模块。也就是说,减少使用由 该给定模块所产生的数据的模块的数量。以及产生由该模块所使用的数据的模块 的数量。这会减少连锁反应,因为数据产生/使用引入了导致连锁反应的依赖。第 8章(飞行模拟)讨论了使用该战术的模式。
                            
•    仲裁者的使用。如果B对A具有非语义的任何类型的依赖,那么,在A和B之 间插入一个仲裁苕是可能的.以管理与该依赖相关的活动。所有这些仲裁者都有 不同的名字,但我们将根据列举的依赖类型对每个仲裁者进行讨论。如前所述, 在最糟糕的情况下,仲裁者不能补偿语义变化。仲哉者是:
            
            •    数据(语法)。存储库充当数据的生产者和使用者之间的仲裁者。存储库可 以把A产生的语法转换为符合B的语法。一些发布/订阅模式(那些具有通 过中央组件的数据流的模式)也可以把该语法转换为符合B的语法。MVC 和PAC模式把•种形式的数据(输入或输出设备)转换为另•种形式的数据       
            (由MVC中的模型或PAC或PAC中的抽象所使用的形式)。
            
            •    服务(语法)。正面、桥、调停者、策略、代理和工厂模式都提供了把服务 的语法从一种形式转换为另一种形式的仲裁者。因此,可以使用它们防止A 的变化扩散到B。
            
            •    A的接口的身份。可以使用经纪人模式屏蔽-个接口的身份中的变化。如果 B依赖f于A的•个接口的身份并且该身份发生了变化,通过向经纪人添加该 身份,并使经纪人与A的新身份进行连接,B可以保持不变。
            
            •    A的位置(运行时)。名称服务器能够使A的位置发生变化,且不影响B。A 负责在名称服务器中注册其当前的位置,B从名称服务器中检索该位置。
            
            •    A的资源行为或由A控制的资源(运行时)。资源管理器是一个负责进行资源 分配的仲裁者。某些资源管理器(例如那些基于实时系统中速率单调性分析 的管理器)可以保证满足在某些限制条件中的所有请求。当然.A必须把对 该资源的控制转让给资源管理器。
            
            •    A的存在。工厂横式能够根据需要创建实例.因此B对A的存在的依赖性由 该工厂的操作来满足。
                
5.3.3推迟绑定时间
到目前为止已经讨论的两个战术分类经过了精心设计.以使实现修改所要求改变的模 块的数量最少。我们的可修改性场景包括通过减少需要修改的模块的数量不能满足的两个元素——部署时间以及允许非开发人员进行修改。推迟绑定时间支持这两个场景,但需要提供额外的基础结构来支持后期绑定。
 
可以在各个时间把决策绑定到执行系统中。我们讨论一下那些影响部署时间的决策。 系统的部署由某个过程来规定。当修改由开发人员进行时,通常会有一个测试和分布过程, 该过程确定进行改变和该改变对最终用户可用之间的时间延迟。在运行时绑定意味肴系统 已经为该绑定做好了准备,并且完成了所有的测试和分配步骤。推迟绑定时间还能够使最 终用户或系统管理员进行设置,或提供影响行为的输入。
 
许多战术的目的是在载入时或运行时产生影响,如下所示:
 
•运行时注册支持支持即插即用操作,但需要管理注册的额外开销.例如.发布/ 订阅注册可以在运行时或载入时实现。
 
•配置文件的目的是在启动时设置参数
 
•多态允许方法调用的后期绑定。
 
•组件更换允许载入时间绑定。
 
•遵守已定义的协议允许独立进程的运行时绑定,
 
图5.5对可修改性的战术进行了总结。
 
5.4性能战术
第4章己经讲过,性能战术的目标就是对在-定的时间限制内到达系统的事件生成• 个响应。到达系统的可以是单个事件,也可以是事件流的形式,它是请求执行计算的触发 器。它可以是消息的到达、定时器到时、系统环境中重要的状态变化的检测.等等。系统 对事件进行处理并生成-个响应。性能战术控制生成响应的吋间> 如阁5.6所示。等待时 间是事件到达和对该事件生成响应之间的时间。
 
事件到达后,系统或者对该事件进行处理,或者由于某些原因处理被肌塞。下面是产 生响应时间的两个接本因素:资源消耗和闭锁时间。
 
(1)资源消耗。资源包括CPU、数据存储、网络通信带宽和内存•但它也可以包括 由设计中的特定系统所定义的实体。例如,必须对缓冲器进行管理,并且对关键部分的访 问必须是按顒序进行的。事件可以是各种类型的(正如上面所列举的〉,每种类型的事件 都经过了 .个处理序列。例如,消息由-个组件生成,放在网络」并到达另一个组件。 然后将其放在缓冲器中:用某种形式进行转换(对象管理小组对该转换使用的术语是编组
 
(Marshalling));根据某个算法进行处理:针对输出进行转换;放在输出缓冲器中:发送 给另一个组件、另•个系统或用户》上述每•个阶段都会增加处理该事件的等待时间。
 
(2)闭锁时间。可能会由于资源争用、资源不可用或计算依赖于另个还不能得到 的汁算的结果而导致计算不能使用某个资源,从而阻止了计算的进行。
 
•资源争用。图5.6给出了到达系统的事件。这些事件可能是单个流,也可能 是多个流。争用同一个资源的多个流或相同流中争用同•个资源的不同事件 都会增加等待时间。•般而言,对一个资源的争用越多,就越_有可能引入等 待时间•然而,这取决于如何仲裁争用以及仲裁机制如何处理单个请求。
 
•资源的可用性:即使没有争用,如果资源不可用,计饵也无法进行下去。资 源离线、组件故障或其他原因都会导致资源不可用•在任何情况下,设计师 都必须确定资源不可用可能会导致急剧增加等待时间的位置。
 
•对其他计算的依赖性。计算可能必须等待,因为它必须与另•个计算的结果 同步,或者是因为它在等待它所启动的一个计箅的结果例如,它可能会从两个不同的源读取信息’如果这两个源是按顺序读取的话,等待时间将会比 并行读取商。
 
介纽了上述知识后,我们开始讨论3个战术分类:资源需求、资源筲理和资源仲裁。 
 
5.4.1资源需求
 
事件流是资源霈求的源。需求的两个特性是:资源流中的事件之间的时间(在事件流 中多长时间进行-次请求):每个请求所消耗的资源是多少。
 
减少等待时间的.个战术就是减少处理一个事件流所需耍的资源。方法如下:
 
•提高计算效率,,处理事件或消息中的一个步骤就是应用某个箅法。改进在关键的 地方所使用的算法将减少等待时间。有时可以用一种资源换取另-种资源。例如, 可以把仲裁者数据保存在存储库中.也可以重新生成,这取决于时间和空间资源 的可用性„该战术通常用在处理器上,但用在其他资源上也足冇效的,如磁盘。
 
•减少计算开销    如果没有资源请求,就可以减少处理需求。第17章将给出-个 使用Java类而非远程方法调用(Remote Method丨nvocation, RMI)的承例,因为前者减少了通信需求。仲裁者的使用(对可修改性也非常重要)增加了处理事件流所消粍的资源,因此删除仲裁者将会减少等待时间。这是个经典的可修改性 /性能权衡问题。
 
减少等待时间的另•个战术就是减少所处理事件的数量。可以用如下方式进行:
 
•管理事件率,如果可以降低监视环境变量处的取样频率,就可以减少需求„如果 系统进行了超量设计的话,这样做是可行的,其他时候使用不必耍的高采样率来建立多个流之间的和谐的周期。也就是说,某个流或事件流被过采样.以使它们 可以被同步化。
 
•控制采样频率,,如果没有对外部生成的事件的到达进行控制,则可以用-个较低 的频率对排队的请求进行采样,这可能会导致请求的丢失。
 
用于减少或管理滞求的其他战术包括控制资源的使用。
 
•限制执行时间。限制用多少执行时间对事件做出响应„有时这样做有意义,有时 没冇意义。对于迭代式、依赖于数据的算法,限制迭代的数诳就足限制执行时间 的一个方法。
 
•限制队列大小。这控制了排成队列的到达亊件的最人数滅.因此拧制了用来处理 到达亊件的资源。
 
 
5.4.2资源管理
尽管不能控制对资源的需求,但对这些资源的管理会影响响应时间。下面给出了-些 资源管理战术:
 
•    引入并发。如果可以并行处理请求,就可以减少闭锁时间。可以通过在不同的线 程上处理不同的事件流或创建额外的线程来处理不同的活动集宋引入并发。引入 了并发后,适当地把线程分配给资源(负载均衡)非常重要,以尽可能利用并发。
 
•    维持数据或计算的多个副本。客户机-服务器模式中的客户机是计算的副本。使 用副本的目的是减少在中央服务器上进行所有的计箅时出现的争用-高速缓存是 在不同速度的存储库或单独的存储库上复制数据的战术,目的是减少争用。因为 被萵速缓存的数据通常是现有数据的-个副本,因此使副本-致和同步就变成了 系统必须承担的责任。
 
•    增加可用资源。速度更快的处理器、额外的处现器、额外的内存以及速度更快的 网络都可能减少等待时间。在选择资源时,通常会考虑成本,但增加资源绝对也 足•个减少等待时间的战术。第12章将对这种成本/性能权衡进行分析。
 
5.4.3资源仲裁
 
当存在资源争用时,必须对资源进行调度。我们需要对处理器、缓冲器和网络进行调 度安排。设汁师的目标是理解侮个资源使用的特性,并选择与之一致的调度策略。
 
从概念上说.调度策略有两部分:优先级分配和分派。所有的调度策略都分配优先级. 在一些情况下,分配如同先进/先出一样简单-在其他情况下,可能与请求的时限时间或其 语义重要性有关。进行调度的相互竞争的标准包括最佳的资源使用、请求重要性、最小化 所使用的资源的数量。使等待时间最少、使吞吐量最大、防止资源缺乏以确保合理等等, 设计师需要知道这些可能会发生冲突的标准以及所选择的战术对满足这些标准的影响。
 
可以分派•个髙优先级的事件流,条件是分配给该事件流的资源是可用的„有时这取 决于对该资源的当前用户的先占。可能的先占选择如下:可以在任何时间发生:仅在指定 的先占点发生:执行进程不能被先占。一些常见的调度策略为:
 
(1)先进/先出。FIFO队列同等看待对资源的所有请求,并依次对其进行处理。在 FIFO队列中,-个请求可能会被另一个需要很长时间来生成响应的请求阻止。只耍所有 请求的优先级都是相同的,这就不是个问题:但如果-些请求的优先级高于其他请求的 优先级,就存在一个问题。
 
(2)固定忧先级调度。固定优先级调度为每个请求资源的源分配一个特定的优先级,
并按该优先级顺序分配资源。该策略能够确保为优先级较高的请求提供更好的服务,但是, 对一些优先级较低但重要的请求来说,可能要等很长的时间才能得到服务,因为它前面有 很多优先级较高的请求在等待提供服务。3个常见的优先级策略为:
 
•    语义重要性.,毎个流都根据生成它的任务的某个与领域特性被静态地分一个优先级。这种调度用在大型机系统中,其中领域特性是任务启动的时间。
 
•    时限时间单调。时限时间单调是•种静态优先级分配,它将较高的优先级分 配给具脊较短时限时间的流。在调度的不同优先级流具有实时时限时间时, 使用该调度策略。
 
•    速率单调。    速率单调是周期流的一种静态优先级分配。它将较高的优先级分 配给具有较短周期的流。该调度策略是时限吋间单调的•种特殊情况,但它 更为我们所熟知。操作系统对此提供支持的可能性较大。
 
(3)动态优先级调度:
 
•轮转。轮转是-种调度策略.它对请求进行排序,然后在允许的时候,把资 源分配给该排序中的下一个请求。轮转的-个特殊形式就是循环执行,在循 环执行中,资源分配是每隔一个固定的时间进行的。
 
•    时限时间最早优先。时限时间最早优先根据具有最早的时限时间的挂起请求 来分配优先级。
 
(4)静态调度。循坏执行调度是一种调度策略,在该策略中,离线确定先占点和资 源分配顺序。
 
本章末尾的“可进一步参阅的文献”部分列出了关于调度理论的书籍。
 
图5.7对性能战术进行了总结。
 
 
 
posted @ 2019-12-04 21:59  mongotea  阅读(460)  评论(0编辑  收藏  举报