第一章:系统
1. 问题类型:
①Emergent properties突生属性——Surprises
问题在系统单个组件中不会显现,但在多个属性组合在一起就暴露出来
②Propagation of effects传播效应——Small change -> big effect
很小的变化,会引起一系列的更改,造成很大开销。设计系统的要求:将错误的影响降到最低。
③Incommensurate scaling扩展不相称——Design for small model may not scale
系统的各个组成部分不一定遵守相同的缩放规则。系统不同部分的变化速度是不同的。通常是限制速度和性能的根源。
④Trade-offs权衡——Waterbed effect(将一个问题解决,另一个问题就会因此而产生)
权衡的一般模式:某种收益在整体上是有限的,设计的挑战在于首先考虑如何最大化收益,其次考虑如何避免浪费,最后考虑如何将其置于最有用的位置。
2. 系统、组件、接口、环境
①系统与环境进行交互,交互通过系统和环境之间的接口。
②人们通过研究系统各组件的行为以及组件之间的互联来预测系统的整体行为。
③组件的确定取决于研究者的两方面的观点:目的和粒度。不同粒度意味着一个上下文中的组件在另一个上下文中看起来是一个完整的系统。
④系统分析之前要明确分析系统的角度,包括如何划分组件、组件划分的粒度、系统边界,以及系统与外部环境的接口。
3. 系统的复杂性标志:
①组件的数量大
②连接的数量大
③不规则性
④没有简短的描述,而是很长的描述或文档,
⑤需要许多人设计/维护
需要采用抽象的方式避免过度深究
4. 复杂性来源:
4.1 相互影响的需求
①需求过多是系统复杂性来源之一。需求的不断增加不只是将每个需求的复杂性累加起来,各需求之间的相互影响也会引入复杂性。
②复杂性的重要性取决于观察者。
③需求增加,系统的例外随之增加,系统的复杂性也越来越大。
④在一个设计中满足不同的需求通常用“通用性”表示(即适用于不同场景),通用性增加会增加复杂性。例外与通用性是相关的,需要权衡系统的通用性和复杂性。→
设计原则:避免过度通用(适用于任何情形的设计对任何情形都不适用)
⑤如果要扩大系统规模或者升级基础硬件,扩展不相称就成了主要问题。消除扩展不相称性也会带来复杂性。
⑥需求变化也会带来复杂性,长期运行的系统随系统所处的环境的改变会改变需求。如果针对环境改变进行局部修改,很有可能会导致错误修改带来的问题比没有修改前带来的问题要多。
4.2 保证高利用率→保证系统的性能和效率。
①复杂性随着稀缺资源的利用率上升而上升。→
设计原则:收益递减律(某种好处获得的越多,下次获得这种好处所需付出的努力就越大。)
5. 处理复杂性Ⅰ→模块化、抽象化、层次化、分级化、用名字互联
①模块化:模块化的特点在于可以很容易的用好模块替换坏模块,系统能够以增量的方式不断改进而不必完全重建。模块化还可以控制修改引入的复杂性,这个特点不仅对调试有益,而且也有利于系统的渐进式改进和发展。
模块是限制故障的基本单位,是减小复杂性的最小最重要的工具,失效是指模块不能满足抽象接口的规范。不用考虑其他模块内部的组件

Divide-and-conquer 技术:分析和设计阶段将系统分解为一组相互交互的子系统,即模块
与模块化相关的设计原则:
- 不变的基础:修改模块比修改模块化更容易。→修改接口vs修改单一模块。
②抽象化:抽象化是划分一个模块的原则:最好的模块划分方法依据系统自身的边界进行抽象化,这样划分的特点是模块之间交互很少(目的就是减少互联),模块之间的传播效应也小。抽象化将接口和内部实现分离,将规范和实现分离。
保证模块之间互联最少的目标会被各种原因破坏:实现错误意外产生的互联;为了性能指标或者满足其他需求而设计的穿越模块边界的特殊互联等。
与抽象化相关的设计原则:
- 鲁棒性原则:宽于输入,严于输出。(可以消除在模块接口处产生的错误,防止错误的传播和放大)
- 安全边界原则:远离悬崖,防坠落。即使鲁棒性原则可以正确处理,跟踪汇报公差之外的输入也是重要的。两种模式:震荡模式(模块严格检查输入,拒绝任何不符合规定的数据,可以尽早发现问题)和生产模式(可以接受任何可以解析的数据)。→二者融合:接受合理的输入并汇报公差边界上的输入,以便在系统完全不可用之前修正错误。
③层次化(layering):目标:再次减小模块间的互联。
新的完整的功能集(上层)基于另一完整的功能集(低层)实现。每一层可以包含多个模块。模块只与同一层的对等模块或者相邻层次的模块交互。这种限制可以显著地控制大规模系统中模块间潜在的互联。

④分级化(hierarchy):从一小组模块开始,将他们组合成一个稳定的、自包含的、接口定义明确的子系统,然后将一组子系统组合成更大的子系统。→分级化的方法限制了模块间的交互只能发生在子系统内。分级化可以控制除接口组件外,每个模块只于其所在的子系统内的其他模块交互,接口组件还需要与上层子系统中的成员交互。分级化的好处在于模块设计师只需要关注它与紧邻子系统元素接口的交互。
分级化可将控制互联数与模块数的关系从2次方,降到1次方。n(n-1)→ (n/10) * (9*10) + n/100 *10

