Principles of Computer System Design 读书笔记 I

CHARPTER 1 Systems

OVERVIEW

系统设计者需要有一个全局的、整体的计算机系统观(包括软件方面和硬件方面的)。
许多有价值的计算机应用程序都具备:

  • 容错性
  • 并发一致性
  • 离散数据的关联性
  • 信息的多样性
  • 对错误和内部攻击的保护性
  • 与许多用户的交互性

计算机系统设计的问题同样可以参考许多其它领域的设计问题,因为他们都有一定的共性。
System design principles - 一种可以帮助系统设计者避免犯错的规则,指导或者经验,并不是不能违背的条例。

Avoid excessive generality
If it’s good for everything, it’s good for nothing.

注解:系统设计的精髓——Everything is Tradeoff。

1.1 SYSTEMS AND COMPLEXITY

1.1.1 Common Problems of Systems in Many Fields

各式各样的系统所面临的首要问题主要包括四类:

  • Emergent properties(隐性的特征)
  • Propagation of effects(效应的传播)
  • Incommensurate scaling(不相称的扩长[0]
  • Trade-offs(权衡、取舍)

1.1.1.1 Emergent Properties

Emergent properties - 那些平时系统中单个组件内并不明显,但当组件进行组合后却能突然显现的属性或特征。

1.1.1.2 Propagation of Effects

Propagation of Effects - 系统一端看似很小的改动或异常却造成了系统远端另一部分的破坏。
注解:类似蝴蝶效应 [1]

所以在绝大多数系统中一个重要的原则就是药尽量限制住系统错误带来的冲击。

1.1.1.3 Incommensurate Scaling

Incommensurate Scaling - 当系统在体积或速度上扩大时,并非系统的所有部分都会成比例的增长,最终系统会停止运作。
注解:就是事物中每个部分的增长或缩小的速率都是不一样的,在自然界和生活中很容易找到相关的例子。

1.1.1.4 Trade-offs

Trade-offs - 现实中有利的因素总是有限的,所以设计中的挑战就是首先最大化这些有利因素,避免浪费他们,最后把他们放在最能提升系统的地方。

Waterbed effect - 水床效应,即你在处理某些问题时按下去一个问题,另一个问题又会浮现出来。文中列举了芯片设计中最关键的“性能-功耗-面积”问题[2]

Binary classification - 在分类问题上,我们有时因为无法通过一个显现的属性或特征来区分出两个类别的事物,只能通过降低容错性来提升划分的准确性。
注解:机器学习中的分类问题也类似。

计算机系统设计还是一个很年轻的领域,并不像一些传统的领域如桥梁或建筑设计那样成熟,所以无法给出一些严格的规格一些或者精准的权衡条件来构造组合系统,只能通过一些特定(ad hoc)案列结合实际情况来分析。
注解:计算机系统很复杂,很多系统之间找不到一个通用的模型或设计理论,现实开发中的方法论也各不相同,比如大型的复杂项目会倾向于螺旋模型[3],而一些小型的互联网项目却选择更容易迭代的敏捷模型[4]

1.1.2 Systems, Components, Interfaces, and Environments

A system is a set of interconnected components that has an expected behavior observed at the interface with its enviornment.

一个系统是一些相互交互的组件的集合,这些组件通过特定的接口与和其环境进行交互,且他们间的交互能产生一些特定的可被观察到的行为。
注解:和系统有交互但并不属于系统本身的就是环境。

对同一套事物用不同的角度去观察可以得到完全不同的系统,这样他们所包含的组件、接口和环境也是不相同的。这时一个系统中的一个组件在某些情景下很可能是另外一个完整的系统。
注解:比如汽车中发动机只是汽车整系统的一个组件,但在另一些研究发动机系统的情景下它就是一个完整的发动机系统。

Subsystem - 子系统,当一个系统在特定情境下是另一个系统的组件。

computer system or information system - 一个能自动控制存储、处理和信息交互的系统,比如:

  • 一个台个人电脑
  • 汽车中的动力控制器
  • 电话系统
  • 互联网
  • 飞机票订购系统
  • 宇宙飞船着陆控制系统
  • 一个万维网网站

1.1.3 Complexity

复杂虽然就暗指“难以理解”,但并没有一种精确的方法来测量系统的复杂度,也没有一个准确的定义来描述复杂度,只能通过一些模糊的特征,比如:

  1. 包含大量的组件;
  2. 拥有大量的交互;
  3. 展现出许多的无规律性;
  4. 冗长的自我描述;
  5. 需要许多设计者、实现者或维护者来工作。

文中举了一个小镇图书馆和一个大学图书馆的例子来说明了上面五个特征。

1.2 SOURCES OF COMPLEXITY

复杂性的根源主要有两个:

  • 设计者要系统满足太多的需求;
  • 需要让系统维持在一个高效的使用效率。

1.2.1 Cascading and Interacting Requirements

Principle of escalating complexity
Adding a requirement increases complexity out of proportion.

图 1.1 展现了复杂度随着需求的增加而呈现出指数级增长的趋势。

图中最重要的一点是复杂度的边界是模糊的:当你往系统里添加各种功能和需求时,并没有一个明确的边界提示你应该停下来了。

Generality - 通用性,即指用一个单一的系统去满足各种不同的需求,也可以认为去“适应各种多变的环境”。

要求系统通用往往是造成复杂性的原因之一,设计者这时就需要去权衡和判断到底需要满足多少程度的通用性。

Avoid excessive generality
If it is good for everything, it is good for nothing.

不过有一些特例就是要巧妙的把子系统设计得更通用化来让异常降到最低。

复杂性的另一个原因就是之前提到的不相称的扩长。

最后,造成复杂性的主要原因就是需求的变化,比如要求系统中的组件进行升级等。系统设计者不可能预测到未来系统的各种变化,当一些未预测到的需求出现时,就给系统带来了额外的复杂度。还有一些复杂的系统在作出一些微小的改动时,比如修复一个bug,就会因为复杂度的陡然增长而引出一些新的bug。

1.2.2 Maintaining High Utilization

一个最最常见的带来复杂度的需求就是要求系统能够高性能或高效率。

The law of diminishing returns
The more one improves some measure of goodness, the more effort the next improvement will require.

一个意图高效率去利用资源而出现的最显而易见的现象就是:越想把所有的资源用到极致,就越需要有更复杂的策略来利用、安置和调配这些资源。文中举了汽车能在红灯右转和机场调度飞机起降的例子来说明高效率就需要更复杂的调度系统。

图 1.2 高效率和复杂度之间的关系:


注解:图 1.1 和 图 2.2 是类似的。

1.3 Coping with Complexity

解决系统设计中问题复杂度的方法有:

  • modularity(模块化)
  • abstraction (抽象化)
  • layering (层次化)
  • hierarchy(结构化)

注解:和很多其它领域的设计方法是相通的,比如芯片设计和建筑设计等

1.3.1 Modularity

最简单且最重要的减少复杂度的方法就是“分治法(divide-and-conquer)”:把整个系统看做一堆交互的子系统即模块,来分析和设计。 文中举了如果把一个系统分成K个模块,debug的时间可以从 N^2 下降到 N^2 /K:

$ DebugTime \approx \dfrac{N^2}{K} $

模块化的好处还有可以轻松的替换系统中的模块,简化系统的升级过程。

The unyielding foundations rule
It is easier to change a module than to change the modularity.

注解:因为接口的更换会影响多个相关的模块,所以能否正确的模块化很重要。

1.3.2 Abstraction

Abstraction - 抽象化,在模块化过程中找到最佳的边界,是的模块之间的交互较少且相互的影响也少。更通俗的说,模块会被外界看做一个整体,之关心它的外部接口规格而忽略其内部结构。

functional modularity - 通过抽象方式来模块化。

注解:合理地抽象化模块堆限制系统错误很重要,因为有效地控制住了模块间的相互影响。

The robustness principle
Be tolerant of inputs and strict on outputs.

注解:模块接口设计要宽进严出,尽可能地大范围接受输入,同时能抑制住错误的输出。

The robustness principle在计算机系统设计中扮演者重要的角色,特别是在人机交互,网络协议和容错系统中,构成了数字逻辑世界的基础。与之相关且同等重要的设计原理是:

The safety margin principle
Keep track of the distance to the cliff, or you may fall over the edge.

注解:关注模块输入的边界值。

接受任何一个合理的输入,但关注那些已经快超出限制范围的值,在其失效前尝试修复它。

1.3.3 Layering

layering - 层次化,通过某种方式把模块组织在一起以减少模块间的相互连接。

注解:架构设计中经常看到的分成设计,比如持久层,业务层,展示层等等,还有计算机体系架构[5]、网络七层架构(OSI)[6]也类似。

层次中的模块除了和同层次中的模块交互外,还可以和紧邻自己的“上层”和“下层”中的模块交互。

1.3.4 Hierarchy

hierarchy - 结构化,从低向上地将模块逐渐组合成子系统,子系统在合成更大的子系统,最终形成一个完整的系统。

注解:本书中这里的hierarchy是通过bottom-up的方式来阐述的,现实中还有一种top-down的说法。

结构化的最大优点就是杜绝了模块随意与其它模块交互的情况,而是只关注其子系统中模块的的接口。

1.3.5 Putting it Back Together: Names Make Connections

在计算机系统中,一个模块通过赋予另一个模块职责(命名)而将模块之间联系起来。

Binding - 从多种方式中选择一个合适的实现方式来连接各种模块。

系统设计者有时为了保证系统的高灵活性,会等所有模块都齐备后才开始绑定模块。推迟绑定的一种方式就是指定其职责(命名)而并不去真正地实现它们。

indirection - 重定向,通过命名的方式来更换绑定(binding)。

Decouple modules with indirection
Indirection supports replaceability.

1.4 COMPUTER SYSTEMS ARE THE SAME BUT DIFFERENT

计算机系统设计和其它领域的系统设计有共通的地方,但计算机系统却在两个地方与其它系统天差地别:

  • 计算机系统的复杂度没有具体的物理定律来约束和限制;
  • 计算机技术的发展无法准确的预测。

1.4.1 Computer Systems have no Nearby Bounds on Composition

由于数字硬件(没有模拟硬件的噪声影响)和软件(无物理限制)上天然没有壁垒,一个胆大的设计者会误用模块化、抽象化、层次化和结构化这些工具还构造出一个复杂的庞然大物。不同其他领悟的系统,计算机系统的组合极限甚至可以等同于设计者思维的极限。
注解:只有思维能束缚住计算机设计系统的大小,设计者需要自己来为系统划定边界。

1.4.2 d(technology)/dt is Unprecedented

The incommensurate scaling rule
Changing any system parameter by a factor of 10 usually requires a new design.

计算机行业的日新月异也导致了系统的更新换代更频繁,设计师更关注新的设计而无暇顾及老系统的存在的问题。而且技术的高速发展也为很多问题带来了一种暴力的解决方式(花更多钱,等更快的硬件,用最新的算法),反而在计算机系统设计中也是一种正确的选择。
注解:人吃透计算机系统设计中奥妙的时间远远追不上整个行业技术更新换代的时间。经常一些涌现出来的新技术很容易就可以替代以前的设计方式。

1.5 COPING WITH COMPLEXITY II

因为计算机系统如此复杂,所以设计者还需要其他额外的方法。

1.5.1 Why Modularity, Abstraction, Layering, and Hierarchy aren’t Enough.

上面提到的四种设计方法是需要用户很清楚系统应该怎么来设计时下才能发挥作用,但在现实中计算机系统日新月异的变化下,设计者很难如大海捞针般去选择:

  • 正确的模块化;
  • 正确的抽象化;
  • 正确的层次化;
  • 正确的结构化。

即使有一些所谓的设计原则和指导,也都来自与之前系统的一些经验。所以设计者又找到了另一个处理复杂度的技术 —— 迭代。

1.5.2 Iteration

迭代就是先从一个最简单,满足最基本需求的系统开始设计开发,然后逐渐扩展和完善其它的需求的过程。成的迭代方法需要有正确的远见,其中就包含了两条设计的原理:

Design for Iteration
You won’t get it right the first time, so make it easy to change.

注解:迭代就要去拥抱变化,了解自己的系统在需要改变是应该调整哪些地方。

  • Take small steps.(小心谨慎)
  • Don’t rush.(循序渐进)
  • Plan for feedback.(感知反馈)
  • Study failures.(吸取教训)

Keep digging
Complex systems fails for complex reasons.

在迭代的实施过程也会受到一些阻碍,主要包括:

  • 在迭代过程中容易迷失方向,难把控全局;
  • 迭代中报喜不报忧,坏消息会被有意或无意的隐藏起来;
  • 模块的重构有较大阻力,一个原因可能是系统本身重构难度大,另一个原因则是设计者难以割舍自己之前的付出;
  • 初期迭代的成功让设计者低估了后面的困难,过度地增加新功能,导致了second-system effect[7]

1.5.3 Keep it Simple

最后也是最重要的,一个处理复杂度最行之有效的方法,同时也是最知易行难的方法就是——简单化。但就如前面提到的计算机系统没有明显的自然和物理边界来限制住它的复杂性,所以需要设计者来认为的设定这些边界,但这确实对于设计者来说太有挑战性了。

Adopt sweeping simplifications
So you can see what you are doing.

注解:设计者要时刻把”如何让系统更简单“放在心上。

WHAT THE REST OF THIS BOOK IS ABOUT

  • The pervasive importance of modularity(无处不在的模块化)
  • Principle-based system design(理论指导实践)
  • Making system robust and resilient(让系统更健壮,有更强的适应性)

  1. 0.Scalability 和 Scaling 在计算机术语中都是特指系统在所运行所需的资源增加或减少的同时,系统性能可以成比例的增加或降低的可扩展性或伸缩性。但这里用“扩长”更能表达原文的本意。
  2. 1.蝴蝶效应 (Butterfly effect)是指在一个动态系统中,初始条件下微小的变化能带动整个系统的长期的巨大的连锁反应,是一种混沌的现象。“蝴蝶效应”在混沌学中也常出现。
  3. 2.芯片设计时往往要权衡性能(频率越高性能越好)、功耗(低功耗,特别是手机或便携设备),面积(芯片的制造成本)三者之间的关系,达到最优的结果。
  4. 3.螺旋模型是一种演化软件开发过程模型,它兼顾了快速原型的迭代的特征以及瀑布模型的系统化与严格监控。螺旋模型最大的特点在于引入了其他模型不具备的风险分析,使软件在无法排除重大风险时有机会停止,以减小损失。
  5. 4.敏捷软件开发,又称敏捷开发,是一种从1990年代开始逐渐引起广泛关注的一些新型软件开发方法,是一种应对快速变化的需求的一种软件开发能力。它们的具体名称、理念、过程、术语都不尽相同,相对于“非敏捷”,更强调程序员团队与业务专家之间的紧密协作、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、能够很好地适应需求变化的代码编写和团队组织方法,也更注重软件开发过程中人的作用。
  6. 5.计算机系统体系架构可以简单分为三层:硬件、操作系统和应用程序。
  7. 6.开放式系统互联通信参考模型(英语:Open System Interconnection Reference Model,缩写为 OSI),共有七层架构。
  8. 7.第二系统效应(英语:second-system effect),又称第二系统症候群(英语: second-system syndrome),由佛瑞德·布鲁克斯在《人月神话》中提出的经验概括。它认为,在完成一个小型、优雅而成功的系统之后,人们倾向于对下一个计划有过度的期待,可能因此建造出一个巨大、有各种特色的怪兽系统。第二系统效应可能造成软件专案计划过度设计,产生太多变数,过度复杂,无法达成期待,并因而失败。
0%