⑤用名字互联:名字支持延迟决策、模块替换和模块共享。连接在总线上的硬件模块也使用名字互联—地址。
延迟绑定的方法之一就是为功能命名而不是提供实现。在设计模块时采用名字进行互联可以认为其他模块已经存在,即使这项功能并没有实现,这从机制上保证了以后可以采用其他实现,直到功能真正被调用的时候,名字必须与具体实现绑定。利用名字完成绑定的延迟和更改称为“间接”,一旦模块有了名字,其他模块就可以用名字调用它,从而实现设计、成本和模块之间内部信息的共享。
相关的设计原则为:“利用间接将模块去耦合。”
6. 计算机系统与其他系统的区别:①计算机系统的复杂性是不受物理定律的限制的。②计算机系统的发展速度快。
数字系统和软件控制这两个属性使计算机摆脱了物理定律对复杂性的限制。
模拟系统 vs 数字系统
模拟系统:噪声可能来自(环境、组件的物理行为并不完全遵守可处理的行为模型);组合模拟组件(噪声来自单个组件的累加噪声,噪声的累加可能是缓慢的,但仍是存在的);随着组件的数量增加,噪声可能会控制系统的行为,噪音限制了组合系统的模拟组件的数量和级联的级数。
数字系统:
数字系统没有噪音 ,复杂性的变化不受噪音的影响。静态约束:设备可以接受的输入范围比其输出的模拟值的范围要宽。抽象化通过隐藏模块接口之下的具体实现可以控制软件的组合。电平复位:使用非线性模拟组件,组件在输入和输出之间存在增益。信号在串联的设备间传递时不会积累噪声,噪声不会限制串联的设备的数量,也不会限制数字系统组合的最大深度。
7. 迭代法:迭代法的本质就是首先构建一个实现部分功能的、简单的、可工作的系统,然后不断改进,逐渐实现所有功能。不断改进的策略可以降低复杂性。迭代需要考虑以下方面:
①遵循的原则:面向迭代的设计:设计不可能一次成功,务必使其易于修改。要记录设计所以来的前提条件,保证在需要修改设计的时候清楚地知道还有哪些部分也需要修改。
②迅速发现错误的设计和方案,可以通过较小的代价修改或清除。否则一旦其他模块对这些错误产生依赖,后续修改就困难了。
③认真规划,保证下一阶段的设计就绪再开始实现。
④便于反馈,在设计中涵盖反馈支持和鼓励提供反馈的机制。
⑤研究失效,激励反馈的机制必须保证关于失效的反馈不会因为责任人怕被处罚而将反馈忽略或隐藏。
迭代法最大的挑战在于迭代不断演进,概念一致性难以保证。
第二章:计算机系统的组成部分
1. 概述:
①现实大多数组件都可以归结为3个明确定义的抽象:存储器、解释器、通信链路。它们提供了调回、处理和通信的基本功能。
②引用是抽象组件进行交互的主要方法,也即是组件通过名字互连。
2.存储器:用来记录计算中所用数值的系统组件。
Write read
①读写一致性和前后原子性
读写一致性:从一个命名的存储单元读取的值与最近一次写入此单元的值相同。
前后原子性:每个读写操作的结果都是它们认为自己完全发生在其他读写操作执行之前或执行之后返回的结果 。
它们带来的问题有:
- 并发性
- 远程存储
- 性能提升
- 存储单元的大小与存储值的大小不相称
- 存储副本
在层次化存储系统中,某一层的设计师必须准确了解其他他调用过的层次的一致性和原子性。
②存储延迟
③存储器命名和寻址:采用连续整数寻址的存储器称为位置寻址存储器;命名不受限制的存储器成为关联存储器:实现关联存储的方式为通过关联层完成不受限的高层的名字和底层物理存储器受限的整数命名之间的映射。
④存储抽象探索:RAID
RAID目标:a.支持并发读写以提高性能;b.在多块磁盘上写数据以提高持久性
3. 解释器:执行构成计算的具体动作,是计算机系统中的主动组件。
①解释器的三层实现:
- 指令引用:解释器下一条指令的位置。
- 指令表:解释器从指令引用所指示的位置取回指令后所需要执行的动作。
- 环境引用:指向解释器所处的环境,即解释器执行当前指令动作时所基于的状态。
②中断:会改变解释器的执行顺序,原先执行的程序不再控制解释器,而将控制权交给中断处理器,它负责处理中断事件,解释器可能会修改环境引用来适应中断处理器。
③解释器流程:咋环境引用确定的当前环境下,解释器根据指令引用定位程序指令,并执行程序指令的动作,(在这中间可能会产生中断,如产生,则交给中断处理器)指令动作一般会使用或者修改环境中的数据,同时更新指令引用,执行完成后,解释器根据指令引用读取下一条指令继续执行。
④解释器异步性是实现存储器读写一致性和前后原子性的困难所在。
⑤处理器→一种解释器
指令引用→程序计数器(PC)记录当前程序下一条指令在内存中的位置。
环境引用(由寄存器维护)→内存,一组内置的位置寻址存储器(以寄存器的形式组织在一起,提供临时计算结果的快速读取),
处理器检测到程序的异常会产生中断→中断机制将控制流转到程序的异常处理句柄;
来自处理器外部的信号也会产生中断,即外部设备请求处理→中断处理句柄在完成必要操作后会将控制流返回给原程序。
⑥解释器的层次:在每个层次的分界面处,下层解释器为上层解释器提供可用的指令集。→保证每一层的设计师确信下一层的每条指令要么完成,要么什么都没做
4. 通信链路:使得信息可在不同物理组件之间流动。
Send receive
①利用名字将系统和通信链路关联起来的方式:①send和receive操作的link-name参数标识了所有和系统相连的通信链路之一;②有的通信链路是连接多条链路的链路网络。
5. 计算机系统中的命名:
①一个对象将另一个对象用作组件的方式:
- 创建组件对象的副本,按值使用 →可以增强模块化
- 为组件对象选择一个名字,在主对象中只包含此名字,按引用使用→名字简化了可修改对象的共享。
②名字的作用:
- 支持引用传递从而简化了可修改对象的共享。
- 可以推迟某个名字应该指向哪个对象的决策时间。
以名字为中介消除对象耦合的方法称为间接,确定名字和对象之间的关联称为绑定。
③命名模型:
三个命名方案:
- 名字空间:包括名字符号的字母表以及生成合法名字的规则;
- 名字映射算法:将名字空间中的部分名字和所有值中的部分值关联在一起;
- 值,值可以是对象,也可以是当前名字空间或者其他名字空间的名字。名字到值的映射是一种绑定,只要映射关系存在即认为改名字绑定到该值。
系统会同时运行多个独立的命名方案,程序解释器需要根据该名字的环境提供的信息来确定命名方案。
→确定命名方案;确定上下文;在这个上下文中解析名字;用解析的值替换名字以便后续解释。
Context→上下文,称为上下文引用
映射算法对名字解析就是寻找并返回与之关联的值的过程,它也被成为解析器。同一映射算法会遇到不同的上下文所以同一名字可能映射到不同的值。
上下文引用必须指定名字映射算法解析名字所处的上下文。
三种名字映射算法:
- 查找表
- 递归查询
- 多重查找
④默认上下文引用和显示上下文引用
程序解释器在对象中遇到名字时,必须为名字映射算法提供上下文引用。
※提供上下文引用的两种方法:如果对象或名字提供了上下文引用,则使用提供的引用,否则使用默认上下文引用。
- 默认上下文引用,由解析器提供。两种:a.作为解析器的一部分而内置的常量;注:常量只能对一个上下文有效,所以只能在全局名字空间中工作。b.是当前的环境变量中包含的上下文引用。此变量根据特定上下文设定规则设置。
- 显示上下文引用,包含在名字的对象中。两种:a. 同一对象内所有名字共享同一上下文。b.对象中每个名字都有一个独立的上下文,这时候每个名字都封装着自己的上下文引用,称为限定名。
※名字解析器在解析名字之前必须首先解析上下文引用的名字,这个递归过程可能迭代多次,但必须在调用只有一个内置上下文的名字解析器中结束。
如果路径名或者网络接入点的名字是非限定的或者不完全限定的,就在默认上下文引用中进行解析。如果是限定的(绝对路径名),则当前上下文本身也是一个名字,解析器必须首先解析上下文引用的名字,然后才能继续原先的解析过程。
⑤路径名、命名网络和递归名字解析
用户和名字解析器必须明确路径中组件的排列顺序。路径名的解析可以简单的用数字表示法类比:最低有效组件之外的部分就是用来解析最低有效组件的显示上下文。
⑥多重查找:在分层的上下文中搜索
多重查找的基本思想是:放弃单一的默认上下文,转而通过系统的方法在一系列的上下文中解析名字。如果名字出现在不同的上下文中,那么多重查找就会产生多个解析结果,命名方案就必须决定如何进行选择。
多重查找的搜索路径是一组按顺序查找的上下文。如果名字在多个上下文中都有绑定,则最先解析成功的胜出,解析器返回与之关联的值。 多重查找的每一个都会调用一个简单的单上下文名字解析器。
“路径名“是包含现实上下文的名字,而搜索路径是包含一组上下文的上下文。
⑦名字发现:即告诉对象的潜在用户本对象所导出的名字,名字发现包括两个组成部分:a导出者公布名字;b使用者搜索导出公告。
名字发现协议是递归的,原因在于用户需要首先明确搜索公告的位置的名字;递归的过程必须是可以终止的,哪怕是通过名字使用者和导出者在计算机之外直接交流来终止。
方法:a. 公认名字;b 广播;c 查询; d 介绍; e物理汇合 f 查询广播
6. 用名字和层次结构组织计算机系统
①计算机典型三层结构P49:(底层)(处理器,内存,通信链路)、(中间层)(是称为操作系统的软件模块的集合,将硬件资源抽象成便于使用的应用编程接口API,)、(最上层)(实现特殊功能的软件)。且每一层也是按照层次结构组织的。
操作系统隐藏硬件层中非常危险的操作,但并不隐藏所有硬件层的特性。
②硬件层:总线
1)处理器模块解释程序,随机访问存储器模块存储程序和数据,输入输出模块实现了计算机与外界的通信链路。
2)总线是高度定制的共享通信链路,连接各种模块,用来在模块间传递消息。总线的特征如下:
- 连接模块和总线接口的一组数据线,地址线和控制线。
- 需要有总线仲裁协议,即决定在任意时刻可以收发消息的模块的规则。有的总线设置了总线仲裁器,即在多个竞争的模块中选择可以使用总线的模块的电路或者解释器。
- 总线是广播链路,即连接在总线上的每个模块可以接收到总线上的所有消息。多数消息只有一个接收者,消息中的总线地址用来标识期望的接收者。模块的总线接口可以配置本模块响应的总线地址。
3)分离传输是一种总线设计,一个模块与另一个模块通信的过程是:
- 第一个模块首先通过控制线的总线仲裁协议请求独占总线。
- 独占被批准后,第一个模块将第二个模块的地址置于地址线,将消息内容置于数据线。
- 假设它们是异步的,第一个模块将在一条控制线上发出就绪(ready)信号,通知第二个模块信息已经在总线上了,接收模块一旦发现地址线上的地址与其自己的地址匹配,就将地址和数据线上的数据复制到它的内部寄存器中,并在另一条控制线上发出确认(acknowledge)信号,告诉发送者现在可以安全释放总线了。
如果是同步的,就不用发ready和acknowledge信号,每个时钟周期模块都会检查地址线。
- 接收者检查地址和消息,并执行相关操作。
4)I/O设备处理过程
a.处理器之一向键盘控制器发出指令,键盘将所有击键操作都发送到处理器
b.用户按键时,键盘控制器将比按下的键作为消息内容发送给指定的处理器。
c.该处理器的总线接口发现总线上有包含有其地址的消息,总线接口就将总线上的数据复制到临时寄存器,发出确认信号,冰箱处理器发出信号,使得处理器在下一个周期进行中断处理,然后中断处理句柄将临时寄存器中的数据发送到记录键盘数据的位置,也可能会通过总线消息将其发送到内存模块。
→问题:中断处理句柄必须在下一个击键事件发生之前完成临时寄存器中的数据转移。
→采用支持直接存储器访问DMA技术的磁盘控制器可以大幅度提高系统性能。
DMA中处理器向磁盘控制器发出read请求,在消息中附加了内存缓冲区的地址,磁盘控制器直接将数据连续的发送到内存模块,每次发送相应的修改内存地址。→数据只在总线上传递一次(磁盘到内存)而不是两次(磁盘到处理器再到内存)降低了总线的负载,也更加支持长消息。
→内存映射I/O
可以将总线地址直接指定到模块的控制寄存器或缓冲区上,因为处理器都将总线地址映射到内存地址空间。
内存映射I/O和DMA配合使用
③软件层:文件抽象
文件的两个属性:持久性、有名字
- OPEN的操作:open将文件名转换为局部名字空间中供read和write使用的临时名字,open还可以检查用户是否有操作文件的权限,open的最后一步是设置游标(文件指针)为0,游标记录read和write操作的位置到文件头的偏移量,有的文件系统为read和write设置不同的游标,open时初始化write游标。
Open的目的:早期是为了减少文件名解析的开销,文件名是由多个部分组成的路径名,open也减小了文件权限检查的开销。
- Close操作:close释放文件系统中维护的被操作文件的所有内部状态(如已无意义的游标和临时文件名)
close的目的:简化资源管理,程序调用close时,文件系统即知道此程序不再需要为此文件维护内部资源(游标
最近open和close的意义:文件系统用它们标记原子操作的开始和结尾,在并发文件访问中,文件系统可以将交叉的写和读实现原子性:
- 文件系统通过open和close协调并发文件访问:如果一程序已经打开文件,另一程序也想打开,必须等到第一个程序close后才可以。
- 如果文件系统在程序关闭文件之前崩溃,系统恢复之后,之前的写操作不会生效。“全部/全不”
Open/close的不足在于需要为每个文件使用者维护状态,包括文件解析后的名字和游标。
文件形式的好处:P57
7. UNIX文件系统应用程序接口 P59
①块层:
块以距离设备起始位置的偏移量为名字,块设备映射算法:输入为块号,输出为块
文件系统在磁盘上的布局结构:a引导块 b超级块 c记录磁盘块使用情况的位图 d inode表,每个文件对应一个inode。 e 分配给文件的块。
超级块中以块为单位记录着位图和inode表的大小。
②文件层:
Inode记录元数据
③inode编号层:
Inode_table
④文件名层:避免使用数字不方便,避免位置改变后需要同时修改文件名。使用新的命名层,隐藏文件管理的元数据。
⑤路径名层:
⑥连接:UNIX支持文件别名,即连接。调用Link(原路径,别名)
只能为文件创建连接,目录不得创建连接,目录是有向无环图。
UNIX的连接只是在不同的上下文中将不同文件名映射到相同的inode号,所以实现连接并不需要扩展已有的命名方案。
UNLINK(fliename)告知文件系统将filename删除,即从包含filename的文件夹中删除filename和inode号的绑定。如果是inode的最后一个绑定,就将此inode及相关块置于空闲列表中。
⑦绝对路径名层:
用户要实现文件共享,就需要知道引用其他用户文件的方法,最简单的办法就是在一个公共上下文中,为每个用户的顶级目录绑定一个名字,也就需要为此公共上下文命名。文件系统通过提供根目录这样的全局上下文来满足对其他全局上下文的需求。
两种引用根目录的方法:a. 不断调用“..”,用户判断是否到达根目录的条件是根目录的父目录是自己。b. 使用绝对路径名。
要定位一个路径的磁盘块,①首先确定存储在超级块中的inode表,②然后定位根目录,根目录的inode中的块号包含了根目录的块。
⑧符号链接层
将/dev/fd1上的目录树挂载至/flash:mount(“dev/fd1”,”/flash”)
UNIX实现挂载的方法:在/flash的内存inode中记录它是文件系统的挂载点,并一直在内存中维护此inode,知道调用Unmount。系统还在内存中记录设备及其根目录的inode号。
挂载点的信息都保存在内存中而不是磁盘上,系统失效后就丢失了,因此断电后要重新挂载。
文件挂载后,因为每个文件系统都是独立的inode空间,inode的默认上下文就是它所在的设备,所以不可能在一块磁盘上的目录项中绑定另一块磁盘中的inode号,两个方法解决此问题:1)令所以磁盘上的inode唯一,2)采用不同的方法为其他磁盘的文件创建别名。→通过符号链接或软连接将一个文件名绑定到另一个文件名中。
Type=Symlink可以在同一文件系统内或挂载文件系统间创建文件别名。如果type=Symlink,块中的数据就是目标文件路径名,而不是inode号。
直接绑定inode的是硬链接,绑定目标文件路径名的是软连接
软连接可以构成回路,由此形成的目录结构是一个普通的命名网络,非前述无环有向图;文件系统还允许为不存在的文件创建软连接,SYMLINK(“cycle“,”cycle“),进程打开这种文件,在连接链上前进一定深度之后就会报错”软连接层次过多“
8. 实现文件系统API
①open为文件返回一个简短的名字,即文件描述符fd,read,write和close用文件描述符引用文件,每个进程默认打开三个文件:标准输入(文件描述符0),标准输出(1),标准错误(2)
②一个文件可为多个进程同时使用,如果多个进程打开同一文件,那么每个进程拥有各自的读写游标,如果一个进程将打开文件的文件描述符传递给另一个进程,则两个进程共享此文件的读写游标。子进程可以继承父进程的读写游标。
③如果一个进程打开一个文件,另一进程删掉了这个文件的最后一个绑定,则在上个进程close掉后才会删掉文件的inode
④全局文件打开表(file-table):记录所有打开且尚未关闭的文件的相关信息,包括文件的inode、文件游标,以及打开此文件的进程的计数。文件描述符。
⑤文件描述表(fd-table):记录文件描述符在文件打开表中的索引,由于文件游标记录在文件打开表而不是文件描述表,所以子进程可与父进程共享文件游标。
⑥父进程创建子进程后,子进程会继承父进程的文件描述符,即父进程的fd-table中的每个表项都复制到子进程fd-table中,所以父进程和子进程fd-table中的表项都指向file-table中的相同表项,也就实现了文件游标的共享。

第三章 命名方案的设计
一、命名方案中的考虑因素
1. 模块化共享
模块化共享的缺乏以名字冲突的形式显现。
实现模块化共享的方式是每个子系统都提供自己的命名上下文,然后设计出多个上下文之间的交叉引用的方式。
①实现模块化共享的探索:为每个子系统都提供自己的命名上下文,然后再设计出在多个上下文之间交叉引用的某种方法。
- 在一个命名上下文中简单的绑定所有它们的名字来集成两组程序。→
将有两个模块竞争相同名字的绑定。
- 为每组程序创建单独的上下文。→
程序解释器需要一些规则,以便为名字的每次使用确定所用的上下文。
如何知道function是该在X的上下文中解析而不是在Y的上下文中解析呢?
- 在X上下文中增加对Y的绑定,并将明确的上下文引用连接到每个模块(要求需要修补模块的表达,某些模块可能属于其他人而不允许进行修补)
- 增加程序解释器以记录最初发现每组程序的上下文。程序解释器将使用对应上下文来解析在该程序中发现的所有名字。→会造成错误:在X上下文中,调用Y,同时调用X的function,上下文选择规则会选择Y的function运行,而不是X的function
→解决规则:在X上下文中放置一个间接名字,使被调用的Y绑定到Y的上下文。
C.另一个将上下文引用连接到对象而无需修改对象表示的更加优雅的方法是把对象的名字不直接关联到对象本 身,而是关联到一个包含原始对象加上其上下文引用的结构体。 “闭包”
2. 元数据和名字重载:
①元数据:对象的名字(用户友好的)、应该与它关联的上下文引用、唯一的标识符、对象的类型(可执行程序、文字处理文本)、视频流)、创建、最后修改和上次备份的日期,备份副本的位置、所有者名字、创建它的程序.。P80
→用于了解一个对象却不能在对象本身内部发现(或不易找到)、允许读取或更新对象的人员名单,以及对象的表示的物理位置。
- 维护元数据的策略:在记录文件物理位置并提供读取和更新元数据方法的同一文件系统结构中为元数据保存存储空间。
②没有任何重载的名字称为单纯名字,应用于单纯名字有意义的操作只有compare、resolve、bind、unbind
③人们不能通过运用解析操作从中提取元数据。
④重载名字能以两种不同的方式使用:
- 作为一个标识符,使用compare、resolve、bind、unbind
- 作为提取重载元数据的源
重载制造了保持名字不变的目标和修改重载信息的需要之间的一种紧张。
一个名字对一个模块是不透明的,如果该模块不知道如何解释该名字。
3. 地址:定位对象的名字
在地址中发现的重载的位置信息会导致名字脆弱性。
借助间接性来分离模块的设计原理来隐藏地址。
4. 生成唯一的名字:
①生成唯一的名字方法:
- 发放连续的整数或足够精度的时间戳。
- 从一个足够大的名字空间中随机选择名字,这样意外选择两个相同名字的概率很小。(随机性选取名字复杂)
- 为具有二进制表示并且命名时已存在的对象选择对象的内容作为它的名字。(为相同内容的两个对象分配相同的名字)→可以通过这种方法发现不想要的副本,名字可能会很长。可以使用哈希。
②MAC地址:MAC地址仅被看作是一个特定硬件组件的唯一名字,而不是它所嵌入的系统的名字。
决定是什么组成了一个由可更换部件构建的系统的独特标识,最终是一个制约命名方案设计人员任意选择的公约。
5. 名字、值和绑定的相对寿命
一个命名方案、一个名字、该名字对一个值的绑定、接受名字绑定的值都可以有不同的寿命。
名字和值一般都是很长寿的,但是把一个关联到另一个的绑定可能是短暂的。
当一个名字比它的绑定还长寿,仍试图解析它的名字的任何用户会遇到一个悬挂引用,这是对一个以前绑定的名字的引用。
当一个名字空间是无限的并且名字是从不重用的,悬挂引用只影响因为某些原因已经从以前的值上去绑定的名字的用户。
悬挂应用的反面:当一个对象比对它的每个名字绑定都更长寿,该对象成为丢失的对象,问题是可能没有好办法去回收它们的物理存储,这种定期失去对象的引用的系统称为 存在存储泄漏。
二、统一资源定位器URL
1. 服务器发送的页面可能包含一个部分/相对URL,它不带有自己的上下文,为了处理它,必须提供缺省的上下文,URL规格说明是从浏览器发现这个链接的页面URL中获得一个上下文。
2. URL的主机名字是大小写敏感的。
3. url的错误上下文引用
1)本地文件系统名字空间到url的映射不是唯一的,一些不同的url可以针对相同对象有不同的路径名字。
“/alice/home.html”实际是“/alice/www/home.html”
而如果在这个页面有一个“context.html”的链接,则根据默认上下文引用得到http://web.pe.edu/alice/context.html①,而实际上正在寻找的应该是http://web.pe.edu/alice/www/context.html②,也就是说使用①种情况会导致返回碰巧在/alice中的context.html的文件,但这并不是我们想要的。
- 解释相对名字“..”时,也会出现问题。Web指定”..”是一种语法符号,指“通过摒弃路径名字的最不重要组成部分,修改默认的上下文引用”。 而unix在当前目录查找名字“..”则会映射到inode名字空间的父目录。
例如:默认上下文是http://web.pe.edu/,如果实际上是“/alice/www/home.html”而在上下文中使用“/alice/home.html”,得到的url为“http://web.pe.edu/alice/home.html”, 那么如果经此路线点击home.html,再从home.html点击“../phone.html”那么l浏览器将生成” http://web.pe.edu/phone.html”将中间的alice隐藏掉了,而不管home的父目录是www。
而如果经“http://web.pe.edu/www/alice/home.html”,路径在点击home.html,又在home.html中点击“../phone.html”那么则将到” http://web.pe.edu/alice/phone.html”,总而言之,web的“../”总是将在url中的“父目录“隐藏掉.
解决url错误上下文引用的方法:P93
4. url中的名字重载
服务器不能让客户来维护关于购物会话的任何信息。
服务器以其上一个状态维护文件的标识符的形式,在url的路径名部分中对状态进行编码。
浏览器将用户的搜索查询编码到已提交的url的路径名部分。
→避免将站点名字陷入指向它的url的一个方法是,选择一个服务的名字,并安排DNS绑定该服务器名字作为站点的一个间接名字。那么如果必须把网站移动到另一台不同计算机,只需要修改对服务名字的绑定,原有的url就能工作。
5. 用户友好的大小写敏感性(大小写敏感→大写和小写分别代表不同含义)
互联网是大小写保留的,cse.com=CSE.com。
Internet 邮件系统也是大小写保留的,所以alice@edu.cn=Alice@edu.cn
Kerberos身份验证系统是大小写敏感的。
DNS是大小写不敏感的。
Unix是大小写敏感的。
第四章:使用客户及服务增强模块化
实现客户/服务模型的一个有效方式是,分别将客户和服务模块运行在各自的计算机上,通过计算机之间的连线设置通信路径。
发送和接受消息的两种风格:远程过程调用和发布/订阅
- 客户/服务组织方式
- 大规模程序中创建模块化的方式为:将它们分成多个相互调用的被命名的过程。
→结构体成为模块化,但是错误可以从调用者传播到被调用者。
①程序员在被调用者过程中如果出现了死循环,则永远不会返回。
②调用者过程和被调用者过程共享相同的栈,任何一方可能意外将数据写入到分配给另一方的地址空间。
→软模块化
- 从软模块化到强制模块化
①软模块化:
软模块通常以规格说明来获得,但是没有把模块间的交互限制到规定的接口上。
不同的过程共享相同的地址空间,如果一个有缺陷的过程错误的篡改了一个全局变量,这时,不调用该缺陷过程的过程也可能受到影响。
使用受限的和类型安全的实现语言,能在一定程度上改善软模块化的问题。
②强制模块化:通过某种外部机制来强制实现的模块化。
限制减少了错误传播的机会。
允许验证用户是否正确的使用模块。
有助于阻止攻击者侵入一个模块的安全体系。
- 客户/服务的组织方式
①强制模块化的一个好方法就是把模块之间的交互限制到明确的消息上。
②客户是发起请求的块:它创建包含服务执行任务所需的所有数据的消息,并把它送到服务端。
服务是响应请求的块:从请求消息中提取参数,执行请求的操作,建立响应消息,并把响应消息返回给客户,等待下一个请求的到来。
缺点→需要每个模块一台计算机,设备成本大。
③客户必须把参数转化成标准形式,以便服务方能正确的解释参数→这个转化过程称为“组装 marshaling”。
组装通常包括把一个对象转化为一个带有足够范式信息的字节数组,以便拆装unmarshal过程能够将它装回一个对象。
服务过程等待请求到来→卸装请求→检查请求→处理请求→返回一个组装好的响应
客户和服务组织方式的优点→P111
④设计者通常在更大粒度的软件模块之间应用客户/服务组织方式。向更大粒度发展的趋势出现。因为一个应用中的各个过程典型的需要紧密耦合,比如它们都操作相同的共享数据结构,把每个过程都放置在分离的客户端或者服务端,将使得对共享数据的操作很困难,因此设计者需要在易于访问模块所需数据和易于在模块内部传播错误之间进行折中。
- 可信中间方:多个或许彼此互相猜忌的客户端之间作为可信的第三方服务端。可信中间方能够很小心的控制共享资源。
可信中间方增强多个客户端之间的模块化,保证一个客户端的错误对另一个客户端造成有限的影响。
例子→文件服务、电子邮箱服务端、通过让可信中间方提供大部分功能来简化客户端
- 一个简单的例子服务
编辑→文件服务→块服务
- 客户端和服务端之间的通信
- 远程过程调用RPC:将调用的对象从服务器端迁移到客户端是针对过程的函数调用
RPC系统通过隐藏构建和格式化消息的很多细节,简化客户端和服务器端的编程。
Stub→装载参数、通过网络发送请求、执行服务的stub、拆卸参数、装载返回结果、通过网络收取响应、拆解响应
→隐藏了调用者和被调用者中装配的消息和通信的细节。
- RPC不等于过程调用P120
三个方面RPC与过程调用不同:
①RPC减少了调用者和被调用者之间的同名效用,它将被调用者的失败暴露给调用者,由此调用者可以恢复。
②RPC引入了在过程调用中不会出现的失败。程序员需要修改相关的代码,并且这些修改经常要求程序员对周围的代码做出调整。
引入的新的失败类型为:“没有响应”:客户端无法判断是哪里出错:可能是在服务器运行请求之前已经出错;或者服务器端运行请求的操作时发生了错误。
处理没有响应的策略:至少一次、至多一次、恰好一次
③远程过程调用比普通过程调用需要更多的时间,执行一个普通过程调用的指令数目远少于使用stub。
④一些编程语言的特点无法与RPC很好的结合起来。
- 通过中间方通信:
①电子邮件中的中间方:实现缓存的通信,缓存的通信提供发送/接收的抽象,但避免了发送者和接收者同时在线的要求。允许消息的传递在时间上改变。中间方可以缓存消息,直到接收方上线。
②发布/订阅:利用通信的三个机会的一般形式通信
- 发送者和接收者可以对是推送还是拉取消息进行不同的选择。
- 中间方的存在为应用“使用间接方解除模块耦合”的设计原则提供了机会。
- 当通过中间方的间接通信可用时,设计者还要考虑何时何地复制消息。
- 因特网域名系统DNS
DNS实际上是一个通用的名字管理和名字解析系统,分级的将名字管理分布在不同的命名机构,也分级的把解析域名的任务分布在不同的名字服务器上。
DNS的主要用途是把称作域名的用户友好的字符串名字与称作因特网地址的面向机器的网络接入点的二进制标识符关联起来,域名是分级结构的。
DNS过程:接受一个请求包、查询表格、发送响应包
DNS:一个服务器维护一组名字记录,每条记录将一个域名绑定到一个因特网地址。
- DNS名字解析的三种设计方式:
①电话簿模型:给每个网络用户一份包含每个域名及其相关因特网地址列表的文件副本。→为保持域名文件最新所带来的网络流量将会以域名数目的三次方增长。
②集中式目录服务模型:不能很好的满足域名分配中的责任委托的需要。
③分布式目录服务模型:能提供代理,并能够在维持可靠性和性能的同时对规模增长做出响应。
- 分布式目录服务模型的步骤:
①客户端发送名字解析请求,名字服务器查看它所负责的域名记录集合。
②如果找到一个名字记录,返回该记录作为响应。
③如果没有找到,则查询转交记录的一个单独组合,每条转交记录将DNS名字空间的一个分级区域绑定到某个其他名字服务器,其他名字服务器能帮助解析该命名分级区域内的域名。
- DNS特点:
①拥有某一域名对应的名字记录或者转交记录的服务器,被视为该域名的权威名字服务器,由于,名字服务器不会拥有它自己域名对应的名字记录,因此它对于自己的域名不能是权威的。
②发送请求到一个本地名字服务器的能力意味着,常见情况中,客户端、名字服务器、目标域名都在相同的域里,可以使用一个单一的请求/响应交互很快地处理。
③一些域名服务器提供递归的名字服务。
④除自身权威记录外,每个名字服务器预期维护所有从其他名字服务器获取的名字记录的一个缓存,提供递归的名字服务的服务器收集能够极大的加速未来的名字解析请求的记录。
- 层次化的名字管理:
分散责任是分布四目录服务模型的主要优点之一,相同的层次结构也通过分散操作名字服务器的责任来分散管理名字分发任务。
- DNS的其他特点:
DNS规范要求运行名字服务的各个组织安排至少两个相同副本的服务器。
间接名字①修改服务器②允许一台计算机以两个非常不同的命名域的形式呈现。
- 网络文件系统NFS
P131
UNIX vs NFS
- 在打开一个文件描述符“dir1/f”后,再对原来的文件的目录进行重命名(dir1变成dir2,dir3变成dir1),在同一台计算机上,并共享一个unix,会读取dir2/f(现在的dir2,也是原来的dir1) ,NFS读取现在的dir1/f(原来的dir3/f)
- 打开一个f的文件描述符“dir1/f”后,删除f,再重新创建一个同名的f,在同一台计算机上,并共享一个unix,会读取原本的f,如果服务器重用了原来f的而inode,在NFS中会读取新的f,但因为文件描述符有生成编号,所以NFS中可以允许NFS的服务器立即重用inode,但是在读取的时候会报错:陈旧的文件句柄。
- NFS 远程过程调用设计成服务器是无状态的,客户端必须记录文件游标。服务器不必维护除了磁盘以外的任何其他状态。
①客户端将文件游标作为一个参数包含在 read远程过程调用中,文件句柄包含为了在服务器上找到文件inode所需的所有信息。
②无状态的特性简化了从服务器失效中的恢复,客户端能够只是重复请求,直到收到回复,→NFS远程调用实现了至少一次。
③但是,有些操作是幂等的,所以不能简单的操作多次,NFS实现了“回复缓存”,回复缓存用事务标识符来索引记录事务标识符对应的响应,服务器收到一个请求后,它在回复缓存中查找事务标识符,如果该标识符在缓存中,服务器无需执行该请求就返回缓存中的回复。
维护缓存回复→软状态,将他存储在非易失性存储中代价太大,因此存储在磁盘中,因此磁盘读写成为性能瓶颈。
- 扩展UNIX支持NFS
Vnode是一个易失性内存中的结构,它抽象化文件或目录是通过本地文件系统还是远程文件系统来实现的。这个设计允许文件系统调用层中的许多功能使用vnode而不必担心文件或目录是本地的还是远程的。
→一台计算机能够简单支持多种不同的本地文件系统。
NFS客户机维护各种缓存,客户端为每个打开的文件保存vnode,客户端知道打开文件的文件句柄(vnode中包含了文件句柄),客户端也缓存最近使用的vnode,它们的属性、那些缓存vnode的最近使用块,以及路径名到vnode的映射。缓存技术降低了对远程文件的文件系统操作的延迟,对已经缓存vnode的块,客户端能够避免远程过程调用的开销。
- 一致性
关闭到打开的一致性:①一个客户端调用write、close,另一个调用open、read可以看到最后的数据;②两个客户端同时打开,一个写,一个读,读到的可能不是最新的。
对每个读写操作都提供一致性:NFS将保证不同客户端上的两个应用同时打开同一个文件,一方可以看到另一方写的结果。
第五章:使用虚拟化技术强制模块化
- 在一个计算机内部使用虚拟化技术进行客户端服务器组织
- 虚拟化某一物理对象的程序模拟了物理对象的接口:①通过复用一个物理实例的方式建立许多虚拟的对象,②通过将许多物理实例进行聚合提供一个更大的虚拟对象;③使用仿真的方式通过不同类型的物理对象中实现一个虚拟对象。
- 虚拟化计算机的抽象概念
实现虚拟计算机的三个主要抽象概念:①在有界缓存区上发送和接收(虚拟通信链路)②虚拟内存(虚拟化的内存)③线程(虚拟化的处理器)
- 线程:
①线程的引入可以帮助改进中断机制:外部事件中断一个处理器,这个事件可能跟当前执行在处理器上的线程没有关系,那么,在发生中断的时候,处理器调用中断处理函数,在处理函数返回的时候继续执行中断之前运行在处理器上的线程,如果一处理器由于正在处理一个中断条件下不应该被中断,则下一个中断则可能去中断计算机中的另一个处理器,这样就实现了中断的并发处理。
②与当前线程有关的中断为异常。异常处理函数运行在被中断的线程的上下文中,它可以读取并且修改被中断线程的状态。
③异常处理函数运行在被中断的线程的上下文中,中断处理函数运行在操作系统的上下文环境中。

1090

被折叠的 条评论
为什么被折叠?



