重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF...

101
普通高等教育“十一五”国家级规划教材 重 点 院 校 推 荐 教 材 李西宁 编著

Transcript of 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF...

Page 1: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

普通高等教育“十一五”国家级规划教材 重 点 院 校 推 荐 教 材

分 布 式 系 统

李西宁 编著

北 京

Page 2: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

内 容 简 介

本书是作者在国外多年讲授分布式系统课程经验积累的基础上,结合

国内现状编写的教材。 本教材以传统的分布式系统理论和经典算法为基础,重点介绍系统的

构成模块、实现方案以及存在的问题。具体的构成模块包括网络、通信、

并发计算、域名服务、同步与互斥、时间与协作、分布式事物处理、复制

技术、容错机制以及安全机制。本教材还简要地介绍了该领域里的新进展,

如移动软件代理、P2P 系统、网格计算、万维网服务等。作者试图采用浅

显易懂的语言描述分布式系统的原理与实现,做到概念清晰,深入浅出。

为方便学生复习、掌握书中所学知识,每章末附有丰富的习题。本书既保

证内容的前后呼应,又力图做到每一章节自成体系,教师可根据学生的不

同基础和需要,适当进行裁剪。本书配有中/英双语电子教案,有教学需求

的教师可到科学出版社网站上下载(http://www.sciencep.com)。 本书可用作高等院校计算机及相关专业本科高年级或研究生一年级的

教材,亦可供科研工作人员参考。

图书在版编目(CIP)数据 分布式系统/李西宁编著. —北京:科学出版社,2006 普通高等教育“十一五”国家级规划教材 重点院校推荐教材

ISBN 7-03-016760-0

Ⅰ. 分 … Ⅱ. 李 … Ⅲ. 分布式操作系统- 高等学校- 教材

IV. TP316.4

中国版本图书馆 CIP 数据核字(2006)第 141634 号

责任编辑:鞠丽娜/责任校对:赵 燕 责任印制:吕春珉/封面设计:三函设计

出版 北京东黄城根北街 16 号

邮政编码:100717 http://www.sciencep.com

印刷 科学出版社发行 各地新华书店经销

* 2006 年 12 月第 一 版2006 年 12 月第一次印刷

印数:1-4 000

开本:787×1092 1/16印张:20 字数:474 200

定价:32.00 元

(如有印装质量问题,我社负责调换< >)

销售部电话 010-62136131 编辑部电话 010-62138978-8002

Page 3: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

谨以此书献给我的导师,中国科学院院士、

南京大学计算机系教授孙钟秀先生。感谢

先生将我引入科学研究之路。

Page 4: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

起源于 20 世纪 70 年代中期的分布式系统已经历了近 30 年的开发与研究,从简单

的多机文件共享到广义的资源共享,从单一的计算模型到多种多层次的计算模型,从封

闭的局部网络到开放的全球网络,分布式系统已演化成近代计算机系统的基本组织结

构,支持非常广泛的工业、商业应用。分布式系统自身也从学术界走入商业化,日益丰

富完善,日益规范成熟。 概言之,分布式系统是一组协同工作的计算机。这组计算机被网络连接,用通信的

手段进行协调同步,用合理的算法调度分配资源,从而达到高效可靠的计算。当然,分

布式系统是一个泛指词。如果细分的话,我们可以有不同种类不同功能的分布式系统。

例如,以分布计算为主的系统一般采用紧密耦合计算机系统,或者是共享内存的多处理

器,或者是用高速网络相连的一组同构计算机。而另一方面,以网络服务为主的系统则

面临多种多样的计算设备。这些设备可以是计算机、无线电话、传感器乃至家用电器。

它们可以形成一个局域网,也可以开放到一个广域网。此外,现代分布式系统一般是在

网络操作系统外层增加一层软件,亦称为“中间件”。用中间件实现的分布式系统易于

标准化,使得不同厂商生产的软/硬件在用户面前呈现出友好的、一致的界面。 与单机系统相比,分布式系统具有几个显著的特征:共享性、开放性、并发性、可

调节性、容错性以及透明性。资源共享是分布式系统的首要特征。资源可以是数据,可

以是软件,也可以是硬件。例如,在客户/服务器模型里,共享的资源就是服务器所提供

的各种服务。开放式的分布式系统遵循一套标准的协议和界面为用户提供服务,其主要

优点是灵活性,在不影响现存服务的前提下,新的共享资源可被安全地扩充到系统中。

顾名思义,并发性指的是在同一时间处理多个任务,其优点在于提高效率。可调节性的

含义很广,不仅一个分布式系统的功能可调节,其网络规模亦可调节,管理结构也可调

节。容错性关系到一个分布式系统能否可靠地运行,当事故或异常事件发生时,具备容

错能力的系统可以自动排除故障并恢复运行。为了方便用户使用,一个分布式系统要尽

量透明,要尽可能地隐藏系统的内部细节,使之作为一个整体展示在用户面前,这样才

能易学易用易管理。 分布式系统并不是一种抽象的概念。要搞清楚分布式系统的原理及设计,我们不

仅要探讨相关的理论基础,也要通过算法设计与分析来理解系统实现中的具体问题。

在了解了分布式系统的目标和基本模型的基础下,我们将引入分布式系统的构成模块,

重点介绍现存的解决方案以及存在的问题。具体的构成模块包括网络、通信、并发计

算、域名服务、同步与互斥、时间与协作、分布式事务处理、复制技术、容错机制以

及安全机制。通过学习,学生们应能掌握设计和实现分布式系统的基本知识和技能,

并能把学到的知识运用到实践中。此外,本书最后一章还简要地介绍了分布式系统研

究领域里的新进展,使得学生们在掌握基本原理的同时,进一步了解分布式系统研究

Page 5: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·ii·

的新领域和新方向。 本书试图采用浅显易懂的语言描述分布式系统的原理与实现,力图减少对读者知识背

景的要求。由于本书的内容颇为广泛,涉及程序设计、操作系统、数据库、网络通信、安

全保密以及算法复杂性等,因此我们希望读者具备这些领域的基础知识。本书按照 36(课

堂教学)学时设计,可用作研究生或者本科高年级学生的教材。根据学生的不同基础,可

适当进行删节。此外,本书每章之后都附有一组练习题,题目可分为三类:① 基本概念

复习题;② 快速思考题;③ 作业题。为便于多媒体教学,本书配有中/英双语电子教案,

有教学需求的教师可到科学出版社网站上下载(http://www.sciencep.com)。 南京大学孙钟秀教授,金志权教授,茅兵教授在百忙之中抽出时间阅读本书的初稿,

并对书中内容和术语提出了许多有益的建议;科学出版社的鞠丽娜老师以及南京大学的

徐洁磐教授、郑国梁教授在本书出版过程中给予了热情的帮助,在此由衷地向他们表示

感谢。 由于作者的学识有限,书中难免有不当之处,恳请同行专家和广大读者提出宝贵意见。

作 者 2006 年 7 月

Page 6: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

目 录

第一章 引论 .................................................................................................................................................................. 1 1.1 分布式系统的定义 .................................................................................................................................... 1

1.1.1 历史背景 .............................................................................................................................................. 2

1.1.2 分布式系统的应用.............................................................................................................................. 4

1.2 分布式系统的显著特征...........................................................................................................................6 1.2.1 基本设计目标 ...................................................................................................................................... 7

1.2.2 用户需求 ............................................................................................................................................ 11

习题.......................................................................................................................................................................... 12 第二章 分布式系统概念和结构 .......................................................................................................................... 14

2.1 硬件概念 ..................................................................................................................................................... 14 2.1.1 基于总线的多机系统........................................................................................................................ 16

2.1.2 基于交叉开关的多机系统 ............................................................................................................... 17

2.1.3 基于网络的多机系统........................................................................................................................ 19

2.2 软件概念 ..................................................................................................................................................... 20

2.2.1 分布式操作系统 ................................................................................................................................ 21

2.2.2 网络操作系统 .................................................................................................................................... 23

2.2.3 中间件系统 ........................................................................................................................................ 25

2.3 系统平台模型............................................................................................................................................ 27

2.3.1 客户/服务器模型............................................................................................................................... 27

2.3.2 浏览器/服务器模型........................................................................................................................... 30

2.3.3 模型界面与多级(MULTI-TIERED)结构 ................................................................................... 31

习题.......................................................................................................................................................................... 33

第三章 网络与通信 .................................................................................................................................................. 35

3.1 计算机网络................................................................................................................................................. 35

3.1.1 网络技术 ............................................................................................................................................ 36

3.1.2 网络协议 ............................................................................................................................................ 40

3.2 通信模型 ..................................................................................................................................................... 44

3.2.1 消息传送式通信 ................................................................................................................................ 45

3.2.2 请求-回应式通信(远程过程调用) ............................................................................................. 53

习题.......................................................................................................................................................................... 62

第四章 并发计算....................................................................................................................................................... 65 4.1 并发计算起源............................................................................................................................................ 65

4.1.1 进程 .................................................................................................................................................... 66

Page 7: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·iv·

4.1.2 线程 .................................................................................................................................................... 69

4.1.3 并发计算中的同步与互斥 ............................................................................................................... 75

4.2 客户/服务器并发系统 ............................................................................................................................ 80

4.2.1 客户软件 ............................................................................................................................................ 80

4.2.2 服务器软件设计 ................................................................................................................................ 83

4.3 软件代理 ..................................................................................................................................................... 86

4.3.1 软件代理技术 .................................................................................................................................... 87

4.3.2 移动软件代理 .................................................................................................................................... 89

4.3.3 软件代理通信语言............................................................................................................................ 92

4.4 程序迁移 ..................................................................................................................................................... 95

4.4.1 程序迁移模型 .................................................................................................................................... 96

4.4.2 程序迁移中的资源管理 ................................................................................................................. 100

习题........................................................................................................................................................................ 102

第五章 命名系统及对移动实体的定位.......................................................................................................... 104

5.1 命名问题 ................................................................................................................................................... 104

5.1.1 命名方式 .......................................................................................................................................... 104

5.1.2 名字的识别与解析.......................................................................................................................... 108

5.1.3 命名空间和域名系统...................................................................................................................... 112

5.2 对移动实体的定位 ................................................................................................................................ 118

5.2.1 移动 IP 技术 .................................................................................................................................... 118

5.2.2 移动代理的定位方法...................................................................................................................... 121

习题........................................................................................................................................................................ 125 第六章 分布式系统的同步与互斥 ................................................................................................................... 127

6.1 时间与同步............................................................................................................................................... 127

6.1.1 物理时钟 .......................................................................................................................................... 128

6.1.2 物理时钟同步算法.......................................................................................................................... 131

6.1.3 逻辑时钟 .......................................................................................................................................... 133

6.1.4 逻辑时钟同步算法.......................................................................................................................... 135

6.2 分布式协调机制 ..................................................................................................................................... 136 6.2.1 全局状态 .......................................................................................................................................... 137

6.2.2 选举算法 .......................................................................................................................................... 138

6.3 分布式互斥算法 ..................................................................................................................................... 140

6.3.1 基于逻辑时钟的算法...................................................................................................................... 141

6.3.2 基于令牌的算法 .............................................................................................................................. 144

习题........................................................................................................................................................................ 148

第七章 分布式事务处理 ...................................................................................................................................... 150

7.1 基本概念 ................................................................................................................................................... 150

7.1.1 事务处理模型 .................................................................................................................................. 151

7.1.2 事务处理分类 .................................................................................................................................. 152

Page 8: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

目 录 ·v·

7.2 事务处理的实现 ..................................................................................................................................... 155

7.2.1 并发控制 .......................................................................................................................................... 155

7.2.2 原子提交协议 .................................................................................................................................. 164

7.2.3 分布式死锁与检测.......................................................................................................................... 169

习题........................................................................................................................................................................ 172

第八章 复制及复制一致性.................................................................................................................................. 175

8.1 复制的概念............................................................................................................................................... 175

8.1.1 动机和目的 ...................................................................................................................................... 175

8.1.2 复制技术的基本结构...................................................................................................................... 177

8.2 以数据为主的一致性模型 .................................................................................................................. 179

8.2.1 基于读写次序的一致性模型 ......................................................................................................... 180

8.2.2 基于同步操作的一致性模型 ......................................................................................................... 185

8.3 以客户为主的一致性模型 .................................................................................................................. 189

8.3.1 单调读/写模型................................................................................................................................. 190

8.3.2 混合读/写模型................................................................................................................................. 192

8.4 一致性协议............................................................................................................................................... 194

8.4.1 分布式更新算法 .............................................................................................................................. 194

8.4.2 复制一致性协议 .............................................................................................................................. 200

习题........................................................................................................................................................................ 205

第九章 容错机制..................................................................................................................................................... 207

9.1 基本概念和模型 ..................................................................................................................................... 207

9.1.1 故障分类 .......................................................................................................................................... 209

9.1.2 硬件容错机制 .................................................................................................................................. 212

9.2 进程容错机制.......................................................................................................................................... 213

9.2.1 基本设计思想 .................................................................................................................................. 214

9.2.2 故障屏蔽协议 .................................................................................................................................. 216

9.3 通信可靠性............................................................................................................................................... 219

9.3.1 点对点通信 ...................................................................................................................................... 219

9.3.2 组播通信 .......................................................................................................................................... 222

9.4 恢复技术 ................................................................................................................................................... 226

9.4.1 检查点技术 ...................................................................................................................................... 227

9.4.2 日志技术 .......................................................................................................................................... 230

习题........................................................................................................................................................................ 234

第十章 安全机制..................................................................................................................................................... 236

10.1 安全性概念 ............................................................................................................................................ 236

10.1.1 威胁及安全对策............................................................................................................................ 237

10.1.2 安全机制的基本实现方案 ........................................................................................................... 239

10.2 加密技术 ................................................................................................................................................. 242

10.2.1 对称加密 ........................................................................................................................................ 243

Page 9: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·vi·

10.2.2 非对称加密 .................................................................................................................................... 246

10.2.3 散列函数加密 ................................................................................................................................ 249

10.3 认证与访问控制................................................................................................................................... 252

10.3.1 认证方法 ........................................................................................................................................ 252

10.3.2 信件的完整性和可信度 ............................................................................................................... 258

10.3.3 访问控制 ........................................................................................................................................ 259

习题........................................................................................................................................................................ 264

第十一章 分布式系统的发展............................................................................................................................. 266

11.1 P2P 计算.................................................................................................................................................. 267

11.1.1 P2P 结构模型................................................................................................................................. 268

11.1.2 P2P 系统分类及实现 .................................................................................................................... 271

11.2 网格计算 ................................................................................................................................................. 276

11.2.1 网格计算模型 ................................................................................................................................ 277

11.2.2 网格系统的实例:Globus 项目................................................................................................... 280

11.3 Web 服务 ................................................................................................................................................. 284

11.3.1 Web 服务协议 ................................................................................................................................ 285

11.3.2 设计 Web 服务............................................................................................................................... 288

习题........................................................................................................................................................................ 291

英汉术语对照表 ......................................................................................................................................................... 293

主要参考文献 .............................................................................................................................................................. 307

Page 10: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构

从硬件方面来看,一个分布式系统是一组由网络连接的能够独立工作的计算机。而

从软件来看,这组计算机应该遵循一种“民主集中式”的理念,通过通信相互协调合作。

当我们深入考察分布式系统的硬件结构时,可以发现实际存在着多种多样的硬件组织结

构。同样,分布式系统软件也根据不同的硬件结构和应用领域展现出多种多样的模型和

设计风格。在本章中,我们将要讨论这些基本概念,给出典型的硬件结构和软件模型,

并且简单地描述它们所适合的应用领域。

2.1 硬 件 概 念

硬件的核心是计算机,计算机的核心是中央处理器(CPU)。CPU 由指令驱动对数

据进行加工。如果我们用 I 代表指令流,用 D 代表数据流,我们可以给出 4 种可能的系

统结构,这种分类法是由美国计算机科学家 Flynn 首次提出的,见图 2.1。

I1 I2 In-1 In

I

D

D'

I

D1 D2 Dn-1 Dn

D'1 D'2 D'n-1 D'n

D'1 D'2 D'n-1 D'n

D1 D2 Dn-1 Dn

I1

D

I2

D'

In-1

In

通信线路

SISD SIMD

MISD MIMD 图 2.1 Flynn 系统结构分类

Page 11: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·15·

1)单指令流单数据流(SISD,single instruction single data); 2)单指令流多数据流(SIMD,single instruction multiple data); 3)多指令流单数据流(MISD,multiple instruction single data); 4)多指令流多数据流(MIMD,multiple instruction multiple data)。 SISD是我们最常见的单机系统结构。CPU由一个顺序程序的指令流I所控制,对输

入的数据流D进行操作,产生加工后的输出数据流D'。这种硬件系统结构直到今天还占

据着主导地位,我们所使用的大多数个人计算机和工作站都是基于这种结构的。虽然有

人认为传统的SISD结构已经不复存在,即便是个人计算机或单片机都存在不同程度的硬

件化的并行操作,可是从整体来看,它们仍属于SISD的范畴。在进行科学计算的时候,

我们经常需要处理大量的数据,而很多数据是以矩阵或矢量的形式出现。由于这些数据

类型的特殊性,我们往往是在两组数据上进行一个同样的操作。如矩阵加法,我们只要

把两个同类矩阵的各对应元素相加就可以了。可是,如果仍旧使用SISD结构,我们必须

用循环的方式把每一对输入Di相加而产生输出Di',这样做显然效率很低。为了高效地处

理这类应用,人们开发了SIMD系统,也就是我们常说的并行处理机或矢量处理机。这

样的系统一般都拥有相当数量的CPU,少到数十,多至成千上万,而且都由一个指令流

进行控制。 在理想的情况下,也就是说当一个 SIMD 系统有足够多的 CPU 来同时接纳所有矩

阵元素对的情况下,一条指令就可以完成两个矩阵的加法操作。例如美国宇航局所拥有

的大规模并行处理器系统(MPP,massively parallel processor),就是由 128*128 的 CPU方阵(一共有 16384 个 CPU)组成。我国自行研制的银河系列和曙光系列巨型计算机也

具备有 SIMD 功能。 顾名思义,MISD 系统指的是多个 CPU 同时对同一个数据流进行不同的加工操作。

真正基于 MISD 的计算机系统并不存在,因为若干个 CPU 同时对一个数据进行不同的

运算没有现实意义。但是如果我们换一个思考角度,把这组 CPU 看成是一条流水线上

的各级工作站,每一级 CPU 都对输入的数据完成一个具体操作并产生一个中间结果,

作为输入传给下一级 CPU,这样就能大大提高某些应用的运行效率。在现代硬件的设计

中,这种技术的一种变体称作流水线或管线(pipeline),已得到普遍的应用。例如,奔

腾Ⅳ的芯片采用了 20 级的流水线技术,极大地提高了 CPU 的处理速度。值得一提的是,

奔腾Ⅳ的管线技术只借用了 MISD 的思想,实现指令的“乱序”执行(大致地说,具备

执行条件的数据不分先后都可以激活指令),而不是真正的 MISD 结构。 分布式系统的硬件结构属于最后一种分类,即 MIMD 系统。在这种结构下,多个

处理部件独立地执行各自的指令流对不同的数据流进行处理。这是一类最为复杂的硬件

结构,多处理器(multiple processor)系统和多计算机(multiple computer)系统都属于

这一类。在一般情况下,我们统称为多机系统。多机系统的目的是通过并发(concurrent)或并行(parallel)来实现最大的系统效能。这里,我们需要解释一下这两个术语的来历。

并发这个术语首先来自于单机系统,用以描述多个进程或线程分享 CPU 时间片,从而

最大限度利用 CPU 资源的设计思想。例如 UNIX 系统中的进程和 Posix 中的线程都是用

来实现单机内多道程序并发的概念。而并行这个术语则来自于 SIMD 类型的系统结构,

指的是多台 CPU 同时执行一条指令对不同的数据流进行操作。例如我们常说的“并行

Page 12: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·16·

机”就是指 SIMD 结构的计算机系统。虽然这两个术语没有国际标准定义,但计算机界

一般都接受上面给出的解释。那么,对分布式系统而言,哪个术语更为确切呢?我们认

为两者皆可。在众多的分布式系统教科书和参考文献中,这两个术语一直被混用,它们

的含义也被延伸:不仅多机同时运行,而且多道程序(进程)在同一个时间片被执行。

在后面的章节里,我们一般使用并发这个术语来描述单机系统中多进程(或多线程)的

概念,用并行来描述多机系统中的多道程序概念。在没有二义性的情况下,我们也可能

随意地使用这两个术语来刻画分布式系统的属性。 尽管 MIMD 是分布式系统硬件结构的基本特征,但我们可以通过处理器(或计算

机)之间不同的连接方式大致归纳为 3 种不同的系统结构:基于总线的多机系统,基于

交叉开关的多机系统以及基于网络的多机系统。下面我们对这 3 种分布式硬件结构作进

一步的讨论。

2.1.1 基于总线的多机系统

任何一本计算机原理的教科书都有对总线(bus)的定义:在一台计算机里,总线

是介于系统各个部件之间的交换数据的通道。如 PC 中的地址总线和数据总线就是介于

CPU,输入/输出设备以及存储器之间的通道。同理,我们这里的总线指的是连接所有处

理部件,使得它们能够访问数据或者彼此交换信息的硬件设施。 基于总线的多机系统一般是多处理器系统,而且大都采用同构处理器,也就是说,

连接在总线上的处理器要么同型同类,要么相互兼容。对存储器的享用方式是刻画这类

系统的另一个重要因素,处理器(P)可以拥有一组共享的存储器(M),也可以拥有只

能独自访问的局部存储器,见图 2.2。

M1 M2 Mm-1 Mm

Pn Pn-1P2 P1

Mn Mn-1 M2M1

Pn Pn-1 P2P1

… …

(a)共享存储器总线结构 (b)局部存储器总线结构

图 2.2 基于总线的多机系统

1. 共享存储器总线结构

通过总线来共享内存的系统一般处在同一个地址空间(address space)。这个地址

空间由多个存储器模块构成,也像处理器一样连接在总线上。一种简单的系统构造就

是把若干个 CPU 和存储器插件板都接插到一块高速主机板(motherboard)上,这也就

是人们常说的紧密耦合系统(tightly coupled system)。由于只存在一个数据传输总线,

多个处理器势必会产生对总线的竞争,我们必须有一个总线仲裁机构来调度这些访问

请求。此外,如果一台处理器更新了内存中某个地址的内容,而另一台处理器马上访

问这个地址,则它必须得到更新后的值。具备这种性质的内存称作为连贯一致性

Page 13: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·17·

(coherent)内存。 当系统内只有几个处理器时,对总线的竞争不会太大地影响到系统的效率,但随着

处理器个数的增长,总线的负载越来越高,系统的效率便会急剧下降。解决这个问题的

方法是在每个处理器中引入高速缓存(cache)。我们把最近访问的一组数据存放在里面,

并且期望它们被频繁访问。于是,所有对内存的访问都先经过这个高速缓存,如果所访

问的数据就在缓存中,我们就无需占用总线,直接把缓存里的数据传递给处理器。显而

易见,缓存越大,数据的命中率(hit rate)也就越高,当然系统价格也就越昂贵。我们

必须在命中率和价格之间做出权衡。引入高速缓存还会带来另一个问题:不同处理器对

同一个地址单元的读/写操作可能都在各自的缓存里进行,从而使得内存的连贯一致性问

题变的更加复杂。关于这一点,我们在后面的章节里会详加讨论。

2. 局部存储器总线结构

总线结构下的另一类系统是每个处理器各自携带只能自行访问的局部存储器。这

类系统当然不存在内存连贯一致性的问题,因为处理器各自管理自己“私有”的地址

空间。这里唯一要解决的问题是处理器之间如何交换信息,也就是如何通信的问题。

同样,我们需要一个总线仲裁机构来解决处理器对总线的竞争。总线仲裁机构可以是

集中式的,也可以是分布式的。集中式总线仲裁往往需要一个特殊的硬件或者一台专

职的处理器来分派对总线的占有权。分布式总线仲裁机制比较复杂,有基于令牌

(token)的方法,有基于选举(election)的方法,也有基于探测(probe)的方法。由

于总线是多个处理器之间的一个共享资源,稍后我们将有专门的章节讨论资源管理的

分布式算法。 总线结构的优点是性能高,结构简单,价格相对低廉;其缺点是可扩展性差(所容纳

的处理机个数取决于总线的带宽),容错能力差(总线本身就是系统的瓶颈,总线一坏,整

个系统瘫痪)。基于总线的多机系统一般用于高速分布式计算。

2.1.2 基于交叉开关的多机系统

为了克服总线结构的缺点(可扩展性差、容错能力差),我们可以采用基于交叉开

关的多机系统。顾名思义,交叉开关指的是系统各个部件“交叉”连接点上那个可以“开”

和“关”的硬件设施。这个设施一般都是用快速电路实现的。最简单的交叉开关系统是

纵横交叉开关(crossbar)结构,如图 2.3 所示。在这种结构里,N台处理器和N个存储

器模块纵横相连,一共有N2个交叉点,每一个交叉点代表一个电子开关。当一台处理器

需要访问某个特定内存时,它只要通过交叉开关暂时对外关闭那条线路。不难看出,这

种结构的优点是多台处理器可以同时访问内存,从而提高整个系统的效率。当然,多台

处理器同时访问同一个存储器模块是不允许的,在任何一个时刻,一个存储器模块只能

由一台处理器独享,其他的竞争者必须等待。 纵横交叉开关系统的缺点是需要O(N2)个交叉开关,当N增长时,系统的成本亦

急剧增长,因而对一个大型系统来说,这种结构显然不太适用。那么,我们是否能够减

少交叉开关的数量呢?图 2.4 给出一个变通的例子,称为多级交叉开关(multiple stage switch)结构。这个例子中含有三级开关,其中第一级和第三级各包含两个 2*5 的交叉

Page 14: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·18·

开关,而第二级由两个 2*2 的交叉开关组成。每个开关都能自动地把某端的输入切换到

某个输出,从而使得每个处理器都能访问到每一个存储器模块。

MN MNM2 M1

PN

PN-1

P2

P1

图 2.3 纵横交叉开关系统

图 2.4 多级交叉开关系统

Page 15: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·19·

这种构造的交叉开关系统有两个明显的优点。第一,大大减少了开关数量。如图 2.4所示,我们只需要 48 个开关就可以取代一个需要 100 个开关的纵横网络。第二,增加

了系统的可靠性。我们从任一台处理器出发,可以有两条不同的路径到达任一个存储器

模块。当然,有所得就必有所失,有好处就必然要付出代价。纵横交叉开关系统中的开

关设计很简单,一般只需要一个门电路就可以了;而多级交叉开关系统里的开关要复杂

得多,因为这种开关要具备一定的路由(routing)功能。此外,从处理器到存储器的访

问需要经过多级开关,在一定程度上增大了访问延迟。和基于总线的多机系统一样,基

于交叉开关的多机系统一般都是采用同构处理器的紧密耦合系统,而且其应用范围也以

分布式计算为主。

2.1.3 基于网络的多机系统

基于网络的多机系统是分布式系统硬件结构的主流,这类系统价格低廉,组织灵活,

结构多样,易于扩充,应用广泛。网络可以用来连接多处理器或者多计算机。连接多处

理器的系统类似于前面讨论过的基于总线和交叉开关的多处理器系统,可以实现同一个

地址空间的共享;而连接多计算机的系统大都自行管理局部内存空间,通过网络通信实

现计算机之间的数据交换,通常也叫做松散耦合系统(loosely coupled system)。现今的大

多数基于网络的多计算机系统都允许使用异构计算机,也就是说,对计算机的处理器类

型、内存容量以及输入/输出等没有特殊要求。与此同时,连接计算机的网络也呈现出多

样性,不同带宽、不同传输介质、不同结构的网络都可以使用或者联合在一起使用。由

于网络结构的多样性,用具体的实例很难描述这类系统的普遍特征。为了不失一般性,

我们着重讨论一下网络拓扑结构以及我们期望的网络性质。 网络的拓扑结构是一种抽象的图示方法。我们用图中的结点来代表网络中的计算

机,用图中的边来代表网络连接。为了方便讨论,我们先给出几个与本节内容有关的重

要定义: 1)网络规模:网络中结点个数,记作 N。 2)网络结点:网络中任意结点,记作 ni,1≤i≤N。 3)结点距离:两个结点(ni,nj)之间边的条数,记作 d(ni,nj)。 4)网络直径:网络中任意两个结点之间的最长距离,记作 D。

D=MAX(d(ni,nj)),∀ni,nj∈ 网络 5)结点度:通向一个结点的边的条数,记作degree(ni)。 根据这些定义,我们在下面给出所期望的 5 个网络性质。我们无法全部用数学的方

式来刻画这些性质,有些涉及具体实现的性质只能用自然语言描述。 性质 1 当网络规模任意增长时,网络直径增长缓慢,即

lim D/N=0 N→∞

性质 2 存在一个与网络规模无关的常数 K,使得 K≥degree(ni),∀ni ∈ 网络

性质 3 网络的路径算法(routing algorithm)易于实现而且与网络规模增长无关。 性质 4 当网络中某些结点或者某些边出现故障时,网络的连通性不受致命的损害。

Page 16: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·20·

性质 5 网络负载在所有结点和边上均匀分布。

星形

环形

二叉树形

全连通形

正则形

任意形

图 2.5 典型的网络拓扑结构

我们期望一个基于网络的多机系统具备上面给出的 5 条网络性质,但在实践中,我

们很难找到一种满足所有这些性质的网络拓扑结构。一般而言,不同的网络拓扑结构对

某些性质表现不错,而对另一些性质却表现很差。我们在图 2.5 中给出几个典型的网络

拓扑结构,并且在表 2.1 中针对 5 个所期望的网络性质对它们作出简单的评价。

表 2.1 典型的网络拓扑结构及性质评价

星 形 环 形 二叉树形 全连通形 正 则 形 任 意 形

lim D/N=0

N→∞ 是(D=2) 否(D=N—1) 是(D=2log N) 是(D=1) 是(D= n ) 不详

K≥degree(ni) 否 是(K=2) 是(K=3) 否 是(K=4) 不详

路径算法 易 易 易 易 易 不易

连通性 差 差 较差 好 较好 不详

负载均匀 否 是 否 是 是 不详

N

当设计一个基于网络的分布式系统时,我们首先要决定的是选取什么样的网络拓扑

结构。影响这个决定的主要因素有四个:性能、价格、可扩展性以及具体的应用。另外,

针对不同的情况,一个系统有可能采用若干个网络拓扑结构的组合。比如说,假定一个

提供远程服务的分布式系统拥有 5 台服务器,我们可以采用星形结构作为客户和服务器

之间的网络结构,而在 5 台服务器之间采用全连通结构,藉以增加系统的可靠性和容错

能力。

2.2 软 件 概 念

如果我们只有一组被连接到一起的计算机,尚不能称其为分布式系统。分布式系统

Page 17: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·21·

的另一个重要组成部分是分布式软件。硬件是躯壳,软件是灵魂,只有当硬件和软件结

合到一起时,才形成一个具有活力的系统。我们都知道,软件这个术语涉及广泛,它囊

括了从系统到应用所有具备实用功能的那些程序和数据。即便局限在分布式软件这个范

畴里,我们也可以列举出一连串的软件名称,如分布式语言、分布式数据库、分布式算

法、分布式文档、分布式信息检索、分布式多媒体、分布式电子商务、分布式事务处理

等,那么,我们所关心的分布式软件是哪一类呢?显而易见,我们感兴趣的是分布式系

统软件,也就是说,用以控制、管理、协调一组网络相连的计算机,实现资源共享,使

之在用户面前呈现为一个透明整体的那类软件。 在系统软件中,操作系统扮演着极为重要的角色。如前所述,分布式硬件结构可以

大致分为两类:紧密耦合系统和松散耦合系统。不言而喻,操作系统必须与硬件结构相

匹配:紧密耦合结构下的操作系统试图把所管辖的资源一体化,而松散耦合结构下的操

作系统则通过提供服务的方式达到资源共享。我们一般把前者称作分布式操作系统,而

把后者称为网络操作系统。此外,在网络操作系统的框架下,我们可以添加一层软件来

改进系统的透明性,这样一类软件被称为中间件(middleware)系统。在下面的小节里,

我们将逐一讨论这 3 种模型。

2.2.1 分布式操作系统

分布式操作系统通常用来管理多处理器或者同构多处理机。就像传统的单机操作系

统一样,其主要目的是隐藏硬件细节,管理硬件资源,提供系统接口,使得并发进程能

够共享系统资源。在一个操作系统管理下,可能有多个并发的应用,可是在任何一个应

用程序的眼光里,整个系统就好像属于它自己。从这个角度看,覆盖在硬件之上的操作

系统实现了一台虚机器(virtual machine),图 2.6 展示了传统单机操作系统下的虚机器。

分布式操作系统继承了这种虚机器的概念。然而,它所面临的硬件结构更为复杂,更加

多样化。首先,它要管理多个处理器,要通过对这些处理器的合理调度而达到高性能的

计算。其次,它要管理多个甚至多级的存储器,要通过对存储器的管理而形成一个共享

的地址空间。由于存在有不同的分布式硬件结构,分布式操作系统也会面临不同的数据

存取机制。例如,基于总线和交叉开关的共享内存已经由硬件对并发访问进行了保护,

而基于网络的共享内存就需要由操作系统来进行保护。又如,在多处理器环境里,并发

进程之间的数据交换一般通过共享存储器完成,而在多计算机环境里,并发进程之间的

数据交换往往都通过网络通信完成。总之,一个分布式操作系统就要隐藏这些差异,提

供给用户一台如图 2.7 那样的虚机器。

单机操作系统

计算机硬件

进程调度 设备管理 存储管理 文件管理

应用程序

图 2.6 单机操作系统下的虚机器

Page 18: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·22·

分布式操作系统

计算机硬件……

进程调度 设备管理 存储管理 文件管理

分布式应用程序

网络

图 2.7 分布式操作系统下的虚机器

在一台虚机器中实现资源共享的一个重要原则是要保护每一个应用对资源的安全

使用。有的资源可以被多个应用同时共享,如“只读”存储器;有的资源可以被多个应

用以互斥的方式共享,如某个可读可写的文件;也有的资源在一段期限内根本不允许共

享,如进程的地址空间。毫无疑问,如果允许互不相干的并发进程随意闯入他人的地址

空间,整个系统必然会乱套。 为了实现上述原则,操作系统必须完全掌握对资源的控制权和分配权。也就是说,

所有应用都要通过操作系统所提供的原语(primitive)和协议(protocol)来共享资源。

例如,为了防止不同的进程同时存取某个共享内存里的数据,它们必须使用系统提供的

同步原语才能保证数据的安全性和一致性。在传统的单机操作系统里,实现这种同步的

方法之一是信号灯(semaphore)。信号灯可以是二元信号灯,也可以是多元信号灯。信

号灯本身只不过是一个简单的数据结构(一个整型数加上一个队列),但我们把一个信

号灯用来控制一个资源时,我们就可以通过施加在该信号灯上的两个原语(P,V 操作)

来达到保护该资源的目的。关于这一点,操作系统课程都有详尽的介绍,我们就不再展

开讨论了。值得指出的是,在共享内存的前提下,分布式操作系统可以继承这些传统的

同步机制实现对共享资源的保护。 如果分布式操作系统所面临的硬件是基于网络的多计算机结构,情况就变得复杂得

多。主要原因是我们没有一个可以共享的内存,因而无法继承传统的以内存为媒介的同

步机制(如信号灯)。在这种硬件结构下,计算机之间交换数据或者协调同步的唯一手

段是消息传送(message passing)。一般而言,这类系统中的每一台计算机都拥有自己的

系统内核(kernel),用来管理该机器的局部资源。同时这个内核还提供一个特殊的通信

模块来实现计算机之间的消息传送。抽象地说,消息传送是把一组共享数据从一台计算

机的地址空间复制到另一台计算机的地址空间里。在实现上,这个“复制”工作是由网

络上的数据通信完成的。我们把消息传送的语义、类型以及实现方法留待下一章讨论。 如果仅仅依赖消息传送来共享资源,这个分布式操作系统所形成的虚机器就过于低

级。大量的实践表明,设计一个基于消息传送的分布式程序要比设计一个同样功能的基

于共享内存的分布式程序难得多。一个简单的解释就可以说明这一点:共享内存结构下

的同步机制要简单的多、丰富的多、容易使用的多。例如,在共享内存的系统里,一个

信号灯就可以管理一个互斥共享的资源;那么,在只有消息传送的系统里,我们怎样才

能达到相同的目的呢?办法无非是两种:其一,开发新的基于消息传送的资源管理服务;

其二,在多计算机系统上模拟共享存储器。我们将有专门的章节讨论第一类方法,这里

Page 19: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·23·

我们简单地讨论一下如何模拟共享存储器。 在多计算机系统的框架下模拟共享存储器的基本模型是分布式共享内存(DSM,

distributed shared memory)。消息传送模型和 DSM 模型的本质区别是后者把所有的局部

内存合并成一个逻辑整体,为应用程序提供一个全局的虚拟地址空间。在一个 DSM 系

统中,这个虚拟地址空间被划分页面(page),而且页面被分布存放在不同的局部存储

器里。当一个进程所访问的页面不在局部内存时,操作系统便会自动捕捉这种“缺页”

中断,调入所需的页面,然后重新启动被中断的进程。要想实现这个思想,DSM 必须

维护一套目录系统,用以存放或检索系统中页面的位置和状态。除此之外,我们还要解

决两个问题:第一,如何分布共享页面?第二,对一个给定的页面,最多允许多少进程

同时进行读写? 解决第一个问题的方法有两种:复制和迁移。复制技术要维护一个页面的多个拷贝,

当某个进程需要时就分配给一个拷贝。迁移技术保持页面的唯一性,当某个进程需要时

就把这个页面移到该进程所处的局部内存中。显然,这两种技术都有缺陷,例如,复制

技术要解决数据的一致性问题,而迁移技术要解决迁移策略和迁移开销的问题。 管理共享数据的第二个问题是多个进程对数据的并发读写问题。允许多个进程同时

“读写”势必破坏数据的一致性,我们必须有一个仲裁机构来协调这些并发操作。最简

单的方法是“单读/单写”,即任何时候只允许一个进程独享数据。可惜这样就违背了共

享的宗旨。进一步的方法是“多读/单写”,即允许多个进程读数据,而只允许一个进程

执行写操作。那么,如果多个读进程各自拥有共享数据的只读拷贝,而写进程修改这个

共享数据的话,这些读进程的拷贝就不再准确了。为了解决这个问题,大多数 DSM 系

统都提供一种失效(invalidation)机制,用来通知那些拥有只读拷贝的进程:“当前拷贝

失效,需要重新复制”。最为复杂的数据共享是允许“多读/多写”。设想一下,如果一个

项目设计组里的每一个成员都把一份共享文件的拷贝带回家修修改改,那么你怎样才能

把这些独立的修改合成到一起呢?这实际上也是允许“多读/多写”的 DSM 所面临的问

题。解决方法是把所有“读/写”操作用一种时序规范加以控制,以保证数据的一致性。

这个问题还会在稍后的章节中进一步展开讨论。

2.2.2 网络操作系统

与分布式操作系统不同,网络操作系统对其基础设施的要求不甚严格,只需要有

一组连接在某种网络上的计算机,这些计算机可以装有异构处理器,甚至装有不同的

单机操作系统。但光凭这一点并不能刻画出分布式操作系统和网络操作系统之间的本

质区别,严格地说,这两者之间的本质区别在于系统呈现在用户面前的透明程度:分

布式操作系统为用户提供一台虚机器,而网络操作系统为用户提供一组可以互相通信

的虚机器。 图 2.8 给出在网络操作系统下的虚机器概念。可以这样说,网络操作系统是传统操

作系统的扩充,为用户提供各种交换信息和资源共享的服务。显然,这些服务都依赖一

种最基本的服务设施:传送(transport)服务。传送服务是介于网络应用和物理网络之

间的接口,实现点对点(point-to-point)的通信协议。大多数网络操作系统都提供一种

高级应用程序设计接口(API,application programming interface),诸如套接字(socket)

Page 20: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·24·

和远程过程调用(RPC,remote procedure call)。借助于传送服务,网络操作系统还会提

供各种各样网络应用,典型的网络应用包括远程登录、远程文件传送、信息传递、远程

执行等。

计算机硬件……

网络

操作

系统

网络应用程序

网络

网络

操作

系统

网络

操作

系统

网络

操作

系统

图 2.8 网络操作系统下的虚机器

1)远程登录(remote login)可以使一个用户通过网络操作系统进入一台远程计算

机,于是这个用户便能够享用那台计算机所提供的服务与资源。这类应用的实现方法其

实很简单,我们只要把键盘输入转换成信息包传送给远程机器,并把远程计算机发回的

信息包转换成屏幕显示就可以了。这种服务是在用户面前展现出一个虚终端(或者一个

虚远程视窗)。我们常见的 telnet 和 rlogin 就属于这类网络应用,而目前流行的 ssh 协议

对传送的数据进行加密,使得远程登录更为安全可靠。 2)远程文件传送(remote file transfer)可以使用户在不同地点交换文件。文件不仅

只含有数据,同时还隐含着文件自身的结构和属性。一个文件传送协议必须遵守远程文

件系统和局部文件系统的使用规则,同时提供一组交互命令以支持用户的各种访问需

求。在具体实现上,要注意数据格式、数据流控制、访问认证以及安全性。Unix 提供的

ftp 和 rcp 都属于这类网络应用。 3)信息传递这一类网络应用的典型是众所周知的电子信件系统。与远程文件传送

不同,电子信件一般不考虑数据格式和属性,只要把用户的信件打入传送包,原原本本

地送达目的地就可以了。在设计时的主要考虑因素是如何管理和传送信件以及如何为用

户提供一个友好界面。此外,设计者也必须遵循电子信件系统的标准化,诸如 CCITT的 X.400 和美国国防部所颁布的简单信件传送协议(SMTP,simple mail transfer protocol)。

4)远程执行指的是用户向系统发出信息,请求在某个远程计算机上执行一个程序。

这个解释看上去不很明确,我们需要进一步弄清用户发出什么样的“信息”以及远程计算

机执行什么样的“程序”。显然,最简单的信息是一条命令,远程计算机直接调用该命

令的执行程序。例如,我们前面提到的 ssh 就可以做到这一点。用户只要发出“ssh 远

程计算机命令”,一旦用户口令得到确认后,所给定的命令就会在指定的远程计算机上

被执行。那么,如果用户给出的信息本身就是一段程序,而且用户希望在某个远程计算

机执行这段程序,我们该怎么办?我们知道,所谓可执行程序一般都与机器指令系统相

Page 21: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·25·

关,因此我们无法随意地让远程计算机执行一个它无法理解的程序。于是,由用户信息

所携带的程序大都是基于解释系统的脚本(script)文件或者是与机器无关的中间语言程

序。例如,现代的电子信件系统支持多媒体信件,并能够自动地根据信件类型(MIME,multipurpose internet mail extensions)启动相关的解释程序。虽然一封 MIME 信件并非严

格意义上的程序,但它确实起到引发一个远程程序的目的。远程执行给用户带来方便,

同时也带来危险。如今的大多数计算机“病毒”都是钻了远程执行所造成的安全漏洞。 网络操作系统的主要优点是简单灵活,可扩展性好。由于网络操作系统管理下的计

算机独立性强,在网络上增删计算机一般不会影响到网络应用。而其主要缺点是透明性

差,用户必须了解网络的构成乃至计算机的名字,才能使用系统提供的各种服务。此外,

用户尚需管理自己的数据资源,以保证数据的一致性。例如,如果一个用户在若干台计

算机上存放有同一个文件的拷贝,则该用户必须时常地更新这些拷贝才能保证这些拷贝

的相对一致性。目前人们使用的大多数操作系统,如 Windows,Linux 等都属于网络操

作系统的范畴。

2.2.3 中间件系统

对照一下我们在第一章里给出的分布式系统定义,可以发现无论分布式操作系统或

者网络操作系统都存在着不足之处。分布式操作系统有些“事无巨细,面面俱到”,因

而忽略了网络中计算机的独立性和自主性。反之,网络操作系统有些“各自为政,为所

欲为”,因而影响了系统的整体性和透明性。那么,我们是否有可能扬长避短,一方面

利用网络操作系统的开放性和可扩展性的优点,另一方面引入分布式操作系统透明性好

的优点,为用户构造一个又方便又灵活的系统呢?回答是肯定的,但我们同时需要指出,

没有任何事情是十全十美的,也没有任何事情是不花代价的。这里我们所作的折中和所

花的代价就是在网络操作系统之上再覆盖一层软件,称作中间件,藉以改进网络操作系

统的透明性。实际上,大多数现代分布式系统都是基于这样一种思想构造的。我们在

图 2.9 中给出在中间件覆盖下整个系统所构成的虚机器。

计算机硬件……

网络

操作

系统

中间件分布式服务

网络

网络

操作

系统

网络

操作

系统

网络

操作

系统

分布式应用程序

图 2.9 中间件系统下的虚机器

中间件的一个重要目的是隐藏网络操作系统之下的异构性。所采用的方法一般是把

各种各样的服务统一起来,给用户提供一个由中间件形成的分布式服务界面。中间件并

Page 22: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·26·

不干预网络操作系统对计算机局部资源的管理,它只是利用这些局部管理和通信机制来

实现具备更高透明程度的系统服务。有趣的是,中间件并非来自于学术界,也不是来自

如何增强系统透明性的科研成果,它的出现与各种各样的商业化网络操作系统有着密切

的关联。 随着网络操作系统的广泛应用,人们发现很难把各种各样的网络应用集成为一个统

一界面下的系统。于是,开发这些网络操作系统的厂家便开始在他们的系统之上添加一

层高级的软件,使之能够兼容于其他系统并且隐蔽自己系统的内部细节。当然,如果厂

家们依旧独立作战,还是无法克服不同网络操作系统各自为政的弊端,于是各种各样的

标准化组织便应运而生,目的是为各种类型的中间件建立一套标准化规范。可惜的是,

目前这样的组织意见不一,制定的标准也互不兼容。随着时间的推移,中间件的标准化

问题必将得到解决。 中间件是用来提供高级服务的。那么,哪些项目属于中间件的服务范畴呢?首先,

为了满足访问透明性,我们必须有一套高级通信设施,它不仅隐蔽低级消息传送协议的

细节,也要为用户提供一套高级的应用程序设计界面(API)。例如,远程过程调用(RPC)就是高级通信设施的一个典型。另外,建立在网络操作系统之上的分布式文件系统也是

用来提高访问透明性的中间件。要想使得不同网络操作系统提交的服务得到中间件的统

一管理,一个重要的服务项目就是命名(naming)。名不正则言不顺。没有统一的命名

管理,则我们无法与网络中的计算机沟通,也无法获得它们的服务。命名服务类如电话

公司的查号台,提供各种登录、查询业务。典型的命名服务就是 WWW 所提供的对网

页地址(URL)的自动查询服务。 近年来,中间件的一个变体称为群件(groupware),也得到广泛的重视和应用。群

件是建立在网络操作系统之上的面向应用的中间件。它不像传统的中间件那样只提供分

布式服务,而是以功能为划分标准来支持不同业务群体的网络应用软件。例如,一个网

络会务群件可以通过查看与会人员的时间表,做出会议安排。届时,每个与会人员只要

坐在自己的计算机旁,这个群件就会以多媒体的方式显示出其他与会者,展示各种会议

工作文件等。 综上所述,中间件是现代分布式系统在网络操作系统上覆盖的一层软件,它不光是

在应用层和网络操作系统层之间起一个上传下达的作用,重要的是它把底层服务综合起

来,以一种更透明、更高级的形式为应用提供服务。由于中间件的存在,分布式应用不

再依赖底层的网络操作系统,而只要使用中间件提供的高级服务就可以了。但是,我们

去掉了对底层网络操作系统的依赖性,却引入了对高层中间件的依赖性。这种高层依赖

性往往又制约了分布式应用。这种制约力首先来自于中间件的开放程度。理论上,一个

真正开放的分布式系统必须提供一套完备的服务界面。所谓完备指的是系统为应用层所

提供的服务要包罗万象,应有尽有。如果所提供的服务不完备,则不同的系统和应用开

发厂家就被迫推出自己的服务接口。这样,我们就会面临一种尴尬的局面,不同厂家开

发的中间件表面上遵循同一个标准,但它们私下里都有自己的地下通道,于是,这些厂

家开发的应用也就无法兼容,或者使用起来故障频生。除了加强标准化的实施之外,目

前人们还没有更好的方法解决这个问题,因为理论上的完备性过于完美,对实践者来说

可望不可及。

Page 23: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·27·

2.3 系统平台模型

在前一节的讨论中,我们的重点放在分布式系统软件的虚机器层面,也就是着眼在

各种各样的操作系统上。那么,对大量的分布式应用而言,我们应该使用什么样的计算

模型呢?也就是说,对用户而言,我们为他们提供一个什么样的系统平台呢?实践证明,

把使用者看成客户(client),把应用的具体实现者看成服务器(server),可以帮助人们

容易理解分布式系统,也便于人们管理一个复杂的分布式系统。其实,客户/服务器模型

并非起源于分布式系统。20 世纪 80 年代末,美国麻省理工大学(MIT)开发的网络视

窗系统 X Windows 就采用了客户/服务器模型。一个 X 系统由两部分组成:一个 X 服务

器,一个或多个 X 客户。X 服务器控制一个工作平台的键盘、鼠标器输入和以视窗为界

面的显示输出,而 X 客户只能通过与服务器的通信来实现对这些资源的管理。X 系统里

的客户/服务器可以安装在一台工作平台里,也可以分布在网络上。当然,这种早期的客

户/服务器思想只是对虚终端/主机概念的一种抽象。随着计算机网络和分布式系统的发

展,客户/服务器模型得到深入的研究。90 年代以后,客户/服务器技术几乎成为分布式

应用的主流平台模型,并且在工商企业、金融银行等领域得到广泛应用。 然而,随着计算机网络应用的日益普及,人们发现基于客户/服务器模型的系统平台

呈现出不少局限性。首先,它的网络范围较狭窄,拘泥于企业内部,难以突破企业间的

保护边界,因此对电子商务一类的应用有所制约。另外,由于使用人员和网络管理人员

的计算机素质等原因使得应用程序升级和维护十分困难且开销很大。一般而言,每当对

应用程序作一个小小的改动,就必须修改客户端的软件并对客户实施培训,如果整个系

统拥有成千上万的客户,其难度可想而知。从应用设计者的角度来看,客户/服务器模型

很难支持因特网,因此孤立了不同的逻辑组件,使得不同系统平台下的用户很难共享数

据与服务。 为了充分利用因特网自由、开放的特征,为了使计算机应用尤其是电子商务的市场

范围扩展到千家万户,基于浏览器/服务器(browser/server)的分布式系统平台模型浮出

水面,使得网络应用呈现出全球化、个性化的趋势。目前,许多提供电子商务的企业都

采用这种模型,如股票市场、拍卖市场等,使用户可以方便地在常用的浏览器上进行各

种交易。从技术发展走势来看,浏览器/服务器模型以及与其相关的 Web 服务系统正在

逐步取代简单的客户/服务器模型。但我们也看到,在今后相当长的一段时间里,网络应

用可能会采用两者俱存的混合计算模型,以客户/服务器为主的系统平台倾向局域网和专

业化,而以浏览器/服务器为主的系统平台倾向因特网和普及化。在本节里,我们将对这

两种模型进行深入的讨论。

2.3.1 客户/服务器模型

抽象地说,任何一个计算机应用都可以归纳为下面 3 个基本层面的逻辑: 1)表示逻辑:用户如何与应用交往,交往时会出现什么? 2)功能逻辑:应用提供什么功能以及如何实现这些功能? 3)数据逻辑:如何管理、更新、保护数据信息?

Page 24: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·28·

在早期的计算机系统中,客户通过终端向主机(服务器)发出服务请求,客户终端

只具备键盘(鼠标器)输入和显示输出的简单功能,故而 3 个逻辑层面的功能实现都在

主机中进行,其系统结构如图 2.10 所示。

数据逻辑

功能逻辑

表示逻辑

服务器

键盘输入

显示输出

客户

图 2.10 终端/主机模型

以网络应用为目的客户/服务器模型则扩展了上面的概念。由于客户和服务器双方都

是计算机,为了减轻服务器一端的负担,我们把一部分任务移植到客户所处的计算机中,

见图 2.11。

表示逻辑 数据逻辑

功能逻辑

服务器

请求

回应

功能逻辑

客户

图 2.11 客户/服务器模型

在这种模型下,客户软件直接管理用户接口,担负着用户与应用的对话功能。为了

使用户能直观地操作,表示逻辑一般都用图形用户接口(GUI,graphic user interface)实现。当改变表示逻辑时,我们只需要改写用户界面以及数据检查程序,而不涉及或影

响其他层面的任务。值得指出的是,我们这里所谓的数据检查只限于数据的格式和值的

范围,而与数据本身在其他层面的处理逻辑无关。 功能逻辑刻画应用本身,也就是说,我们要提供哪些服务以及如何把这些服务和相

关的算法编写成程序。功能逻辑可以完全由服务器提供,客户一端只担负表示逻辑的实

现。然而,为了进一步缓解服务器一端的负载,有的系统也把一部分前期功能逻辑实现

在客户一端。例如,用户的输入数据往往需要经过一定的类型检查和转换才能被处理,

我们可以把这个工作移植到客户一端的功能逻辑软件中。 数据逻辑位于整个系统的最底层。我们不可能把数据逻辑的实现移植到用户那里,

而必须由服务器来管理。数据逻辑一般是由数据库管理系统(DBMS)实现的。至于我

们是否把数据库安装在同一台服务器上还是采用多台乃至多级服务器,将要在后面的章

节中作进一步讨论。 简单地说,客户请求服务,服务器提供服务。在一个最基本的客户/服务器系统里,

所谓服务器可以是一个进程,提供一些特殊服务,如文件系统服务或数据库服务;而所

Page 25: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·29·

谓客户也是一个进程,向服务器发送信息,请求某个服务并等待服务的结果。简言之,

这些步骤可以归纳为请求-回应(request-reply)这样的一种交互过程,如图 2.12 所示。

服务请求

服务回应 执行服务等待回应

客户 服务器

图 2.12 客户/服务器交互过程

客户与服务器之间的交互媒介是消息传送。如果我们处于一个比较可靠的局域网

里,一个简单的无连接(connectionless)通信协议就可以胜任了。这里,客户是一个主

动的进程,一旦需要某种服务,它只要把自己所需的服务标识打入信息包,加上一些必

须的初始输入数据传送给服务器。服务器则是一个被动的进程,它总是等待在那里,一

旦服务请求到来,便根据不同的服务类型和策略启动某个程序,当完成服务后,把服务

结果打成信息包回传给客户。 如果通信是可靠的,也就是说,信息包不会丢失也不会污染,则上述交互过程简捷

高效。那么,如果通信的可靠性得不到保证呢?也许有人会说,我们把信息包重发几遍

不就可以了吗?可惜,问题并非如此简单。试想,如果客户在等待了很长时间后仍未得

到回应,那么作为客户,你将如何解释这种现象呢?不言而喻,客户面临着两种可能性:

第一,前一个请求丢失了,服务根本没有施行;第二,服务器已经完成对前一个请求的

处理,但回应信息包丢失了。如果采用重发请求的策略,我们可以解决第一个问题,但

却给第二个问题带来了隐患。举一个具体的例子,假设我们的服务器提供公司的账务管

理服务。一个会计客户向服务器发出请求:“转账 10 万元到某公司”,并且期望得到“转

账完成”的回应。于是,当第二种情况发生,而客户软件重发请求的话,这个“转账”

请求就可能被处理两次或多次,公司便会由于系统的缺陷而造成无法估计的经济损失。 为了解决上述问题,许多基于客户 / 服务器模型的系统采用面向连接

(connection-oriented)的通信协议。虽然面向连接的通信协议要比无连接通信协议在实

现上效率较低,但这种协议可以保证网络通信的可靠性。例如,几乎所有的网络应用都

基于可靠的 TCP/IP 通信协议。在这种协议中,整个交互过程都处在一种“连接”的状

态下,客户和服务器之间要通过若干个回合的信息传递,彼此确认对方信息的完整性与

可靠性。 大多数的客户/服务器系统都是采用中间件概念实现的。无论客户如何向服务器发送

请求,无论客户访问哪一个数据库,都有某种形式的中间件在帮助客户沟通从用户界面

到数据处理的通道,同时这些中间件还起着增强透明性的功能,例如隐蔽通信协议、隐

藏数据库查询语言以及转换不同硬件系统结构下的数据格式等。中间件就像是一种透明

胶,把客户和服务器有机地“粘贴”在一起。

Page 26: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·30·

2.3.2 浏览器/服务器模型

浏览器/服务器模型是一种以 Web 技术为基础的新型系统平台。这种模型把传统的

客户/服务器模型中的服务器部分分解为 Web 服务器和数据服务器,从而构成一个三级

结构的客户服务器体系,如图 2.13 所示。

表示逻辑 数据逻辑

功能逻辑

数据库

服务器

请求

回应

功能逻辑

客户

浏览器

功能逻辑

Web

服务器

数据逻辑

回应

请求

图 2.13 客户/服务器交互过程

模型中第一级是用户与整个系统的接口,而这个接口被精简成一个通用的 WWW 浏

览器。它不仅将服务器的服务项目转换成图文并茂的网页,而且还提供一定的交互功能,

使得用户能够与服务器对话。系统中的第二级,即 Web 服务器,响应来自用户的对话。

如果用户的请求能够得到满足,则 Web 服务器动态生成一系列网页代码,同时嵌入处

理的结果,返回给用户的浏览器;如果用户的请求涉及到进一步的数据服务,Web 服务

器便要代表这个用户,向第三级的服务器发出请求,而第三级服务器一般用来提供数据

库管理服务。 浏览器/服务器模型最大的优点是简化了系统的开发与维护。客户机上无需安装特殊

的“客户”程序,只要一个通用的浏览器。这样不仅节省用户的存储空间(内存、硬盘),

而且缩短了系统的安装调试周期。每个用户可以在自己的权限范围内调用 Web 服务器

的各种服务。对系统维护者来说,Web 服务的升级换代不会影响到用户一端,既不需要

改变用户程序,也不需要对用户培训。其次,这种模型对用户更加友好。在传统的客户

/服务器模型里,不同厂家开发的客户程序都有自己的风格和规范,使用者往往要经过专

门培训才能胜任。而浏览器的使用方式已基本家喻户晓,即便对没有任何计算机经验的

人来说,只需稍加指点,就会进行网上购物或者网上拍卖。 这种基于 Web 服务的网络应用模型要求系统设计者提供一种全新的平台结构来进

行程序设计,其中心思想是推出一种“一统天下”的通信机制,使得不同语言、不同操

作系统下的程序能够自由交互。当然,这种想法并不是什么新思维,人们一直在朝这个

方向上努力着。例如,前面提到的远程过程调用(RPC),以及 DCOM 和 CORBA 等都

可以实现不同计算机之间进程级的交互。但这些机制都有一个致命的弱点,它们需要进

行交互的系统之间具备对等的实体,如 DCOM 客户只能和 DCOM 的服务器进行交互。

这样来看,这个“大一统”的交互机制就有了显著的优点:交互的双方完全异构,不仅

操作系统可以异构,进程的语言也可以异构。 客户与服务器交互的关键有两点:信息包标准和通信协议。基于 Web 的流行通

信协议是超文本传送协议(HTTP:hypertext transfer protocol),信息包标准基于可扩

Page 27: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·31·

展标记语言(XML,extensible markup language)。这两者都是举世公认的标准,独

立于任何硬件结构和软件系统,因此采用这两者作为交互的标准自然无可非议。在

这种机制里,用户端只要把请求和数据以 XML 的格式打包,通过 HTTP 协议传送到

Web 服务器,服务器就能够理解用户的需求,完成用户所需的服务。目前有许多厂

家都在试图为 Web 应用提供这种交互机制。我们将在最后一章里讨论有关 Web 服务

的发展趋向。 虽然浏览器/服务器模型是目前网络应用领域的热点,但这个模型仍然存在着一些不

容忽视的问题。首当其冲的问题是网络应用的安全性。传统的客户/服务器模型在安全性

方面占有优势,因为这类系统一般处于局域网内,网络自身安全性好,网内服务器可以

信任,再加上采用特殊的安全通信协议,安全性可以得到基本保证。而对浏览器/服务器

模型来说,情况则完全不一样。它以因特网为基础,采用开放性的通信协议,网络本身

对安全性没有任何保障,任何人都可以在网上截取用户信息,而且网上服务器五花八门,

甚至存在有恶意的服务器,专门盗窃用户的个人信息。所有这些,不但为系统开发者带

来困难,也影响到用户对这类网络应用的信任程度。再者,浏览器虽然易于使用,但其

交互能力较差。在客户/服务器系统中,客户程序都会提供一套完整的应用程序,在出错

提示、在线帮助、故障处理方面功能比较完善。在这一方面,目前通用的浏览器尚无法

比拟。在使用效率方面,客户/服务器系统要比浏览器/服务器系统高得多。道理很简单,

前者采用两级结构体系,而后者需要三级结构体系,这样便增加了对用户服务的延迟和

网络上信息负载。 面对客户/服务器系统平台的成熟性和安全性以及浏览器/服务器系统平台的灵

活性和广泛性,人们似乎难以取舍。作为一个系统设计者,一定要根据网络应用的

特点权衡这两种系统模型的利弊,在必要的情况下,可以将两种模型混合使用或者

交叉使用。

2.3.3 模型界面与多级(MULTI-TIERED)结构

无论是采用客户/服务器模型还是采用浏览器/服务器模型,我们都会遇到一个同样

的问题:客户和服务器之间的一条明显界线应该怎样划分?回答也许令人感到惊讶,我

们常常找不到这样一条界线。例如,在一个分布式数据库系统里,用户向数据库服务器

发出请求,在这个意义上,用户是客户。而数据库服务器又要向不同的文件服务器转发

用户请求,期望得到特定的数据访问,在这个意义上,数据库服务器也是客户。在后面

的讨论中,如果没有必要,我们不再区分客户/服务器和浏览器/服务器模型,一概统称

为客户/服务器,因为这两种模型在抽象概念上是一样的。 然而,由于大多数客户/服务器系统都是用来实现某个网络应用,我们可以采用前文

里描述的 3 个基本的逻辑层面来界定客户和服务器。这种 3 层结构把一个系统平台划分

成表示层、功能层和数据层。这种划分方法的主要优点是: 1)适合于灵活的硬件系统配置; 2)使得系统便于维护; 3)有利于系统升级和改造; 4)可对不同层面的子系统实施不同的安全控制。

Page 28: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·32·

如果我们只用两级物理计算机来实现这些逻辑层次,则称之为二级结构(two-tiered architecture),可以有 5 种可能的逻辑分布方法,见图 2.14。

数据层

表示层

功能层

表示层

功能层 功能层 功能层

数据层 数据层

功能层

数据层 数据层

功能层

表示层 表示层 表示层 表示层

数据层

服务器

客户 图 2.14 二级结构下逻辑分布

尽管在二级结构下我们有 5 种可能的逻辑分布形式,但在实践中,有些形式不太

常用,或者仅局限在某些特定环境中。从左到右来看,第一类逻辑分布对客户端系统

有极强的要求,除非客户系统自身是一个分布式数据库系统的组成部分,否则我们难

以想像任何系统允许客户端参与管理数据逻辑,一旦客户系统出错,可能使整个系统

陷于瘫痪。第二类逻辑分布需要专业化的客户系统,服务器只完成对数据的管理,而

施加在数据上的功能由客户系统实现。第三类逻辑分布在设计时一定要非常小心,因

为我们需要给出一个把功能逻辑一分为二的界面。这种分布的优点在于客户端可以完

成一部分功能逻辑,减轻服务器端的负担。但客户与服务器之间的交互变成功能层内

部的交互,搞得不好这个界面会使得系统难以更新和维护。最后两类逻辑分布接近于

浏览器/服务器模型,客户端看上去很像一个图像平台,所有的功能和对数据的管理都

由服务器实现,甚至这个图像平台的某些表示逻辑都要由服务器提供,譬如 Web 服务

器传送给客户的网页。 如果在一个客户数量不很多的分布式环境里(譬如说几十个客户),采用二级结构

的客户/服务器系统就足以胜任了。但是,当客户数量扩充时,系统性能就会显著下降。

这是因为二级结构下的服务器往往需要与客户保持“连接”,因而限制了系统的负荷量。

另外,二级结构的灵活性和扩展性都很差,同时也限制了把某个服务器也当成其他服务

器的客户的可能性。 为了克服上述缺陷,人们引入了三级结构(three-tiered architecture)乃至多级结构

(multi-tiered architecture)。以三级结构为例,我们可以把三个逻辑层次一对一地分布在

每一级计算机里,即客户机实现表示逻辑,中间服务器实现功能逻辑,而最后一级服务

器实现数据逻辑,见图 2.15。当然,这里我们只是给出一种逻辑界面清晰的三级结构例

子,而具体的实现却要根据应用而定。

Page 29: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第二章 分布式系统概念和结构 ·33·

表示层 数据层

服务器 客户

服务器

功能层

图 2.15 三级结构下逻辑分布

一般来说,数据层的逻辑和功能已经比较清晰完备,大多数系统都直接采用 DBMS。剩下的关键问题就是如何对另外两层进行明确分割,使得表示层和功能层之间逻辑独

立,接口简洁。这里我们举一个简单例子。三级结构的一种典型系统是事务处理(TP,transaction processing)监督技术。客户通过表示层向中级服务器发出事务处理请求。中

级服务器实际上是一台 TP 监督器,它管理信息队列,事务调度,优先权分配等任务,

同时代表客户向数据库服务器发出请求。客户的服务请求一旦被 TP 监督器所接受,TP监督器就负担起全部责任,直到客户请求的事务处理完毕为止。此外,TP 监督器可以

在一件事务处理过程中更新多个数据库,可按照不同的优先次序调度客户请求,同时还

能保证一定程度的安全性。实践证明,对于拥有数千个客户的事务处理系统来说,采用

三级结构的 TP 监督技术是最行之有效的。 我们在前面的讨论中都是采用典型的三层逻辑。值得一提的是,这种分层方法并非

唯一,也非标准,只不过它相对简单,相对清晰,为一般系统设计者和教科书所常用而

已。实际上,在客户/服务器系统平台的设计中,还有一些其他的分层方法。例如,SUN公司推出的 J2EE 模型就给出了 5 层逻辑结构:客户层,表示层,业务层(business),整合层(integration)以及资源层(resource)。

此外,在多级结构环境中,我们可以把一个网络应用的逻辑层面分布在客户和各级

服务器上,其分布方式被称为纵向分布(vertical distribution)。然而,纵向分布只是构

造客户 /服务器模型的方法之一,在现代系统结构中,我们也可以采用横向分布

(horizontal distribution)。横向分布的宗旨是把客户或服务器分割成逻辑上等价的物理实

体,每个物理实体都在完整的数据上管理属于自己的那块领地,因此达到平衡负载,提

高吞吐率的目的。在后面的章节里,我们还会讨论分布式系统的其他构造模型和网络应

用模型,也会看到许多系统根据实际因事置宜,合纵连横,不拘一格。

习 题

2.1 分布式操作系统和网络操作系统的主要区别是什么? 2.2 什么类型的分布式应用最需要共享内存系统?为什么? 2.3 在 DSM 系统的实现中,我们可以采用“迁移” 和“复制” 技术来管理虚存页面,

你认为哪一种方法容易实现?论证你的答案。 2.4 如果让你设计一个基于总线的硬件系统,你用什么方法解决多个处理器对总线

的竞争? 2.5 请你为二叉树网络结构设计一个分布式路径算法。注意:树中每个结点都要执

行同一个算法。

Page 30: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·34·

2.6 请用实例解释网络中哪些资源可以被共享?哪些需要互斥共享?哪些不能共享? 2.7 请给出另一种网络拓扑结构,并用书中的五个性质来说明这种结构的优缺点。 2.8 请用自然语言描述一下共享文件管理器的实现方案。 2.9 请用你的浏览器查阅 DCOM,CORBA,MSMQ。给出这几种模型的大致描述。 2.10 本书采用三层逻辑来刻画客户/服务器系统平台,并且列举出 J2EE 的五层逻

辑。你能找到另外一种著名的逻辑分层模型吗? 2.11 在一个客户/服务器系统里,客户如何找到服务器? 2.12 请你给出缓冲(buffer)和缓存(cache)之间的区别。 2.13 请你给出一个具体例子,说明横向分布的必要性。 2.14 请你尝试使用一个基于浏览器/服务器的网络应用,并写下心得与建议。 2.15 我们讨论了客户/服务器模型,那么,是否存在服务器/服务器模型和客户/客

户模型呢?如果存在,举例说明。 2.16 为什么浏览器/服务器模型尚不能完全取代客户/服务器模型?你认为在将来

有完全取代的可能吗?

Page 31: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算

一个分布式程序必然是一个并发程序,而一个并发程序却未必是一个分布式程序。

在前几章的讨论中,我们已经使用了许多并发程序中的重要概念,如进程、进程间通信、

同步及互斥等。我们假定读者在操作系统课程中已经对这些概念有了初步的了解。然而,

作为一个分布式系统设计者,必须详细地知道并发计算的原理以及并发实体间的逻辑关

系和交互方法,因为这些概念将会作为一个分布式系统的构成基础,极大地影响到系统

的总体设计、具体实现、系统性能以及使用效率。在本章中,我们将要重温一下传统操

作系统中并发程序概念,着重讨论各种并发实体(如进程或线程)在分布式系统中所扮

演的重要角色,以及这些实体如何通过同步与互斥协同完成一个分布式计算。由于客户

/服务器模型是分布式系统的一种典型结构,我们亦将探讨一下服务器软件的设计问题。

此外,分布式系统把传统的单机并发计算扩展到计算机网络上,一种新的并发实体即(移

动)软件代理技术,已经成为现代分布式系统研究的一个重要课题,我们也要在本章中

对这种技术作一些介绍。

4.1 并发计算起源

在众多的计算机术语中,并发这个术语的含义非常明确,指的是在同一个时间做多

件事。那么,如果我们只有一个 CPU 的话,怎样才能在同一个时间执行多个程序呢?

理论上讲,这是不可能的。然而,在早期的计算机实践中,人们发现的确有许多事可以

“并发”。例如,当一个程序在等待输入输出时,CPU 空闲在那里无事可做,而与此同时,

还有许多程序期待着使用 CPU。如果输入输出工作由独立的 I/O 控制器完成,我们就可

以在这个时候调度一个新的程序使用 CPU,那么看上去这个新程序就和正在进行输入输

出的程序“并发”执行了。 20 世纪 60 年代,人们就开始了对并发计算的研究,重点放在操作系统的设计与实

现上。实际上,操作系统本身就是一个并发程序,拥有多个进程来管理系统资源和用户

程序。在传统单机系统里,这种多进程的思想被称为“多道程序设计”,而所谓的“并发”则是以时间片轮转的方式,调度进程占有 CPU。如果多个进程各行其事,我们只要完成

进程调度就可以了。但是,随着对并发计算研究的深入,人们发现可以组织多个进程协

同工作,从而以并发的方式提高整个程序的执行效率。既然名曰协同,进程之间就需要

有通信和同步的机制。到了 70 年代,以共享内存为基础的并发程序设计成了一个热门

的科研话题。许多著名的计算机科学家提出了各种各样的通信、同步以及互斥算法,诸

如信号灯(semaphore)、条件临界区(conditional critical region)、管程(monitor)等。

80 年代,随着网络技术的发展,人们把目光投向进程间的消息传送以及远程过程调用。

90 年代初,人们又提出了一种具有革命性质的新概念-线程(thread),并且在几个典型

Page 32: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·66·

的操作系统上实现了这种概念。线程这种并发实体进一步改进了并发程序设计思想,使

得一个程序的并发程度更高、效率更快、管理起来更容易。在下面的小节里,我们将要

分别讨论进程、线程以及这些并发实体之间的同步与互斥机制。

4.1.1 进程

在传统操作系统中,进程是一种基本的计算单位。进程这个术语的定义有很多,而

最为流行的简单定义是“一个运行着的程序”。如果一个进程只有一条控制流程,则被

称为顺序进程(sequential process)。早期操作系统里的进程大都是顺序进程。多个顺序

进程可以并发执行。我们把互不相干的一组进程称为异步进程,而把需要通过交互来决

定执行次序的一组进程称为同步进程。作为一个基本计算单位,一个进程应该包括执行

中的程序、该程序所操作的数据、所使用的资源以及执行期间的状态。从另一个角度来

看,每一个进程都拥有自身的运行环境,我们可以把这个运行环境看成是一台抽象的计

算机,包括分配给该进程的虚 CPU、存储空间以及其他系统资源。 进程管理是传统操作系统的一个重要组成模块,这个模块提供了进程创建与消亡、

资源分配与去配、进程调度、进程同步与互斥、进程阻塞与释放以及进程通信等系统工

具。在进程管理模块的控制之下,每个进程都会经过从创建到消亡的生存周期,在这个

周期里,进程会产生一系列的状态变迁,我们在图 4.1 中给出一个典型的进程状态变迁

示意图,图中方框指的是初始和最终两个状态,而椭圆代表执行期间的状态。

运行

阻塞 就绪 创建

消亡

调度

时钟中断 请求服务

服务成功

图 4.1 进程状态变迁

当一个进程被创建后,它进入就绪(ready)状态,也就是说,它已经具备除了 CPU之外的一切运行环境。一旦进程管理模块调度到这个就绪进程,它就切换成运行

(running)状态,CPU 开始依照进程的指令流对数据进行操作加工。如果运行中的进程

消耗完分配给它的时间片,调度程序就把它重新放回到就绪队列里,等待下一轮的调度。

在一个进程的执行过程中,它有可能主动或被动地切换成阻塞(blocked)状态。譬如它

可能会主动地把自己挂起(suspend),等待另一个进程将其解挂(resume);或者它被动

地由系统阻塞,等待操作系统的其他模块完成所需的服务请求。当一个阻塞的进程被系

统释放后,它就又回到就绪状态。如果进程的指令流执行完毕,这个进程便完成了自己

的历史使命,从系统中退出。这里需要指出,图 4.1 所展示的是普通进程的状态变迁,

有时我们把这类进程称为暂存进程,即在一个有限的时间里,这类进程将经历一个从生

到死的完整过程。而在操作系统中,有许多进程与整个系统共存亡,我们则把这类系统

Page 33: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·67·

进程称为长存进程。 在传统的操作系统和并发程序设计中,人们通常使用的进程生成模型采用一种“家

谱”式的衍生方案,即一个初始进程(亦可称为根进程)作为一个氏族的老祖宗,通

过这个进程派生出来的进程可以逐层创建新的进程,形成一种父、子、孙……式的氏

族体系。 例如,UNIX 就采用这种“家谱”式并发进程模型,通过一个称作 fork 的系统调用

来创建新进程。我们在图 4.2 中给出一个 C 语言编写的进程创建例子。当这个程序执行

到第一个 fork 时,系统将自动生成一个新进程,按照 fork 的语义,这个新进程(子进

程)是创建者的完全拷贝,用中国的一句老话来形容:“有其父必有其子”。子进程继承

了父进程的一切,包括程序、数据、执行状态以及 I/O 资源。当 fork 成功返回的时候,

父子两个进程都拥有自己独立的执行环境,而且看上去都刚刚执行完同一个系统调用。

唯一不同之处在于,父进程接到一个非 0 返回值,这个值代表系统赋予子进程的标识符;

而子进程则接收到一个 0 作为返回值。于是,程序中的条件判别语句把父子进程中的控

制转向不同的程序体,具体地说,父进程执行条件成功的程序体,而子进程执行条件失

败的程序体。从程序中我们可以看到,子进程执行的是 else if 语句,在该语句中又发出

了第二个 fork 调用,由此便生成了第三个进程,即孙进程。此刻,该程序的祖孙三代进

程并发执行,各自输出一行打印后退出系统。

/* UNIX 进程创建:process_creation.c */ #include <stdlib.h> main(){

int pid; if ((pid = fork()) != 0){ /* 父进程 */ printf("Father\n"); wait(0); } else if ((pid = fork()) != 0){ /* 子进程 */ printf("Son\n");

wait(0); } else { /* 孙进程 */ printf("Grandson\n");

} exit(0);

}

图 4.2 UNIX 进程创建

每一个进程都有自己的执行环境,而执行环境中最重要的部分是存储空间。一般人

们把一个进程的存储地址空间分成若干区域(region),在不同的区域里存放性质不同的

数据和控制信息。例如,每一个 UNIX 进程都具有完全独立的地址空间,该空间由 3 个

区域组成:第一是一块固定的、不可修改的区域,用来存放程序代码、常数等信息;第

Page 34: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·68·

二是一块称为堆(heap)的区域,用来存放所有动态分配的数据;第三是一块称为栈

(stack)的区域,用以存放过程调用的控制信息以及从属于被调用过程的局部变量。

图 4.3 给出了上述 UNIX 进程创建例子中祖孙三代进程的存储空间。

程序常数区

程序常数区

程序常数区

父进程 子进程 孙进程

图 4.3 UNIX 进程创建存储空间示意

毫无疑问,如图 4.3 那样的进程存储空间相当安全,每一个进程的地址空间都处在

系统的严密保护之下,不允许任何其他进程侵入。作为一个并发程序设计者,我们当然

希望进程各自拥有自己的存储空间,这样进程与进程之间就存在一个干净清楚的分界,

彼此互不侵犯,只通过进程间通信来实现同步与交互。然而,这种高级的并发概念却以

系统性能为代价,尤其是进程的存储管理方式会造成操作系统的巨大开销。从资源管理

的角度来说,每当创建一个新进程的时候,系统都要为它分配一个独立的地址空间,同

时还要把父进程的程序数据原封不动地复制到子进程的地址空间去;从系统调度的角度

来说,每当把 CPU 从一个进程分配给另一个进程时,我们都要进行进程内容切换(context switch),包括保存旧进程的执行状态,设置新调度进程的执行状态等一系列繁杂费时的

工作;从进程交互协作的角度来看,由于进程之间不存在共享内存,我们必须提供一些

进程间通信(IPC,interprocess communication)机制,或者强制这些进程通过互斥手段

来访问一块操作系统控制的共享内存空间。另者,对现代计算机系统结构而言,顺序进

程的概念也显得有些落伍。如今的计算机都装有大容量的高速缓存,其访问速度远远高

于内存(一般都有一个数量级的差异)。当一个进程运行时,这个进程频繁访问的一部

分数据存放在高速缓存里,缓存的高命中率会极大地提高程序执行效率。可是,如果

一个程序的并发实体仅限于顺序进程,那么每当进程内容切换时,由于新调度的进程

拥有完全独立的地址空间,高速缓存中原有的数据对新进程毫无用处,缓存里的内容

及其地址影射要全部刷新。这种更换高速缓存数据的工作无疑也是导致系统效率降低的

因素之一。 根据上面的讨论,我们知道造成系统重大开销的关键因素是进程内容切换。那么,

所谓的进程内容(process context)包括哪些东西呢?按照进程的运行环境来考察,我们

Page 35: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·69·

可以把进程内容划分为两部分:一部分是 CPU 内容(CPU context),另一部分是存储内

容(storage context)。一个进程 CPU 内容比较简单,包括程序计数器、通用寄存器,栈

指针以及其他一些辅助信息。而一个进程的存储内容却复杂得多,包括该进程的程序、

数据、地址空间、不同区域的地址影射、磁盘交换(swap)影射等。所以,当我们进行

进程内容切换时,只需要很少的时间完成 CPU 内容切换,而把大量的时间花费在存储

内容切换上。其中的道理很简单,CPU 内容切换仅仅涉及到若干个系统寄存器的保存与

更新;而存储内容切换却要实现大换班,包括更改内存管理单元的所有寄存器、刷新高

速缓存的地址翻译信息,更有甚者,如果计算机内存不够大,新老进程还可能需要进行

磁盘和内存之间的程序交换。 也许有的读者会说,既然进程内容切换这么浪费时间,我们何不把进程占用 CPU

的时间片加大,以减少进程切换的次数。可惜,这样做一来损害了进程调度的公平性,

二来对频繁交互的进程不起任何作用。以 UNIX 为例,顺序进程只能通过 UNIX 提供的

IPC 机制实现进程间的交互。典型的 UNIX IPC 包括管道(pipe)、消息队列(message queue)、套接字以及(系统控制的)共享内存段(shared memory segment)。每当一个进

程使用 IPC 时,都要受到操作系统的干预,这种干预的实质是从用户进程到系统进程的

内容切换。如果一对用户进程想通过 IPC 实现一次发送/接收操作,我们会面临至少四

次进程内容切换(包括用户运行模式/系统运行模式的转换):发送进程切换到系统内核、

系统内核反切换回发送进程、接收进程切换到系统内核、系统内核反切换回接收进程。

这种巨大的 IPC 开销显然是传统顺序进程概念的一个致命缺点。此外,许多计算机应用

往往需要并发实体之间能够共享用户自己控制的内存。共享内存不仅可以提高程序执行

效率,也可以方便程序设计。例如,在一个多媒体动画系统中,我们至少需要编制两个

关键的并发实体,一个用来生成一帧帧的画面,另一个用来显示动画。如果这两个并发

实体之间不存在共享地址空间,每一帧画面都要通过 IPC 机制来传送的话,速度较慢的

计算机就会由于频繁的进程内容切换而发生画面抖动。反之,如果两个并发实体之间存

在一个不受操作系统干预的共享地址空间,我们就可以通过指引元,把生成的一帧画面

方便快捷地传递到显示程序。 综上所述,尽管进程是并发程序或分布式程序的基本构造单元,但实践证明传统

操作系统提供的进程概念已经无法适应现代计算机结构、无法满足分布式应用的需求。

我们需要的是另一种并发概念,通过这个新概念可以克服顺序进程概念所存在的缺点,

可以构造细颗粒度(fine granularity)的并发实体,这就是我们将在下一小节里讨论的

线程概念。

4.1.2 线程

直观上看,线程非常类似于进程,人们把线程也定义为“一个运行着的(部分)程

序”。因此,线程会像进程那样有一个从生成到消亡的周期,并且在这个周期里经历一

系列的状态变迁。然而,线程没有进程那样高的并发透明度,具体地说,一个线程系统

仅需要维护 CPU 内容,当线程内容切换的时候,我们不改变原来的存储内容,而只需

切换 CPU 内容。要做到这一点,线程之间就必须共享同一个存储空间。 显然,引入线程概念只有一个目的,那就是以最小的系统代价实现最大程度的并发。

Page 36: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·70·

而由于线程和进程的定义相类似,也有人把传统顺序进程称为重量级(heavyweight)进

程,把线程称为轻量级(lightweight)进程。那么,我们是否可以用线程完全取代进程

呢?只要读者仔细想一下进程和线程的差异,就可以得出否定的答案。线程共享存储空

间,其潜在含义是:系统不负责对线程的自动地址保护。这个潜在含义也蕴藏着潜在危

险。如果我们只有线程概念,那么属于不同应用的多个线程可能会随心所欲地存取同一

个地址空间里的数据,任何非法访问都会造成整个系统的混乱乃至崩溃。为了避免这种

危险,人们采用了一种混合方案,即把进程当成一级并发单元,用来实现不同应用程序

的并发,或者同一应用程序中不同功能模块的并发;而把线程当成二级并发单元,用来

实现一个进程内多个子功能的并发。针对这种两级并发结构,我们有一个形象的比喻:

一个进程好像是一个封闭的大玻璃瓶,瓶里有空气、花粉等资源;线程好像是一群蜜蜂,

它们可以在瓶子里自由地飞来飞去,有序地采花酿蜜,但无论如何也飞不出那个封闭的

空间,假若这些蜜蜂乱了套,在瓶子里胡作非为,它们也只是自食恶果。根据这种解释,

我们可以把传统的顺序进程视为单线进程,而将拥有多个线程的进程叫做多线进程,如

图 4.4 所示,其中,PCB 代表进程控制块(process control block),TCB 代表线程控制块

(thread control block),这些控制块含有控制调度进程或线程所需的信息。

PCB PCB

TCB TCB TCB

PCB

TCB TCB TCB

线程支持系统

操作系统

单线进程 多线进程 多线进程

图 4.4 进程与线程

实现线程的方法有多种,可以由操作系统实现,可以由语言实现(如 JAVA),然而,

大多数线程系统都是通过程序包实现的,用户通过线程程序包提供的 API 对线程进行管

理,诸如创建与消亡、同步与互斥等操作。目前最著名的两个线程程序包是由 IEEE 和

OSI 推荐的 POSIX(portable operating system interface)以及 SUN 操作系统之下的线程

包 LWP(light weight process)。 在设计一个线程程序包时,我们会面临两个关键问题:一是如何调度线程,二是如

何处理阻塞性的系统调用。也就是说,当若干个线程都处于就绪状态时,我们怎样使它

Page 37: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·71·

们分享 CPU?当某个运行的线程发出系统调用,而这个调用有可能阻塞调用者时,我们

又如何对待这个线程及其所属的进程?不同的线程系统可能采用不同的解决策略,一般

而言,实现线程的策略有 3 种:用户级(用户空间)线程,系统级(内核空间)线程以

及混合型线程。

1. 用户级线程

顾名思义,用户级线程策略意味着把所有的线程完全构造在用户进程的地址空间

里。因此,采用这种策略的线程程序包也完全在用户模式下运行,操作系统对此毫无知

晓。当操作系统把 CPU 分配给一个进程的时候,这个进程就要进一步把它的时间片转

分配给它所管辖的众多线程,从而实现进程内部的并发执行。线程程序包的 API 提供了

各种在用户进程空间里操作的同步互斥调用,这些调用可能引发线程状态变迁,诸如从

就绪到阻塞或者从等待到释放等。然而,这种线程状态变迁无非是把该线程从一个队列

移动到另一个队列,并不影响到用户进程的当前状态。为了方便后面的讨论,我们把引

发线程状态变迁的调用称为线程调用,把引发进程状态变迁的调用称为系统调用。用户

级线程策略有两个主要优点。第一,由于线程都使用当前运行着的存储空间,线程的创

建与消亡很容易实现。创建一个新线程的代价只不过是动态分配一块内存,然后把这块

内存设置成线程的工作栈;而消亡一个线程无非是把栈释放而已。有人在奔腾机

(133MHz)做过性能比较,创建一个线程只需要 50μs,创建一个进程(fork)却需要

35000μs;而在 SPARC 工作站(110MHz)上,创建一个线程需要 330μs,创建一个进程

却需要 45000μs。这种巨大的差异无疑是线程概念成功的重要因素之一。第二个优点体

现在线程内容切换上。前面我们说过,线程内容仅仅包括 CPU 内容,即程序计数器、

通用寄存器以及栈指针。进行线程内容切换只需要把这些寄存器的内容存回当前线程的

TCB,把新调度线程 TCB 里的值设置到相应寄存器上,这个切换过程往往用几十条机

器指令就足以胜任。 然而,用户级线程策略有一个很大的缺陷,线程无法获得操作系统的支持与合作。

这种支持与合作主要体现在阻塞性系统调用上。由于操作系统只知道进程而无视线程的

存在,当一个线程发出阻塞性系统调用时,操作系统认为是进程发出的调用,于是,受

阻塞的是该线程所属的那个进程,从而导致整个进程里的所有线程都被阻塞。这种现象

会产生两个恶劣的后果,其一,线程的并发性将随着进程的阻塞而终止;其二,我们无

法使用时间片轮转的方法来调度线程。第一种后果颇为直截了当,既然进程阻塞了,它

所包容的线程当然也无法运行。而第二种后果尚需做些解释。大家知道,要想实现并发

实体的时间片轮转,我们必须使用硬件的时钟中断。调度程序等待(阻塞)在那里,一

旦系统捕捉到时钟中断,立即释放调度程序,然后由调度程序实现并发实体的内容切换。

对用户级线程来说,其调度程序是用户进程中的一段程序,它根本不可能使用硬件时钟,

因为只要调度程序一阻塞(等时钟中断),它所管辖的线程就全部阻塞,计算机的运行

环境就被操作系统切换给另一个(不同地址空间的)就绪进程。 如此说来,我们岂不是无法调度用户级线程了吗?非也。尽管我们不能使用时间片

轮转调度,亦称为强占式(preemptive)调度,但我们可以采用非强占式调度,也就是

说,当一个线程需要与其他线程交互而发出某个线程调用时,线程调度程序就可以抓住

Page 38: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·72·

这个时机进行线程切换。细心的读者可能会发现,这种非强占式调度缺乏公平性,如果

一个线程只做计算而从不发出任何线程调用的话,我们就无法从它手里夺回 CPU,其他

线程就会出现饿死(starvation)现象。

2. 系统级线程

阻塞性系统调是用户级线程策略无法克服的障碍。为了逾越这个障碍,有的系统干

脆把线程概念融入操作系统的内核,直接由系统来管理线程调度和系统调用,这种方式

被称为系统级线程策略。毫无疑问,系统级线程策略可以采用时间片轮转的方式调度线

程,可以阻塞一个线程而不影响同一进程中的其他线程。但遗憾的是,这样做不仅损害

了进程和线程两级并发的抽象结构,也使得系统开销恢复到与传统进程概念差不多的程

度。例如,每一个线程操作,诸如创建、删除、同步等,都要通过系统调用传递到系统

内核才能执行。这种从用户模式到系统模式的运行状态变迁都会引发昂贵的进程内容切

换,因此,线程概念所拥有的优点也就黯然失色。

用户级线程 用户级线程

LWP LWP LWP LWP

重量级进程 重量级进程

操作系统内核级线程

图 4.5 用户线程和系统线程混合型策略

3. 混合型线程

我们能否从上述两种策略中取长补短呢?当然可以,这就是把用户级线程和系统级

线程混合在一起,而沟通用户线程和系统线程的桥梁就是抽象的 LWP,如图 4.5 所示。

在混合型方案里,一个重量级进程可以有若干个 LWP,这些 LWP 由用户进程所生成,

却由系统所管理。换言之,LWP 是系统能够识别、能够调度的最小运行单元。同时,我

们还拥有一个用户级线程程序包,提供各种各样的用户线程调用和操作,如创建与消亡、

同步与互斥等。混合型方案的设计关键在于,用户线程程序包必须在用户进程的地址空

Page 39: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·73·

间里工作,系统对用户级线程以及这个程序包提供的操作仍旧一无所知。那么,如何才

能调度用户线程呢?这就要依靠 LWP。我们把一个和多个用户线程赋予一个 LWP,而每一个 LWP 自动影射到一个由内核管理的系统级线程。内核只对系统级线程进行

强占式调度,通过 LWP,用户级线程就相应地获得了 CPU。一个 LWP 可以对一组用

户级线程实行非强占式调度,而这种调度所引发的内容切换却不会影响到操作系统。

当一个用户线程发出线程调用时,这个调用完全在用户空间里实现;当一个用户线程

发出系统调用时,这个调用被 LWP 捕捉,于是,LWP 便代表用户线程向系统发出真

正的调用,并由此被阻塞。然而,一个阻塞的 LWP 并不会殃及同一个进程中的其他

LWP,那些没有阻塞的 LWP 依然并发运行。使用 LWP 来沟通用户级线程和系统级线

程有许多优点。第一,用户线程的创建、消亡、同步等操作不需要操作系统的干预,

故代价很低。第二,只要一个进程有足够多的 LWP,一次阻塞性系统调用不会导致

整个进程被阻塞。第三,一个线程应用并没有必要知道 LWP 是如何工作的,只要设

计好用户线程就行了。第四,越来越多的服务器采用多处理器系统,LWP 概念非常

适合于这类硬件结构,而且 LWP 在多处理器上的真正并发执行对用户来说是完全透

明的。 综上所述,线程已经成为现代操作系统中必不可缺的成分。线程概念极大地简化了

复杂的程序设计,增强了系统的吞吐率,细化了程序的并发颗粒度,改善了多处理器的

利用率。绝大多数现代操作系统、数据库、程序设计语言都以不同方式支持线程概念。

图 4.6 以框架的形式给出 3 个线程例子,分别为线程程序包 POSIX,操作系统 Win32 以

及程序设计语言 Java。

/* POSIX 线程 */ main(){ … pthread_create(f,arg); … }

void *f(void *arg){ … pthread_exit(status); }

/* Win32 线程 */ main(){ … CreateThread(f,arg);_beginthread(f,arg);_xbeginthread(f,arg);}

DWORM f(DWORD arg){… ExitThread(status);_endthread(status);_xendthread(status);}

/* Java 线程 */ main(){ MyThread t; t = new MyThread(); t.start(); }

class MyThread extends Thread{ public void run(){ … return; } }

图 4.6 不同系统下的线程例子

为了深入理解线程概念,我们简单介绍一下著名的线程程序包 POSIX。POSIX 目前

已经成为大多数 UNIX 和 LINUX 版本的标准线程规范。UNIX 之上的 POSIX 一般只支

持用户级线程,LINUX 内核在 1.3.56 版之前只支持用户级线程,而其后实现了系统内

核级线程,故而支持混合型线程策略。然而,作为线程应用程序设计者,我们可以忽略

线程实现策略,只需了解如何利用 POSIX 的 API 编写程序。在图 4.7 中,我们给出一个

Page 40: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·74·

用 C 语言编制的 POSIX 线程例子。与 Java 不同,C 没有提供任何有关线程的语言成分,

线程概念是由库程序实现的。因此,在编译这个程序时,我们必须在编译命令中显式地

给出 POSIX 库程序连接,即-lpthread。这个程序由 3 个部分组成:第一,全局说明及初

始化,其中包括所需的程序库、函数原型、共享互斥机制以及一个共享变量 x;第二,

主程序入口函数 main;第三,线程函数 mythread。

/* POSIX 线程创建: thread_creation.c */ /* 编译:gcc –o thread_creation thread_creation.c –lpthread */

#include <pthread.h> #include <stdlib.h> #include <stdio.h>

/* 线程函数原型 */ void *mythread(void);

/* 初始化一个互斥锁 */ pthread_mutex_t mylock = PTHREAD_MUTEX_IITIALIZER; /* 线程共享变量 */ int x = 0; /* 主程序(根进程) */ int main(){

pthread_t tids[10]; /* 线程标识符数组 */ int i; for (i = 0; i < 10; i++){ /* 创建 10个线程 */ pthread_create(&tids[i], NULL, mythread, NULL); } for (i = 0; i < 10; i++){ /* 等待线程结束 */ pthread_join(tids[i], NULL); printf("Thread id %ld returned\n", tids[i]); } exit(0);

}

/* 线程函数 */ void *mythread(void){ /* 每个线程都对共享变量 x进行加一操作 */

while (x < 4000){ pthread_mutex_lock(&mylock); /* 上锁 */ x++; /* 临界区 */ printf("Thread id %ld: x is now %d\n", pthread_self(), x); pthread_mutex_unlock(&mylock); /* 开锁 */ } pthread_exit(NULL); /* 线程结束 */

}

图 4.7 POSIX 线程例子

Page 41: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·75·

初始启动这个程序时,操作系统只创建一个单线进程。当这个进程执行到第一条循环

语句时,10 个新线程就逐一地诞生,开始并发运行。此刻,我们的进程就变成了多线进

程。它一共拥有 11 个线程,其中一个以 main 为执行体,而新生的 10 个线程都以函数

mythread 作为执行体。main 线程随后执行第二条循环语句,它被阻塞在那里,直到所有

的 mythread 线程执行完毕才结束循环。然后,它执行退出语句,整个进程从系统中消亡。 mythread 线程的工作很简单,概言之,它用循环的方式对一个共享变量 x 进行加一

运算,直到 x 的值大于等于 4000,然后它以线程退出调用来结束自己的历史使命。读者

也许要问,既然如此简单,那么为什么在加一运算的首尾要用上锁(lock)/开锁(unlock)的线程调用呢?这里,我们建议读者尝试着运行一下上述例子,然后删去 mythread 线程

中上锁/开锁两个调用,再运行一下修改过的程序,对比两个程序的输出结果,看看是否

能发现什么不同,而其间的道理,我们留待下节讨论。

4.1.3 并发计算中的同步与互斥

当我们采用多线程或者多进程来编制并发程序时,如果这些并发实体需要访问共享数

据或资源,一个首要的问题就是要保证对共享资源的保护。换句话说,我们必须使这些并

发实体井然有序地访问共享资源,否则有可能出现非确定性的结果。那么,什么是非确定

性的结果呢?这里我们考虑一个非常简单的例子,如图 4.8 所示。假定有两个并发线程 T和 S 执行相同的语句,对共享变量 x 实行加一运算。假定这条语句通过编译会生成 3 条

汇编指令,即取 x 值(LOD)、加一(ADD)以及存回 x(STO)操作。为了方便下面的

讨论,我们在图中对每条指令都给出标号。从计算机原理课程中我们知道,每一条指令是

一个“原子”动作,即该条指令从开始执行到执行结束期间不允许被中断,但任意两条指

令之间却有可能出现中断。中断所导致的可能后果是线程内容切换,即控制从 T 切换到 S,反之亦然。理论上讲,我们有各种各样合法的指令执行序列。就图 4.8 给出的并发线程例

子而言,一共有 20 种合法的指令执行序列,我们在图中列举了其中的 9 种。

线程 T 线程 S

可能出现的指令执行序列:

(1) t1,t2,t3,s1,s2,s3 (2) t1,t2,s1,t3,s2,s3

(3) t1,t2,s1,s2,t3.s3; (4) t1,t2,s1,s2,s3,t3

(5) t1,s1,t2,t3,s2,s3 (6) t1,s1,t2,s2,t3,s3

(7) t1,s1,t2,s2,s3,t3 (8) t1,s1,s2,t2,t3,s3

(9) t1,s1,s2,t2,t3,s3 …

T: { x++; }

t1: LOD R1, x t2: ADD R1, 1 t3: STO R1, x

S: { x++; }

s1: LOD R1, x s2: ADD R1, 1 s3: STO R1, x

图 4.8 并发进程共享变量存在的问题

Page 42: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·76·

从这个并发程序的语义上看,显而易见,我们期望对共享变量 x 进行两次加一运算,

即如果 x 的初始值为 0,当程序结束时,x 的值应该为 2。遗憾的是,由于我们对共享变

量 x 没有施加保护,它的最终值是非确定的。考察一下图中给出的序列,我们发现,执

行指令序列(1),x 的最终值是 2;而指令序列(2)到(9)都使得 x 的最终值为 1。假

若我们枚举出上述程序的所有 20 种合法指令执行序列,我们可以发现,只有 t1,t2,t3,s1,s2,s3 和 s1,s2,s3,t1,t2,t3 两种序列导致预期的结果,而其他 18 种序列都产

生非预期的答案。在传统的操作系统教材中,我们把访问共享变量 x 的那组指令称为临

界区(critical region)。临界区是必须“原子化”的(不允许中断的)一组程序代码。如

在上面的程序中,t1,t2,t3 以及 s1,s2,s3 便是访问共享变量 x 的临界区例子。由于

例子中的并发线程对临界区没有保护措施,这个程序成为非确定性程序,即同一个程序

在同一组数据上的多次执行无法保证都产生相同的结果。 引发非确定性的原因很简单:当一个并发实体正在临界区里操作时,其他的并发实

体也同时闯入临界区,从而破坏了共享资源的一致性。解决这个问题的策略同样很简单:

任何时刻仅允许一个并发实体在临界区里操作。在并发程序设计中,我们把这种策略称

为互斥(mutual exclusion)。一般而言,有 4 种可能的互斥实现方法:第一,由于并发

实体的内容切换是由中断造成的,我们可以采用封闭/开放中断的方式来保护临界区;第

二,我们可以用优先级排序的方法使并发实体按照某个预定的次序进入临界区;第三,

我们可以提供一种中央控制机构,通过这个机构管理所有对临界区的访问;第四,我们

可以提供一组同步互斥原语,并发实体调用这些系统原语对临界区竞争。虽然上述四种

方法在实践中可行,但人们通常都采用第三种和第四种方案,因为允许用户开放/关闭中

断会对操作系统构成威胁,采用优先次序管理临界区的算法不仅过于复杂,而且缺乏公

平性。 在并发程序设计的研究过程中,人们开发出各种各样的互斥算法与互斥机制。有的

机制由硬件提供,有的构造在系统程序包里,也有的演化为程序设计语言的基本结构。

然而,无论解决互斥问题的方法以何种面目出现都应该设法满足下面 3 点要求: 1)必须保证不准多于一个的并发实体同时进入临界区; 2)必须防止来自临界区之外的并发实体的干扰; 3)必须防止饿死现象(即某些并发实体无穷无尽地等待着进入临界区)。 一些著名的互斥机制,如信号灯和 P/V 操作、管程、条件变量等,在操作系统课程

里都有过介绍,我们就不再重复。通过本节的讨论,读者能够理解为什么在图 4.7 POSIX线程例子中我们要对线程的临界区施加上锁/开锁的线程调用。下面我们再给出一个具体

的 POSIX 并发线程同步与互斥的例子,见图 4.9。 这是一个古典的生产者与消费者问题,我们用并发线程来编制解决这个问题的程

序。在生产者与消费者之间有一个共享的缓冲,生产者把制作出来的产品放在缓冲里,

而消费者从缓冲中索取一个产品来享用。显然,这个共享的缓冲必须互斥地访问。于是,

我们采用 POSIX 提供的互斥原语,即上锁/开锁调用对并发线程的临界区进行保护。然

而,这个问题不仅包含并发线程之间的互斥,还涉及到两者之间的同步。当缓冲已经装

满产品时,生产者就不能再往里面置放新的产品;同样,当缓冲里什么东西都没有的时候,

消费者也不可能从中提取产品。为了简化我们的讨论,我们把问题中的缓冲容量定为 1,

Page 43: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·77·

/* POSIX 生产者和消费者问题: producer_consumer.c */

#include <pthread.h>

/* 线程函数原型 */ void *producer_function(void); void *consumer_function(void);

/* 初始化一个互斥锁 */ pthread_mutex_t mylock = PTHREAD_MUTEX_IITIALIZER;

/* 线程共享变量 */ int flag = 0; char buffer; struct timespec dealy;

main(){

pthread_t consumer; delay.tv_sec = 2; /* 设置 2秒时间延迟 */ delay.tv_nsec = 0; /* 创建 consumer线程 */ pthread_create(&consumer, NULL, consumer_function, NULL); producer_function(); /* main演变为 producer线程 */

}

void *producer_function(void){ while (1){ pthread_mutex_lock(&mylock); if (flag == 0){ buffer = produce(); /* 生产一个物品 */ flag = 1; } pthread_mutex_unlock(&mylock); pthread_delay_np(&delay); /* 睡眠 2秒 */ }

}

void *consumer_function(void){ while (1){ pthread_mutex_lock(&mylock); if (flag == 1){ consume(buffer); /* 消费一个物品 */ flag = 0; } pthread_mutex_unlock(&mylock); pthread_delay_np(&delay); /* 睡眠 2秒 */ }

}

图 4.9 生产者与消费者问题

Page 44: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·78·

并且引入了一个整型变量 flag 来指明缓冲的空/满状态。如果生产者成功地进入临界区,

仅当缓冲空时,它才能生产一个新产品并放入到缓冲里,否则,它就必须放弃临界区,

睡眠一段时间,然后再行试探。与此相仿,如果消费者进入临界区,仅当缓冲满时,它

才能取出那个产品并消费之,否则,它就像生产者那样,放弃临界区,睡眠一段时间,

然后再行试探。毫无疑问,图 4.9 给出的程序在逻辑上无懈可击,但在效率上却愚笨之

极。假定消费者要花 1 分钟才能享用一个产品,那么生产者就必须至少等待 1 分钟后才

能开始进行下一个产品的制作,因为消费者在享用产品时一直占据着临界区。而在实践

中,生产和消费这两个动作完全可以并发进行。 也许有的读者会说,既然 produce 和 consume 这两个过程可以并发,我们把这两个

调用移动到临界区之外不就行了吗?遗憾的是,这样做的后果破坏了程序在逻辑上的正

确性。假定生产者在临界区外调用 produce,然后进入临界区,但它发现缓冲还满着,

便立即放弃临界区,睡眠一会儿,又循环生产下一个产品,于是就导致了前一个产品的

丢失。更为恶劣的是,如果生产者和消费者的睡眠时间差异很大(注意,这个睡眠时间

只是一种抽象的模拟,在具体应用中,它可能代表任何数据计算和处理的时间),假定

生产者睡眠 2s 而消费者睡眠 20s,则在消费者睡眠期间内,生产者就有可能最多 10 次

进入临界区,却都无功而返。这种并发实体之间的同步方式被称为忙等(busy waiting),而程序中对互斥锁的操作方式称为循环锁(spinlock)。

采用忙等方式进行同步显然很不合理,它不仅浪费了宝贵的 CPU 时间,降低了并

发性,如果使用不当,还有可能破坏程序的正确性。为解决此类问题,POSIX 提供了另

一种同步结构,条件变量( conditional variable),以及与其匹配的线程调用,

pthread_cond_wait 和 pthread_cond_signal。这种结构的语义并不复杂,对某个条件变量

而言,调用 pthread_cond_wait 的效果是将调用者阻塞在与该变量相关的队列里,而调用

pthread_cond_signal 的效果是将被阻塞的线程释放。我们在图 4.10 中给出利用条件变量

解决生产者与消费者问题的程序。 尽管人们对并发程序的同步与互斥问题作了深入的研究,但具体到应用,并发实体

之间的同步与互斥仍然是一个复杂而且容易出错的地方。如果并发实体仅限于顺序进

程,这个问题所带来的麻烦还不太大,因为顺序进程,尤其是 UNIX 一类系统的顺序进

程都有自己的独立地址空间,操作系统对进程空间施加严格的保护,故而一个进程的错

误不至于影响到其他进程。一旦引入多线程的概念,这个问题就变得非常严重。例如,

我们在本节中提到任一种互斥机制都应该设法满足三个基本要求,而 POSIX 提供的临

界区互斥机制就无法保证其中的第二点和第三点,即“防止外来干扰”和“防止饿死现

象”。是否能做到这两点的责任转嫁在程序员身上,这就要求编写多线程并发程序的程

序员具备较高编程素质,对计算机的内部结构和操作系统的实现有足够的了解,对并发

算法的原理及逻辑有完整的知识,只有这样才能编制出可靠高效的并发程序。

Page 45: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·79·

/* POSIX 生产者和消费者问题: producer_consumer1.c */ #include <pthread.h> /* 线程函数原型 */ void *producer_function(void); void *consumer_function(void); /* 初始化一个互斥锁和两个条件变量 */ pthread_mutex_t mylock = PTHREAD_MUTEX_IITIALIZER; pthread_cond_t w_consumer = PTHREAD_COND_IITIALIZER; pthread_cond_t w_producer = PTHREAD_COND_IITIALIZER; /* 线程共享变量 */ int flag = 0; char buffer; struct timespec dealy; main(){

pthread_t consumer; delay.tv_sec = 2; /* 设置 2秒时间延迟 */ delay.tv_nsec = 0; /* 创建 consumer线程 */ pthread_create(&consumer, NULL, consumer_function, NULL); producer_function(); /* main演变为 producer线程 */

} void *producer_function(void){

char x; while (1){ x = produce(); pthread_mutex_lock(&mylock);

while (flag == 1) /* 等待消费者信号 */ pthread_cond_wait(&w_consumer, &mylock);

buffer = x; flag = 1; pthread_mutex_unlock(&mylock); pthread_cond_signal(&w_producer); pthread_delay_np(&delay); /* 睡眠 2秒 */ }

} void *consumer_function(void){

char x; while (1){ pthread_mutex_lock(&mylock);

while (flag == 0) /* 等待生产者信号 */ pthread_cond_wait(&w_producer, &mylock);

x = buffer; flag = 0; pthread_mutex_unlock(&mylock); pthread_cond_signal(&w_consumer); consume(x); pthread_delay_np(&delay); /* 睡眠 2秒 */ }

}

图 4.10 生产者与消费者问题(条件变量算法)

Page 46: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·80·

4.2 客户/服务器并发系统

分布式系统中最常用的客户/服务器模型就是一种典型的并发程序,而且这类程

序大都包括有二级并发,即客户进程和服务器进程的一级并发,以及客户进程内和

服务器进程内多线程的二级并发。我们曾在第二章中讨论过客户/服务器模型的层次

逻辑,就具体实现而言,用户/服务器模型的实质是一个主动性进程和一个被动性进

程之间的交互,主动性进程发出请求称为客户,而被动性进程接收请求并提供服务

被称为服务器。 我们在本章中讨论的线程概念特别适用于客户/服务器模型的实现,尤其在服务器为

众多的客户提供相同或相关服务的场合下,只有利用线程才能达到最大的系统吞吐率和

最快的系统反应时间。设想一下,如果我们的服务器是由传统的顺序进程实现,那么当

服务器因为某个客户条件不完备而挂起时,就无法对其他的客户请求进行服务。同样,

如果一个客户程序亦由传统的顺序进程实现,那么当客户下载一个大文件时,就无法发

出其他的服务请求。虽然并发进程可以解决上述问题,但我们也讨论过并发进程在执行

效率方面的弊端。为了进一步了解如何使用线程进行分布式程序设计,我们在这一小节

中将比较详细地考察客户/服务器模型的具体实现方案。

4.2.1 客户软件

客户软件的实现涉及到两方面的因素:其一,客户软件所提供的用户界面;其二,

客户软件与服务器的交互。用户界面是客户程序代表远程服务器在用户(操作员)面前

所展示的界面,也就是说,用户通过这个界面可以知道远程服务器能够提供哪些服务,

并由此提交服务请求,而客户软件与服务器之间的交互则包括通信连接、功能分布、事

物处理、容错控制等模块在客户端的实现。

1. 用户界面

一般而言,客户软件所提供的用户界面都由图形用户界面(GUI,graphic user interface)实现。GUI 不仅为用户带来直观友好的视窗操作方式,也使得程序设计更为

灵活方便。传统的程序设计以(数据)控制流为主线,而 GUI 程序设计则以事件流为主

线。一个程序的控制流可以静态描述,而一个程序的事件流却是完全动态决定的。例如,

一个基于视窗界面的客户程序在视窗里提供了多个选择项,而用户用鼠标器点击哪个选

择项完全取决于用户当前的需要。这种动态引发程序执行的方式被称为事件驱动(event driven)程序设计。著名的 X 视窗系统和 JAVA 的 AWT 和 Swing 程序包都是基于事件

驱动的 GUI 系统。值得指出的是,GUI 系统无非是一种介于用户和程序之间的桥梁。对

客户程序来说,用户的基本动作就是引发事件,诸如击下键盘的某个键、移动鼠标器、

单击或双击视窗里的某个图素等;而它所能获得的信息也只有事件类型及与事件相关的

数据。一旦某个事件发生,系统自动地将事件信息传递到客户程序事先预备好的相应事

件处理程序,并自动地执行这个程序。概括地说,客户程序在 GUI 系统中经常使用事件

Page 47: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·81·

有下面几种类型: 1)鼠标器移动事件:用户把鼠标器在某个图素上移入/移出; 2)鼠标器选择事件:用户单击/双击鼠标器的某个按键; 3)键盘事件:用户按下或者释放键盘上的某个键; 4)视窗更新事件:用户要求显示一个被覆盖或者隐蔽的视窗; 5)重定尺寸事件:用户改变视窗的大小; 6)菜单事件:用户在系统定置的菜单中选择某个功能; 7)组合选择事件:用户利用鼠标器和键盘的组合做出多项选择; 8)开始/结束事件:用户通知系统执行初始设置或结束清除逻辑。 尽管 GUI 以图像方式提供用户界面,但并不意味着随意的设计就能使用户满意。要

想设计出一个对用户友好令用户满意的 GUI 界面,客户程序设计者不仅要掌握较高的程

序设计技巧,也要拥有较高水准的艺术细胞。这里我们给出几点设计参考: 1)了解用户:客户程序设计者必须了解用户的计算机知识水平和使用习惯。例如,

用户对专业术语是否有足够的理解?用户喜欢使用键盘还是鼠标器?用户希望采用图

素还是文字等。 2)简化常用服务:常用的服务应该尽可能地安排在明显的位置上,并且可以用最

简单的事件来引发服务。为了使用户能够快速地选择某个菜单中常用的服务,亦可设置

捷径键(shortcut key)。 3)为用户提供反馈:适当的反馈信息有助于用户对系统的理解并且防止潜在的错

误。例如,当远程下载一个文件时,如果系统发现下载文件比局部系统中的同名文件还

要陈旧,就必须给出提示,警告用户可能有潜在的错误,而由用户决定取舍。另外,如

果系统正在忙于处理,我们可以通过改变光标的图素来通知用户;如果某个处理时间较

长,我们可以显示一个信息窗并且给出工作进度;如果系统接收到重要事件,我们可以

用某种音响来引起用户的注意等。 4)保持一致性:作为一个用户界面设计者,既要有一定的创新,也要设法与其他

应用的界面保持一致,不可背离的太远。与界面一致性相关的成分包括语法、特殊的颜

色、图素所代表的对象以及菜单的功能分类。例如,人们通常用绿色代表连通,用红色

代表中断或阻塞;用打印机图素代表打印,用文件夹图素代表打开文件;把建立、打开、

关闭、删除等功能归在文件菜单中,而将剪裁、转贴、复制、置换、查询等功能归入编

辑菜单中等,这些都是用户界面设计者要注意保持一致的地方。 在图 4.11 中,我们给出一个 WS_FTP 远程文件传送客户程序的 GUI 例子,这个

用户界面以不同的事件驱动方式提供客户端和远程服务器端的服务。在图中,左边一

组选项给出局部文件系统的基本操作,如切换目录、重命名、删除等;而右边一组选

项给出远程文件系统的相应基本操作。局部和远程当前目录里的文件都同时显示在带

滑标的窗口里,用户可以用鼠标器选择一个或多个文件。一旦选定了所需传送的文件,

用户就可以点击中间的左右箭号执行下载/上传操作。显而易见,这个界面对用户很友

好,整个系统的现状一目了然,客户端和服务器端的功能清楚直观,系统所提供的服

务简洁易用。

Page 48: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·82·

图 4.11 WS_FTP 客户程序用户界面

2. 客户软件的透明性

提供友好的用户界面仅仅是实现客户程序的一个方面,另一个方面则是实现客户与

服务器的交互,以及在交互过程中如何隐藏各种细节,在用户面前尽可能地展现出透明

性。例如,为了保证高度的分布透明性,客户程序应该尽量地隐藏客户和服务器在因特

网上的通信延迟。目前因特网的通信速度依然差强人意,如果服务器坐落在相当远的地

理位置上,一次往返通信延迟可能会达到数秒。以网页浏览器为例,当我们访问一个很

长的文件时,全部下载也许会耗时若干分钟。假若我们用普通的进程实现,依次地建立

TCP/IP 连接,发送访问文件请求,等待文件传输完毕,然后再显示文件内容,这样的话,

用户一定会极不满意,那么我们怎样才能隐蔽这种由通信延迟所导致的长时间等待呢?

答案只有一个,编写并发客户程序。当客户程序从用户那里接到访问请求后,它可以立

即创建至少两个线程,一个用来和服务器建立联系,另一个用来分析并显示所获得的局

部文件。如果接收到的局部文件中还有其他 HTML 连接,如图像、音乐等,我们还可

以进一步创建更多的线程来对这些多媒体文件进行下载,所以用户可以很快地阅览所访

问的页面,聆听到伴随的音乐。尽管开始时用户会察觉到暂短的网络延迟,但一般用户

的阅览速度要比网络传输速度慢上许多,我们认为这种并发技术在某种程度上体现了系

统的分布透明性。 实际上,现今的网络浏览器都是多线程并发程序。当 HTML 主页被下载后,它立

即派生出多个线程下载网页中的各个部分。每个线程都分别地与服务器建立连接并索取

数据。如果线程系统可以发出阻塞性系统调用而不影响其他线程并发的话,每一个线程

的程序就非常简单,而且这些线程的功能也大致雷同。这种多线程连接的技术还有另外

一个潜在的优点,即当同一个网站有多台副本服务器时,客户端的多线程可能同时与多

台服务器进行交互,从而达到真正物理时间上的并发执行。 除了分布透明性之外,客户软件还要实现访问透明性,也就是说,无论远程服务器

基于何种系统(Windows NT 或 Linux),客户程序都要能够通过一个统一的接口,建立

Page 49: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·83·

与服务器通信的存根子程序;无论远程服务器以何种表达方式提供数据,客户程序都要

能够识别并隐蔽不同服务器在数据表达方式上的差异。位置透明性、迁移透明性以及重

定位透明性也是在设计实现客户软件时应该考虑的因素。位置透明性的关键在于对服务

的命名以及对名字的解析查询。简言之,服务(服务器)的名字越形象越有个性越好,

而对名字的解析与查询则越自动越隐蔽越好。以下载文件为例,有的服务器在其网页上

直接给出下载连接,用户可以很方便地点击这个连接,就可以自动地下载文件,根本无

须知道这个文件位于何处。在实现上,这种透明性无非是由客户程序创建一个线程,执

行一次类如 ftp 的操作而已。如果客户已经与某个服务器建立了连接,而这个服务器动

态改变它的位置,服务器就会及时地通知客户软件。设计完善的客户软件能够隐蔽这种

改变,自动地对服务或服务器进行重连接或重定位。 在设计客户软件时,我们还需要考虑如何对故障错误进行处理以及是否需要设置某

些安全措施,也就是说,如何在用户面前体现故障透明性和系统安全性。例如,当客户

试图与某个服务器连接时,由于服务器一端阻塞而一时连接不上,我们就应该在实现客

户程序时增加自动重复连接的功能。又如,当用户希望在网上进行电子交易时,客户端

程序就必须采用某种加密/解密算法以及纠错算法,藉以保证交易数据的安全可靠。总而

言之,一个理想的客户软件必须满足两个设计目标:其一,提供友好的用户界面;其二,

力图体现整个系统的透明性。

4.2.2 服务器软件设计

服务器是一个含义广泛的字眼,对任何一台计算机而言,只要为其他的计算机提供

服务,诸如文件共享、通信中转、远程计算等都可以称为服务器。而服务器软件则是一

个代表众多客户实现某些服务的进程,这类进程在本质上都具备相同的控制逻辑:被动

地等待来自客户的服务请求,调用相应的服务过程,给予客户回应,然后重复上述逻辑。

在设计服务器程序时,如何定义、保存以及管理客户/服务器之间的交互状态是一个非常

重要而且必须首先确定的问题。如果来自同一个客户的各种服务请求都是相对独立的

(与上下文无关的),则服务器程序可以设计成无状态(stateless)服务器。无状态服务

器无需保留客户的状态,诸如客户是否已经通过了安全检查、客户程序目前执行到什么

位置、用户已经提供了哪些信息等;而且当服务器自身改变状态时,也无需通知客户程

序。例如,网页服务器就是典型的无状态服务器,针对每一个 HTTP 请求,它只不过把

请求的页面文件发往客户,一经发出,它就把那个客户以及其状态忘得干干净净。 反之,如果客户的状态变迁影响到服务器所提供的服务以及服务期间两者的交互,

则服务器就必须是有状态(stateful)服务器。保留哪些状态完全取决于服务器所提供的

服务以及服务期间的交互过程,有的可以很简单,只要保存客户的当前状态以及服务器

所做出的相应状态变迁;而有的却相当复杂,不仅要保留当前状态,还需保留状态变迁

历史,甚至为每一个客户保留个人资料。例如,图 4.11 中远程文件服务器所保留的状态

就不会太复杂。简单来说,这个服务器只要保存一张客户/文件状态表即可,表中的客户

一栏代表已经通过安全认证的合法用户,而表中的文件一栏则代表服务器一端当前目录

以及文件选择(包括读/写权限)。有了这张状态表,服务器程序就可以针对来自不同客

户的请求,正确安全地提供文件的下载/上传服务。相比之下,提供电子商务的服务器就

Page 50: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·84·

必须保留不同类型、不同用途的客户状态。例如,著名的电子拍卖网站 Ebay 在与客户

的交往中,对注册的用户要进行安全认证,要保留用户对拍卖品的选择,在拍卖过程中

的竞叫等。而且,状态的保留不仅发生在用户在线联机的时间里,即便用户退出了系统,

服务器仍然为该用户设置一个代理,只要竞争者的报价没有超过该用户所定的最高价

位,这个代理就代表该用户做出一轮又一轮的加价竞叫;如果某个竞争者给出了更高的

价位,这个代理就会通知用户竞争失败。更有甚者,Ebay 的服务器程序还自动地为每个

用户建立个人文档,通过用户的访问历史来分析用户的兴趣、爱好、习惯乃至信用程度

等,并借助这种个人档案为用户推荐商品。 一经确定了服务器是否保留交互状态,我们就可以进一步考虑具体的实现。从实现

的角度来看,大致有两种服务器编程方法:循环顺序服务或并发服务。循环顺序服务程

序一般由一个顺序进程实现,它等待来自某个特定通信端口或者用循环探测的方法监督

一组通信端口的信件,用条件判别或开关语句来识别请求类型,调用服务过程并返回调

用结果,然后再回到等待信件的起点。并发服务程序由一组进程或线程构成,每一个进

程或线程都同时为客户提供服务。例如,在这组并发实体中,我们可以设定一个特殊实

体,专门用来接收来自网络的客户请求,根据请求类型把信件分配给其他的并发处理程

序,然后立即返回到接收信件的入口;而其他的并发实体则用来提供服务,它们的责任

就是执行服务程序并把执行结果返回给客户。 在前一小节的讨论中,我们看到多线程技术在实现客户软件时展现了优点和效益。

而实际上,这种技术的主要应用还是在服务器软件的实现领域里。实践证明,多线程技

术不仅大大地简化了服务器程序,而且使得程序员能够在最大程度上开拓服务器软件的

并发性,从而提高系统(无论是单机服务器或多机服务器)的效率。我们在图 4.12 中给

出几种常见的多线程服务器软件结构。图 4.12(a)称为中央分配结构,这类服务器软

件由一个分配器线程和若干个(固定个数的)服务线程组成。每一个服务线程都是长存

线程并且只完成一类特定的服务,它设置一个请求队列,队列里存放着由分配器转发的

客户请求,而该线程以循环的方式从队列里索取请求并提供服务。分配器线程监督来自

通信端口的客户信件,对客户服务请求作简单的类型分析,然后将客户请求插入到相应

的服务线程队列里。实现这种结构有一个问题需要注意,即在请求队列的入队/出队的操

作上一定要保证分配器线程和服务线程之间的互斥。显然,如果客户请求无论在时间上

还是在类型上都呈现出一致分布,则这种实现结构非常可取。反之,如果客户请求的时

间分布或类型分布很不均匀,只集中在某个时间区间里或只集中在某些服务类型上,相

应的服务线程就可能成为系统的瓶颈,我们就应该寻找其他的实现方法。 图 4.12(b)称为并发处理结构,在这种结构中,服务器为每一类服务都设定一个

通信端口,客户请求由通信系统导向相应的端口,而长存服务线程以循环的方式监督对

应的通信端口并提供服务。与第一种结构相比,并发处理结构减少了一层中央分配机制,

在某种程度上提高了系统吞吐率,但所付出的代价是对通信端口的管理与分配。由于每

一个长存服务线程在逻辑上类似于第一种结构中的服务线程,客户请求的一致分布也是

系统成功的基本要求。 表面上看,图 4.12(c)即中央调度结构,类似于中央分配结构,其实不然。在这

种结构中,我们没有长存线程,而是当中央调度线程接收到客户请求后创建暂存服务线

Page 51: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·85·

程。对每一个客户请求来说,都有一个专门的线程为其服务,一旦服务结束,这个服务

线程也就自动消亡。于是,同样的服务线程可能有多个并发的副本,只不过每个副本线

程面向不同的客户罢了。这种结构的优点是其灵活性,可以针对不同时间不同类型的访

问密集度来调节并发性,从而达到最大的系统吞吐率。可是,尽管线程创建的代价比较

小,但频繁的线程创建与消亡仍是一个不容忽视的系统开销,设计者必须注意这一点,

在灵活性和系统开销之间选择平衡。

分 配

线程 A

线程 B

线程 C

线程 D

线程 A

线程 B

线程 C

线程 D

线程 A

线程 B

线程 C

线程 C

相同线程

相同线程

调 度 线 程

(a) 中央分配结构 (b) 并发处理结构

(c) 中央调度结构 (d) 轮转调度结构 图 4.12 服务器软件多线程结构

图 4.12(d)称为轮转调度结构。与以上 3 种结构不同,这种结构里的线程是通用

服务线程,而非专门服务线程。此外,线程的个数亦可以固定,也可以随着系统访问密

集度变化而增加或减少。当这种服务器初始启动的时候,系统自动创建一定数量的线程,

叫做线程池(thread pool),池中的线程都到一个中央队列里轮流索取客户的服务请求。

如果得到服务请求,就分析请求类型,提供相应服务,然后又回到起点;如果当前中央

服务请求队列为空,则池中的线程便挂起等待。毫无疑问,我们还要有一个队列管理线

程,用以监督通信端口。但是,这个队列管理线程在功能上要比第一种结构中的分配器

线程简单得多,因为它对客户请求不做任何分析,只把客户请求插入队列即可。这种结

构的另一个优点是所有的服务线程都共享同一个程序,当系统增加线程池中的线程个数

时,无需从磁盘上装入新的程序,只要为新创建的线程分配一块栈区就可以了。有一点

需要特别指出,当编制这样的共享程序时,我们一定要保证程序的可再入性,也就是说,

这种程序的执行绝不能产生任何副作用。

Page 52: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·86·

近年来,一种特殊的服务器日益呈现出优越性,这便是对象服务器。顾名思义,对

象服务器是为分布式对象所建的服务器,与传统服务器相比,对象服务器本身并不直接

为客户提供任何服务,而只为其所管辖的对象提供一种运行环境,同时将远程客户请求

转换成局部对象调用。实际意义上的客户服务由分布式对象所实现,对象服务器的管理

者可以采集相关的对象构成不同的服务器,也可以方便地通过增加或删减对象来改变服

务种类。所以,在设计对象服务器时,我们的着重点不是如何为客户提供服务,而是如

何安全高效地管理对象。在实现对象服务器时,最简单的方案就是采用“一视同仁”的

策略,也就是说,我们把所有的对象都看成是等价的,因此可以用同一种方式来实现对

象调用。然而,这种策略欠缺灵活性,在某种程度上导致系统资源的浪费和效率的降低。

为了克服上述缺点,我们可以采用“区别对待”的策略,即根据不同对象的属性、用途,

把它们分划成长存对象和暂存对象。不难想像,长存对象应该是一直驻留在系统中的对

象,代表经常使用的各种客户服务;而暂存对象仅当客户调用时才创建,当无客户使用

时则消亡。由于暂存对象的生存周期仅与客户的调用相关,系统资源就不会无缘无故地

被占用或浪费;但其缺点是时间上的开销,暂存对象的调用增加了创建与消亡这两个操

作所需的时间。 另外,在编制对象服务器软件时我们还要考虑具体的实现方案,以及不同方案下引

发的同步、互斥、保护等问题。例如,当客户调用一个对象时,我们必须确定如何管理

对象的状态(数据)、如何执行客户所调用的对象方法、是否为每一个对象建立一个独

立线程还是为每一次方法调用创建一个独立线程等。对这些问题的回答并非是一个简单

的“是”与“否”,而需要经过详细的论证与试验。举例来说,如果我们仅为一个对象

建立一个独立线程,则该对象的执行状态自动满足一致性的要求,因为这个对象线程只

能以顺序执行的方式调用该对象所定义的方法;反之,如果我们为每一个方法调用建立

一个线程,则有可能多个线程同时对同一个对象施加运算或操作,这样做显然提高了系

统的并发性,但如何保护该对象的状态一致性就成了关键问题。 总之,就各种服务器软件的实现来说,我们没有一个“最好的”实现方案,不同的

方案各具所长,也各有所短。我们还是一句老话:“具体问题具体分析”,在效益与开销

之间谋求一种平衡。

4.3 软 件 代 理

进程和线程都是基于操作系统的并发实体,从应用的角度来看,这两种概念的抽象

层次较低(线程比进程还要低,因为线程是在同一个物理空间下的并发概念,而进程是

在同一个运行环境里虚拟空间下的并发概念)。基于这两种概念,程序员必须对操作系

统的结构及原理有足够的了解和全面的知识,才能编写出可靠、高效的并发程序。从这

种意义上说,进程和线程是面向系统的并发概念,而不是面向应用的并发概念。为了解

决面向应用的问题,人们引入了分布式对象的概念。当然,这种概念的抽象层次要比进

程/线程高级,但可惜的是,分布式对象仅代表并存实体而不是严格意义上的并发实体,

也就是说,分布式对象并不是一个运行中的程序,这种概念仍旧要借助于进程/线程这些

载体来实现并发执行。

Page 53: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·87·

那么,我们能否建立一种新的、高级的抽象概念,在这种概念下,并发实体所代表

的不再是某个特定系统中一组可以同时执行的控制流,而是开放系统中一组可以同时工

作“代理人”,这便是近年来一个非常热门的研究课题,软件代理(software agent)技术。

什么是软件代理?简言之,软件代理也是一个(执行中)的程序,是一个“协助人、代表

人来完成某个任务的程序”。也许有人会说,这岂不是故弄玄虚?哪一个程序不是人编

写的,不都是代表人的意愿吗?不错,进程和线程都是人所编制的程序,都代表人的意

愿,但是,人的意愿却在这些概念下受到限制,而产生限制的根源来自于它们赖以生存

的系统。例如,当我们准备外出旅游时,当然希望有一组程序能够协助我们在网络上寻

找最便宜、最便捷的飞机票,那么,如何用进程或线程来编制这样的程序呢?而若采用

软件代理技术,移动软件代理就完全可以胜任这个工作。再如,当我们设计一个电子商

务系统时,我们可能会面临大量的客户,分别代表“销售员”和“采购员”。而如果用

户不想亲自联网作业,只给出商品的价位、买进/卖出的数量、讨价还价的规则以及对不

同商家的信任度,然后派遣某个程序来代表自己参加交易的话,我们又如何用进程/线程

的概念来编制程序呢?毫无疑问,智能软件代理是这类应用的最佳候选者。 在这一小节里,我们将讨论软件代理技术。这是一个相对较新、相对活跃,故而也

颇有争议的科研领域。由于本书是教科书,而不是科研综述,我们试图避免那些混淆和

有争议的概念,只把一些成熟的概念和思想介绍给读者。首先我们讨论一下软件代理的

定义以及应用领域,其后讨论软件代理的一个重要分支:移动软件代理。像进程/线程一

样,软件代理也要借助于某种通信机制实现代理之间的交互和协同,我们还要介绍一下

相对规范化的软件代理通信语言。

4.3.1 软件代理技术

在软件代理技术的发展史上,恐怕最为“百花齐放、百家争鸣”的领域就是对软件

代理的定义。尽管我们在前文中曾给出一个简单的定义:软件代理是一个“协助人、代

表人来完成某个任务的程序”,但到底一个软件代理应该包括些什么,应该具备哪些特

征,以及软件代理的目的是什么,一直是长期以来争论的问题。根据 Jennings 和 Woolridge的定义,软件代理是一个自主(autonomy)程序,能够自行适应环境,对环境做出反应,

并且可能与其他代理或用户协同合作。大多数软件代理研究者认为这种定义描述了软件

代理最基本层面的特征,可以把这个定义看成软件代理的“弱”定义。 Lange 和 Oshima 却从不同的视角给出软件代理的定义。他们认为,从用户的角度

来看,软件代理就是用户所派遣的代表用户自身的程序;而从系统的角度来看,软件代

理是一个具备下列性质的软件对象: 1)必须能够适应运行环境。 2)必须拥有下述特征(必备特征): 反应(reactive):能够察觉环境的变化并能够根据变化做出及时反应; 自主(autonomous):能够自身决定行为控制,即自己管理自己; 目标驱动(goal driven):能够主动地实现目标并影响环境; 时序连续(temporally continuous):能够连续(长期)地执行。 3)可以拥有下述特征(可选特征):

Page 54: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·88·

通信(communicative):能够与其他软件代理交换信息; 移动(mobile):能够从一个环境(计算机)迁移到另一个环境(计算机); 学习(leaning):能够自动地吸取以前的经验并增长知识; 信任(believable):能够代表用户的意愿,为用户所信任。 除了上面的定义外,还有学者把软件代理的概念进一步扩展,提出智能软件代理的

概念。智能软件代理不仅要具备上述性质,还能够自动寻找资源、访问资源,自行解决

不同环境中的非一致性,自动筛选过滤不相干、不需要的信息,自动从不同的信息源截

取并合成所需要的结果,以及自动适合用户的需求。如果把这个定义形象化一点,智能

软件代理看上去像是一个模仿用户工作的“类人程序”。 迄今为止,人们对软件代理的研究主要侧重在人工智能(AI)系统上,试图用软件

代理的概念来解决 AI 中知识表述、自我学习、经验积累、逻辑推理等问题。换句话说,

人们希望把自己愿望和意图(desire and intention) 灌输给软件代理,从而达到“代理”

人的目的。例如,传统的知识系统及专家系统隶属于符号人工智能(SAI,symbolic artificial intelligence)的范畴,因为这类系统在进行推理时所采用的模式识别和符号操作

都是 SAI 的基本工具。对一个具体问题而言,如果我们具备“专家”级水平,而且这个

问题的知识覆盖面相对简单,人们对知识的掌握相对完善,则实现这样一个知识系统不

会太难。但如果我们面对一个复杂的问题、涉及多方面(而且不完备的)知识时,传统

的 AI 程序设计模型就显得力不从心了。而如果把软件代理概念应用于这个领域,人们

或许可以设计出相对简单的逻辑推理代理、定理证明代理、模式识别代理、信息检索代

理、知识学习代理等,通过这些代理的相互合作而达到解决问题的目的。虽然软件代理

有单代理系统和多代理系统之分,但目前真正实现的软件代理系统大都是多代理系统。

其间的道理很简单,多代理系统可以充分地利用计算机网络和并发技术,而单代理系统

无疑在效率上有个瓶颈在作祟。因此,我们在后面的讨论中所提及的软件代理系统都是

多代理系统。 软件代理是一个抽象概念,为了把抽象具体化,人们按照功能把软件代理划分成 3

类:任务代理(task agent)、界面代理(interface agent)和信息代理(information agent)。显然,任务代理就是用来完成人们指定的某个工作,它必须具备自主能力,在人们界定

的工作范围和规则下尽力地满足人们的意愿。为了完成一个大任务,人们可能会使用多

个任务代理,这些任务代理必须既独立又合作,通过彼此之间的通信交互,协同达到人

们所期待的目标。例如,会议安排就是一种典型的任务代理应用。在这种软件代理应用

中,会议的参加者都由一个任务代理所代表,这个代理能够访问用户的个人时间表和备

忘录,并且可以根据这些信息,如出差、会晤、作息时间等,与其他代理协商,做出会

议的时间安排,然后通知它所代表的会议参加者。在任何情况下,软件代理系统中直接

与用户打交道的是界面代理。界面代理的目的是协助用户使用各种不同的应用。界面代

理与通常 GUI 界面程序的显著不同之处在于学习能力,GUI 界面程序所提供的是一成不

变的用户界面,而界面代理可以根据学习到的知识和经验,为用户提供友好的协助。例

如,对电子商务用户来说,我们可以编制一种特殊的界面代理,它会根据用户以往的兴

趣、爱好、习惯,自动地在网上寻找用户喜欢的商品,自动生成用户界面,为用户比较、

分析、推荐商品。显而易见,任务代理和界面代理与信息代理之间存在着紧密的联系,

Page 55: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·89·

没有信息代理的协助,任务代理就很难做出正确的决策,界面代理就无法发挥其学习能

力。信息代理的主要任务是管理信息,这里面包括信息采集、分类、过滤、校对、筛选

等工作。常驻信息代理一般管理来自外部的信息,如电子信件代理能够自动把垃圾信件

从用户的信箱里删除,能够自动地把不同类型的信件分派到相应的子信箱里,甚至能够

对有疑问的信件(如可能携带病毒的信件)单独处理,在用户阅读信件时给出警告提示。

另一方面,移动信息代理可以在网络上漫游,根据用户的需求到处采集信息。例如,我

们前面提过的旅游代理就是信息代理的典型例子,它移动到不同的旅行社网站,根据用

户给出的旅行时间、出发点、目的地等基本要求,向所访问的旅行社服务器发出咨询(局

部数据库查询),最后回到用户计算机,把采集的票价、行期、时间等向用户汇报。 值得指出的是,虽然我们按照功能把软件代理划分成 3 类,但并不意味着这 3 类代

理必须营垒分明、各司其职。在实践中,一个软件代理可以既是信息代理又同时是任务

代理。例如,就上述旅游代理而言,如果用户不仅让它采集航班信息,同时也授权给它:

一旦信息采集完毕,就可以在用户指定的时间、价格范围内,选取最便宜的、安全信誉

最好的航空公司直接定票。这样的话,这个旅游代理就兼行信息代理和任务代理之责了。

4.3.2 移动软件代理

软件代理中一个非常重要的分支是移动软件代理(mobile agents)。移动软件代理技

术隶属于分布式系统这个大范畴,为这个大家庭里增添了一种全新的分布式计算模型。

概括地说,移动软件代理就是可以在网络上不同计算机之间自由迁移的软件代理。实现

这种技术关键在于程序迁移与接纳移动的程序:一个软件代理可以移动,但如何移动以

及迁移后如何恢复工作则是我们必须解决的问题;另外,软件代理必须被迁移后的目的

地所接纳,如果目的地计算机不提供这种软件代理的运行环境,迁移到那里又有何用,

迁移的目的又何在呢?鉴于此,我们必须用更确切的术语来描述移动软件代理模型。 首先,我们需要建立一类特殊的服务器,称为移动软件代理服务器。在前面的小节

里,我们曾讨论过对象服务器,其主要目的是管理对象。与此相仿,移动软件代理服务

器的主要功能是接纳并管理软件代理。而不同之处在于,前者基于客户/服务器模型,服

务器的动作被动地取决于来自客户的调用请求;而后者则是服务器/服务器模型,服务器

主动地执行所接纳的软件代理。也就是说,在移动软件代理系统中,我们完全丢弃了客

户的概念,移动软件代理的运行环境是开放(封闭)网络上的一组软件代理服务器。正

是由于上述理由,人们把软件代理划分为常驻软件代理和移动软件代理两大类。常驻软

件代理一直在启动它的那个局部运行环境里运行,如果需要与其他代理协同合作,只能

依赖系统提供的通信手段进行。而移动软件代理并不把自己局限在某个固定的软件代理

服务器里,它可以根据需要,在运行期间从一台服务器迁移到网络上的另一台服务器,

并且在迁移后的服务器上恢复运行。 从上面的讨论中,我们可以看出,移动软件代理的确是一种新颖的分布式系统模型。

那么,为什么需要这种模型?这种模型的初衷来自哪里?下面,我们来探讨一下这个问

题。抽象地说,无论各种各样的计算机应用如何五花八门、千奇百怪,其实质无非都是

对“数据”进行“运算”。在传统的单机系统中,数据和运算都处在同一个运行环境里,

程序(运算的体现者)直接对局部数据进行加工;而在分布式系统中,数据和运算却有

Page 56: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·90·

可能分散在不同的运行环境里,由此便产生了一个问题:我们是把数据移向运算呢,还

是把运算移向数据?为了回答这个问题,我们在图 4.13 中给出 4 种可能的运算/数据分

布模型,图中灰色方框代表不同的运行环境(网络计算机)。

运算 数据

部分运算 部分运算

数据

部分数据部分数据

运算 A 运算 B

运算 运算

数据

(a) 远程文件访问模型

(b) 客户/服务器模型

(d) 移动软件代理模型

(c) 分布式数据库模型

数据迁移

程序迁移

数据协调

远程调用

图 4.13 4 种可能的运算/数据分布模型

第一种模型,即远程文件访问模型,是典型的“把数据移向运算”,应用程序借助

于网络通信对远程数据进行加工处理。这种模型的优点在于灵活性,用户可以根据自

己的需要编写应用程序,可以对数据施加“任意”的运算。遗憾的是,如果应用程序

面临极大的数据量,而且其中的许多数据毫无用处,昂贵的网络通信开销就无法令人

容忍。因此,这类模型往往只适用于简单的文件上传/下载型应用,或者高速局域网的

文件共享应用。 为了减少网络上的数据传输量,客户/服务器模型采取了一种折衷的方案,把运算分

成两部分,界面程序迁移到用户一端,而服务器一端完成对局部数据的加工运算。这样

一来,网络负载明显减轻,在网络上移动的数据只有调用请求和调用后的结果。可是,

Page 57: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·91·

我们却失去了灵活性,用户无法按照自己的意愿编写应用程序,只能利用客户界面提供

的有限服务来实现对数据的操作。 毫无疑问,只有当数据和运算处在同一个运行环境里,应用程序才能达到最高的

效率。于是,分布式数据库模型把数据分布到不同的环境中,由分布在这些环境里的

程序对所分布的数据进行加工运算。然而,数据分布是个非常复杂的工作,假若在不

同环境都设置一个相同的数据副本,则我们就面临如何保证数据一致性问题;反之,

如果不同环境只分配一部分互不相交的数据,则我们就必须解决跨越环境的数据共享

问题。此外,这种模型也限制了用户的灵活性,应用程序只能在分布式数据库的封闭

范围内工作。 鉴于上述 3 种模型的利弊,人们产生了一种想法:“我们能不能把运算移向数据呢?”

如果可行,我们保证了用户的灵活性,用户可以按照需要编制各种应用程序。同样,我

们也在某种程度上保证了效率,因为迁移后的运算可以在一个局部环境里访问数据、处

理数据。再者,我们将面临一个开放的大环境,运算可以在网络上各个软件代理服务器

自由地移入移出,对不同数据库管辖的数据进行访问与处理。于是,我们有了第四种运

算/数据分布模型:移动软件代理。 Lange 和 Oshima 列举了 7 个理由来说明移动软件代理的重要性: 1)减少网络负载:分布式系统通常依赖于各种通信协议来实现并发实体之间的信

息交换,这样将导致大量的网络通信流量,甚至造成网络阻塞。而移动软件代理技术允

许频繁通信的并发实体移动到同一个服务器中,从而在局部环境下进行信息交换。此外,

移动软件代理技术也可以减少网络上原始数据的流量。当我们面对大量数据时,我们把

运算移向数据,而不是把数据移向运算。 2)克服网络延迟:实时控制系统(如工厂生产线的机器人)需要及时地对工作环

境做出反应。如果通过计算机网络进行控制,网络所导致的延迟往往会误事。而移动软

件代理技术提供了新的实时控制方案,我们可以把软件代理从中央控制器派遣到局部控

制器(机器人),在局部环境下实施实时控制。 3)密封通信协议:在分布式系统中,不同运行环境(计算机)都可能拥有自己的

特殊程序来实现通信协议。如果我们为了加强安全性或者为了提供效率而更新通信协

议,则所有运行环境里的协议程序都要重新设计,这无疑是一件非常困难而且代价很高

的工作。然而,采用移动软件代理技术就可以轻而易举地解决这个问题。我们只需要把

实现新协议的软件代理派遣出去,在不同环境中沟通新老两种协议,就达到了并发实体

在新协议下通信的目的。 4)异步独立自主:在无线网络或者移动通信设备环境里,通信连接不仅昂贵,而

且不太稳定。如果我们想在移动通信设备和固定网络之间一直保持连通,则既不经济划

算,也有技术上的困难。为了解决这类问题,我们可以把嵌在移动通信设备中的任务转

换成移动软件代理,一旦需要就把它派遣到网络上。一经迁移,这个代理就暂时脱离了

它的派遣者,成为因特网上一个异步独立自主的漫游者,而它的派遣者可以在稍后的时

间里将它召回。 5)动态适应环境:移动软件代理能够自动地感知其运行环境并且对环境的变化做

出反应。例如,当软件代理发现所处的服务器负载太高,就可以自动做出决定,迁移到

Page 58: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·92·

其他的服务器去。再如,如果某个软件代理发现所面临的数据量太大,就可以自动“克

隆”自己,从而提高并发程度。 6)自然适合异构:无论从硬件还是软件的角度来看,网络计算都呈现出异构性,

即网络上的计算机未必相同,机器上所配置的系统也各种各样。然而,移动软件代理一

般都独立于计算机,也独立于网络传输协议,只依赖于接纳它们的软件代理服务器,因

而可以说,移动软件代理技术为“无缝”系统合成提供了优越条件。 7)具备容错能力:由于移动软件代理能够对环境的变化做出迅速反应,一旦面临

异常事件或突发事件时,可以调整自身的决策,我们便能利用这种特征设计出具备容错

能力的分布式系统。例如,如果某个代理服务器要关机,则该机上运行的所有软件代理

可以在接到停机警告后的有限时间里,立即迁移到其他服务器去,然后在新的环境里恢

复运行。 从以上的讨论中我们可以看出,移动软件代理技术无疑为分布式系统增添了一种新

颖的计算模型,它比进程/线程概念高级,是一种开放网络的逻辑空间里的抽象并发概念。

目前已有相当多的移动软件系统在不同的院校和科研单位里运行,但这些系统大都属于

科研项目,而非商业化产品。我们知道,任何一种新思想,都有一个从幼稚走向成熟的

过程,移动软件代理技术也不例外。就这种技术而言,我们还有许多悬而未决或者值得

进一步深入研究的问题。例如,我们说移动软件代理技术的宗旨是“把运算移向数据”,

那么,如果当运算非常大(亦即程序代码很长)而数据量很小的时候,这样的迁移划算

吗?再如,随着因特网应用的日益普及,网络的安全性就显得格外重要。如果软件设计

者提供的应用能够确保安全性,人们才会放心地在网络上交换保密信息。然而,目前的

情况却并非如此,不要说网络上的通信尚不可靠,人们对网络上下载的程序都充满疑虑,

生怕这个程序会含有病毒或盗窃自己机器里的保密信息,甚至不敢轻易打开电子信件里

的附件,许多计算机病毒都是通过电子信件的附件传播的。那么,当人们面对移动软件

代理技术时,就更不放心了,没有安全保障,贸然接纳移动软件代理无疑是“引狼入室”。

此外,软件代理只是一种抽象的概念,我们必须提供某种程序设计语言来具体实现这种

概念。目前的移动软件代理系统大都基于传统的程序设计语言,如 Java,Python,Scheme,Tcl,Prolog 等,这些语言都是以虚机器或解释器作为运行环境,因为只有这样的环境才

能隐蔽网络上的异构性。然而,传统的语言及其实现方案未必完全适合移动软件代理的

思想,尤其在实现程序迁移上都存在着这样或那样的先天缺陷(我们将在下一小节详细

讨论程序迁移问题)。综上所述,尽管移动软件代理技术展示了众多优点,但要想把这

种技术真正投入应用,人们还有相当长的路要走。

4.3.3 软件代理通信语言

无论是通过共享内存还是计算机网络,分布式系统中的并发实体都要借助于某种通

信机制进行交互,藉以交换信息或达成同步,软件代理亦是如此。毫无疑问,常驻软件

代理之间只有通过通信才能相互协作,那么,移动软件代理呢?也许有人说,移动软件

代理总可以把自己移向数据,就没有必要进行信息交换了吧。事实并非如此,通信的目

的不仅仅是交换数据,也包括并发实体之间的同步,况且,面对小规模数据量的时候,

传输数据还是比程序迁移要经济合算。

Page 59: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·93·

既然软件代理之间的通信是必要的,我们就产生了下一个问题:软件代理之间用什

么样的“语言”来通信?语言是一种工具,人类的自然语言是人与人交流思想的工具,

同样,分布式并发实体之间也要借助某种语言来达到交流的目的。任何一种语言都包括

语法和语义这两个方面的定义,简单地说,语法是一组行文规则,而语义是对行文的解

释。不言而喻,通信双方所交换的信件必须遵守这组规则,也必须在如何解释信件内容

上达成共识。传统的进程/线程间通信语言非常简单,系统提供的通信原语只定义了最基

本的语法,即信件是一组给定长度的字节串,而对信件的语义没有任何定义,完全依赖

于通信双方的自行解释。 如果依旧沿用进程间的通信语言,就无法显示出软件代理面向应用的高级特征。我

们需要一种软件代理通信语言(ACL,agent communication language)来沟通软件代理,

使得它们能在不同环境下用一种彼此都理解的语言进行通信。近年来,人们力图将软件

代理之间的通信标准化,提出了若干 ACL,如知识查询管理语言(KQML,knowledge query and manipulation Language),知识交换格式(KIF,knowledge interchange format),以及 FIPA 软件代理通信语言(FIPA ACL)。这些语言都是陈述性(declarative)语言而

非过程性(procedural)语言,也就是说,是基于逻辑(如 Prolog 或 Lisp)而不是基于

过程控制(如 C 或 Java)的语言。例如,如果软件代理 A 向软件代理 B 询问是否教室

201 比教室 203 大,就可以利用 KQML 进行陈述性通信,如图 4.14 所示。

A to B: (ask-if ( > (classroom_201) (classroom_203) )

B to A: (reply true)

图 4.14 软件代理利用 KQML 通信的例子

从这个例子可以看出,高级通信语言不仅规定了语法,也对语义作出了适当的描述。

为了更充分地理解软件代理通信语言,我们再举一个颇为详细的例子,FIPA ACL。FIPA是由 70 多家著名的电讯、通信、计算机公司和科研机构组成的国际论坛,致力于软件

代理系统的标准化工作,其目的之一是使得所有 FIPA 兼容系统能够通过一种共同的

ACL 进行对话通信。根据 FIPA ACL 定义,信件应该包括两种成分:行为(performative)和内容(content)。行为代表一种目的或动作,而内容则给出达到目的或采取动作的具

体描述。我们在表 4.1 中列出几种典型的行为和内容定义。 从表中第一列我们得知,所谓行为无非是把各种信件的语义进行有限的、严格的分

类。例如,行为 INFORM 指出,按照命题演算逻辑,信件中的内容为真;至于发送软

件代理如何描述这个内容,接收软件代理如何处理这个命题却没有进一步的定义。虽然

FIPA ACL 没有指定内容描述语言,却给出了 ACL 协议数据单元(PDU)的规范格式,

这种格式类似于一种数据结构,可以包括一个或多个数据元素,诸如行为、发送者、接

收者、内容描述语言、具体内容等。我们在表 4.2 中列出 FIPA 抽象结构规范中定义的

抽象信件元素。

Page 60: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·94·

表 4.1 FIPA ACL 几种典型的行为和内容定义

信件行为 信件内容 解 释

INFORM 命题 告知所给定的命题为真

QUERY_IF 命题 询问是否所给定的命题为真

QUERY_REF 表达式 询问某个给定对象的指引元

PROPOSE 建议 给出一项建议

ACCEPT_PROPOSAL 建议标识符 告知所给出的建议已被接受

REJECT_PROPOSAL 建议标识符 告知所给出的建议已被拒绝

REQUEST 动作说明 请求按说明采取动作

CFP 建议说明 请求提供一项建议

SUBSCRIBE 资源引用 预定某个信息资源

表 4.2 FIPA ACL 信件元素定义

信件元素 元素类型

行为(performative) 动作类型

发送者(sender) 通信参与者

接收者(receiver) 通信参与者

回应送达者(reply-to) 通信参与者

内容(content) 信件内容

语言(language) 内容描述

编码(encoding) 内容描述

本体(ontology) 内容描述

协议(protocol) 会话控制

会话标识(conversation-id) 会话控制

回应索引(reply-with) 会话控制

索引式回应(in-reply-to) 会话控制

回应定时(reply-by) 会话控制

我们已经在前面讨论过什么叫做行为并且在表 4.1 中给出了典型的行为定义。行为

是所有 ACL 信件中必不可少的元素,而且 FIPA ACL 的开发者应该尽可能地使用表 4.1中的标准定义。发送者、接收者以及回应送达者都代表某个(些)具体的软件代理,代

表的方式可以用名字,也可以用标识符。大多数 ACL 信件都含有发送者元素,仅当发

送者企图发出匿名信件时才可以缺省。同样,接收者也是信件的基本元素,除非我们能

够从信件内容中可靠地推演出接收者的名字,这个元素才能缺省。接收者可以是一个

软件代理的名字,亦可以是一组软件代理的名字,显然,后者对应于组播通信,即发

送者希望把信件传送给所指定的一组软件代理。在发送者和接收者会话期间,如果发

送者不想得到回应,而是希望把回应导向另一个软件代理时,就可以在信件中给出回

应送达者的名字。

Page 61: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·95·

顾名思义,内容就是信件中的行文,也可以被视作施加行为的对象。大多数 ACL信件都需要包含某种内容,否则通信变得没有意义。但如果从某一些 ACL 信件类型中

可以辨别出隐含的内容,就可以省略内容元素。信件的内容是通过某个语言来描述的,

FIPA ACL 并没有定义统一的内容描述语言,而是由程序设计者通过语言这个信件元素

来指明,而且内容描述语言一般都采用形式语言。当然,如果通信双方都明确地知道所

使用的语言,这个信件元素便可以缺省。虽然内容用语言来描述,但体现这种描述的方

法是编码技术。因此,一封 ACL 信件的内容可以用指定的编码方式来编码/解码,也可

以用缺省的方式进行。为了帮助接收者对信件的理解,我们可以通过本体元素指出信件

内容的大致含义或者语义范围。例如,如果信件内容说“某人是某人的父亲”,本体元

素就定义为“家谱”。本体元素一般与语言元素联合使用,用来支持接收者对信件的翻

译。如果信件中没有语言元素,本体元素也就毫无意义。古人说:“皮之不存,毛将焉

附”?语言和本体就是个“皮”与“毛”的关系。 当发送者要采取某种交互协议进行通信时,就在信件中给出协议元素。使用这种元

素要格外小心,因为协议的建立是一件非常困难复杂的任务。有时,为了使一系列信件

构成一次对话,我们可以引入会话标识元素。例如,如果某个软件代理同时与多个其他

代理通信时,就可以用会话标识来区分来自不同代理的对话信件,也可以用这个会话标

识来分析会话的历史记录。与此相仿,为了区别来自不同代理的回应信息,发送者可以

给出回应索引,而接收者在返回回应时就必须附上索引式回应。此外,发送者还可以对

接收者做出时间要求,通过回应定时这个信件元素指定一个时间/日期表达式,要求对方

在指定的时间内做出回应。 根据上面的讨论,我们可以用 FIPA ACL 的信件来展示图 4.14 中软件代理利用

KQML 通信的例子,假定通信双方所使用的语言是逻辑程序设计语言 Prolog,则 A,B两个软件代理通信的信件如图 4.15 所示。从这个例子可以看出,软件代理通信语言是把

高级的、规范的、形式化的语言引入分布式系统通信机制的一种可喜尝试,为软件代理

技术的深入研究和普及应用奠定了基础。而另一方面,就像软件代理技术尚未完全成熟

那样,软件代理通信语言也存在着许多悬而未决问题,有待于进一步的探讨与开发。

行为 QUEPY_IF

发送者 A

接收者 B

语言 Prolog

内容 greater(classroom_201, classroom_203 )

行为 INFORM

发送者 B

接收者 A

语言 Prolog

内容 true

图 4.15 软件代理利用 FIPA ACL 通信的信件例子

4.4 程 序 迁 移

在前面的章节里,我们讨论分布式通信时所涉及到的对象都是简单数据,然而,现

代分布式系统中在网络上传送的对象几乎是任何可以数字化、信息化的东西,包括影视、

音乐、图形乃至程序。那么,什么是程序呢?这个问题似乎有些过于简单,按理说,凡

Page 62: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·96·

是学计算机的人都能马上给出回答,程序就是用某种程序设计语言编制的一段可执行代

码。但细细一想,这个回答还真值得再推敲一下。譬如,WWW 网页是 HTML 语言所

书写,那么,一段下载的网页算不算程序?也许有人说,网页不算程序,因为 HTML只是一种格式描述语言,它所定义的上下文只代表文本数据及其显示格式,而非可执行

程序。这样的话,我们朝前进一步,如果网页中除了 HTML 定义之外,还含有由某个

脚本语言(如 JavaScript,VBScript,ASP,Tcl/Tk,CGI 等)所书写的代码,浏览器对

这些代码解释执行,从而实现用户与浏览器、服务器的简单交互,这类网页可以算作程

序吗?如果还有争议,我们索性再进一步,假若网页中还嵌有对 Java 编制的 APPLET调用,浏览器中的 Java 虚机器(JVM)自动地下载并且执行 APPLET 代码,这总该算

作程序了吧? 大多数程序设计教科书中都采用一个早期的定义:“程序是用来完成某个特殊任务

或者解决某个特定问题的一组计算机指令”。然而,如今许多的“程序”却并非全以计

算机指令的形式出现,它们的执行方式也大相径庭,有的对源代码解释执行,有的把源

代码翻译成特殊代码由一个称为虚机器的软件执行,也有的把源代码编译成计算机指令

由硬件直接执行。因此,我们认为更为确切的定义应该是:“程序是用来完成某个特殊

任务或者解决某个特定问题的一组行为描述、逻辑定义或者控制命令(指令)”。浏览器

可以执行 HTML 网页中的格式定义,故网页是相对于浏览器的程序;Java Script 解释器

可以理解并且执行 JavaScript 编制的脚本,故这种脚本是相对于 JavaScript 解释器的程

序;JVM 可以执行经过 Java 编译系统产生的字节代码,故 Java APPLET 是相对于 JVM的程序;以此类推,不同语言书写的程序都对应于某个能够理解并执行这类程序的运行

环境,而这种运行环境可以是硬件,也可以是软件(即另一种语言编制的程序)。 不同的语言有不同的表达能力,有的很弱,只能作简单的格式描述,而有的很强,

可以进行系统程序设计。即便是针对同一个语言的运行环境,也可能对不同类型的程序

施加不同的功能限制。例如,Java 是高级的通用程序设计语言,但 Java 编制的 APPLET和 Application 相比就有许多功能上的限制,如 Application 可以在 JVM 的完整运行环境

中工作,但 APPLET 只能在 JVM 的一个沙盘(sand box)里执行,任何超出安全所许可

的功能(如局部文件访问)都被严格禁止。此外,如今的许多程序也并非只由一种语言

编制。众所周知,现今的 WWW 浏览器都体现了一个综合运行环境,它可以接收 HTML程序、脚本程序以及 Java APPLET。为何我们要费这么多的口舌讨论什么叫做程序,这

是因为在本章中我们将要探讨分布式系统中的一个重要概念——程序迁移。只有理解了

什么叫做程序,才能简洁清楚地讨论各种程序迁移模型以及在实现程序迁移时所要注意

和解决的问题。

4.4.1 程序迁移模型

顾名思义,程序迁移(program migration)指的是把一段(静态的或运行中的)程

序从一个运行环境(计算机)移动到另一个运行环境(计算机)中,使得该程序在新环

境里开始(或继续)运行。程序迁移技术起源于早年分布式系统科研中的两个重要课题:

其一,当一个分布式计算应用面临多台计算机(处理器)时,系统如何调度、分派众多

的并发进程,使得每一台机器上的负载达到平衡;其二,当某台机器发生故障时,系统

Page 63: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·97·

如何把该机器上的进程转移到其他机器上,从而保证系统的故障透明性。显然,解决上

述问题的进程迁移技术一般只适用于同构计算机,而且这些计算机都由一个大运行环境

(分布式操作系统)所管理。同时,进程迁移的目的也很直观:提高系统效率以及加强

系统容错能力。 随着对分布式系统研究的深入,人们发现进程迁移技术不能满足各种分布式应用模

型的需求,而且“迁移”的目的也不仅仅局限于效率和容错能力。例如,在浏览器/服务

器模型中,用户知道“做什么”,却不知道“怎样做”。“做什么”代表用户的需求,而

“怎样做”则是程序的任务。为了在浏览器一端实现部分的“怎样做”,我们就必须把一

段程序“请”进来。又如,在上一小节讨论的移动软件代理模型中,用户不仅知道“做

什么”,也知道“怎样做”,然而,为了在远程数据上实现“怎样做”,我们就必须把一

段程序“送”出去。于是,早年的进程迁移概念被延伸,分布式系统中可以移动的不再

是狭义的进程,而是广义的程序。 为了方便下面的讨论,我们需要定义几个涉及程序迁移技术的术语。首先,我们需

要申明这里所谓的程序不只是静态程序,而且包括运行中的程序,也就是说,一个程序

可以是一个网页、一个脚本、一个 Java APPLET、一个进程或者是一个软件代理。因此,

一个程序可能会含有 4 种成分: 1)代码:可以被运行环境执行的一组语句或指令。大致上,代码可以被分成 3 类:

① 源代码(source code),即没有经过任何加工处理的源语言代码,其运行环境一般是

该语言的解释系统;② 字节代码(bytecode),即源代码通过翻译所形成的中间代码,

其运行环境一般是该语言的虚机器;③ 二进代码(binary code),即源代码通过编译系

统产生的二进制机器指令,其运行环境是某类特定的计算机。 2)数据:代码所操作的一组对象。程序尚未执行时的数据称为初始数据,而运行

期间的数据称为中间数据。当我们不需要强调执行状态时则泛称数据。 3)资源:程序运行时所需要使用的一组外部软硬设备,如打印机、磁盘、文件、

数据库、URL、通信端口等。 4)执行状态:程序迁移发生时对运行环境的快照(snapshot),包括程序计数器、

通用寄存器、栈指针、栈中内容等。如果在迁移时程序尚未开始执行,则其执行状态只

是该程序的启动入口。 实践中,不同的分布式应用可能会需要不同程度的程序迁移,不同的运行环境由于

条件限制只能实现某类程序迁移,为了不失一般性,我们在表 4.3 中归纳出 3 种常用的

迁移技术,分别为原始迁移(primeval migration)、弱迁移(weak migration)以及强迁

移(strong migration)。在多数讨论程序迁移技术的文献中,只列举了其中的两类,即弱

迁移和强迁移1)。但我们发现,有一类迁移技术在浏览器/服务器模型中很为流行,因此,

根据这类迁移技术的特征,我们将其称为原始迁移。同时,根据前面给出的程序成分术

语定义,对每一种迁移技术我们明确地指出所要移动的对象,以及当程序迁移成功后,

系统从哪一点开始执行程序。

1)有些文献中关于弱迁移和强迁移的定义仅针对移动软件代理,而忽略了广义上的程序迁移技术及分类。

Page 64: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·98·

表 4.3 3 种常用的程序迁移技术

迁移模型 迁移对象 迁移后执行方式

原始迁移 代码、初始数据 系统从起点开始执行

弱迁移 代码、中间数据、执行标志 系统从起点开始执行,而用户程序需要通过判别执行标志转移回到继续点执行

强迁移 代码、中间数据、执行状态 系统自动从继续点执行

从表中我们可以看到,3 种迁移技术的本质区别在于所移动的对象以及移动后的程

序启动点。原始迁移技术有时也叫做代码迁移,或者叫做静态程序迁移,即我们仅把程

序的代码及其初始数据从一个运行环境移动到另一个运行环境中,然后从该程序的原始

状态开始执行。例如,网页(包括脚本)程序以及 Java APPLET 的迁移都属于原始迁移

的范畴,同样,许多系统的更新或“打补丁”所下载并执行的程序亦属于这个范畴。原

始迁移技术的优点是实现起来非常简单,一般适用于浏览器/服务器模型。每当浏览器一

端需要某种程序来实现“怎样做”的时候,就可以从服务器那里索取一段特殊代码来帮

助用户完成与服务器的交互工作。 与原始迁移技术不同,后两种迁移技术都涉及到运行中的程序,也就是说,被迁移

的程序正在工作,它可能已经完成了部分任务,还有一部分工作尚未完成。那么,是什

么原因使得一个正在执行的程序发生迁移呢?我们认为,原因可以归纳为两类:其一,

由于某种系统决策,诸如负载平衡或者容错处理,系统把某个运行中的程序强制中断,

从一个运行环境移动到另一个运行环境中,即程序被动地迁移;其二,程序本身具备自

主能力和决策能力,它在执行期间发现需要转移运行环境,诸如在网络上漫游以寻找适

当的服务,于是调用系统提供的迁移原语,即程序主动地迁移。早期的进程迁移技术大

都属于被动式迁移,而如今的软件代理迁移技术大都属于主动式迁移。与原始迁移技术

相比,迁移一个运行中的程序要复杂得多。一方面,我们必须完整无误地迁移程序代码

和中间数据;另一方面,我们还要保证程序在迁移后,能够从正确的继续点(continuation point)恢复运行。对被动式程序迁移而言,其继续点是被迁移所中断的下一条指令(语

句);对主动式程序迁移而言,其继续点是紧接在迁移原语之后的那条指令(语句)。 毫无疑问,要想在迁移后的新运行环境里恢复程序运行,我们必须首先恢复该程序

的执行状态。如何保存、传送以及恢复一个程序的执行状态?这正是弱迁移和强迁移这

两种方法的本质区分所在。从常识上说,要想在迁移后恢复一个程序的执行状态,就必

须在迁移前保存这个程序的状态,并且把保存的执行状态随同程序的代码和数据一起传

送到目的地。完全不错,我们所谓的强迁移技术正是这样做的。然而,有一种论点认为,

恢复一个程序的执行状态未必一定要保存程序迁移前的执行状态,只要我们能够迁移代

码、中间数据以及一些执行标志,那么在迁移后,这个程序从头开始执行,通过对执行

标志的判别,寻找到迁移后的继续点就可以了,这便是我们所谓的弱迁移。 人们之所以提出弱迁移,并不是因为这种技术具备什么优点,而是因为在实现程序

迁移中所遇到的障碍而不得不采取的权宜之计。我们在前面提到,几乎所有的移动软件

代理系统都采用主动性程序迁移技术,而且大多数的移动软件代理系统都以 Java 作为程

序设计语言。可惜的是,Java 所支撑的程序设计模型面向对象而不是面向软件代理,因

此不可避免地有一些先天不足。例如,Java 的运行系统 JVM 并不支持对执行状态的保

Page 65: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·99·

存与恢复,与执行状态有关的信息,如程序计数器、通用寄存器、运行栈等都是不容任

何用户程序所访问的禁区。于是,当一个移动软件代理要迁移的时候,只能利用 Java提供的对象序列化(object serialization)方法,把该软件代理及其拥有的对象、用户信

息、原地址、代码等,转换成一个字节数组,当把这个数组传送到目的地之后,再调用

一个序列逆转(deserialization)过程将该软件代理恢复。遗憾的是,由于所迁移的信息

中不包括执行状态,该移动软件代理要想在迁移后恢复运行,就必须从头开始,依赖于

迁移前所设置的特殊标志,寻找程序的继续点,从那里恢复运行。为了使读者更清楚的

理解强迁移和弱迁移之间的不同之处,我们在图 4.16 中给出了两个移动软件代理的框

架,其中 move_to(A)表示软件代理在当前的运行环境里调用迁移原语,尾端带黑点

的实箭号线代表程序迁移后的正确继续点,强迁移和弱迁移的差异则一目了然。

强迁移示意:

move_to(A);

(从继续点恢复) 继续点

弱迁移示意: (从头开始/恢复)

if (not moved){

moved = true;

move_to(A);

}

else{

继续点

}

图 4.16 强迁移和弱迁移程序示意

从图中的程序框架我们看出,弱迁移技术显然有些不尽人意,程序迁移的透明性较

差,程序员必须在编制软件代理程序时增加额外的判别语句,这不仅使程序的可读性差、

程序逻辑变得复杂,而且程序在迁移后要浪费时间寻找继续点。试想一下,如果一个软

件代理要在数十台、数百台服务器里自由移动,你该如何编写这样的软件代理呢? 由此可见,强迁移技术应该是所有涉及程序状态迁移的分布式系统中最佳候选者。

然而,实现强迁移却并非易事,除了需要迁移并恢复程序的代码及中间数据外,我们还

必须完整地迁移并恢复程序的执行状态。其间的关键是如何快照、保存、恢复执行状态。

快照指的是在哪一刻“冻结”要迁移的程序,即停止当前的程序运行,使得该程序处于

静止状态;保存指的是如何把静止的程序状态按照某种格式打成信件包,其中包括寄存

器信息、运行栈集结(stack marshalling);而恢复则意味着在目的地分配新的存储空间,

把寄存器和运行栈还原(stack unmarshalling),然后从恢复后的程序计数器启动程序。 由于程序呈现多样性,强迁移技术的实现方法也根据程序的特定运行环境而有所不

同。例如,进程在操作系统的管理下由硬件直接执行,当进程迁移时,我们所面临的代

码是机器指令,所面临的寄存器是真正的硬件寄存器;而当我们的程序是基于某个虚机

器或者某种解释系统的软件代理时,程序迁移所面临的代码就是一组字节代码甚至源程

序,而所谓的寄存器就可能是一组变量所代表的软寄存器,所谓的程序计数器就可能是

Page 66: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·100·

一个字节代码指针或者是源程序中的语句计数。此外,迁移环境是否同构也极大地影响

到实现的复杂性,很难想像一个 PC 中的机器指令程序能够迁移到 SUN 工作站去运行,

除非在 SUN 工作站里安装一套 PC 机的模拟程序。正因为如此,现今的移动软件代理系

统都构筑在同构虚机器或解释系统的运行环境之上,从而隐藏网络上的异构计算机,为

软件代理提供一个可以自由移动的虚拟网络空间。 另一种程序迁移分类方法以程序移动的方向为标准,即程序被“请进来”还是“走出

去”。如果把一段程序送出去,则称为发送者引发(sender-initiated)的程序迁移;反之,

如果把一段程序请进来,则称为接收者引发(receiver-initiated)的程序迁移。就发送者引

发的迁移而言,被迁移的程序位于发送者的运行环境中,如一个进程被动地从当前计算机

迁移到网络上的另一台计算机,或者一个移动软件代理主动地把自己从当前服务器迁移到

网络上的另一台服务器,亦或者一个客户软件向服务器上传一段程序并希望该程序在服务

器一端执行等都属于这个范畴。相反,接收者引发的迁移是由接收者主动发出邀请,从远

程计算机或服务器索取一段程序,然后在接收者的运行环境中启动,如我们前面讨论过的

网页调入(如果我们把网页视作广义上的程序),执行 APPLET,或者下载自动更新程序

等。因此,有的文献将接收者引发的程序迁移称为按需调入代码(code on demand)。结

合我们前面讨论的 3 种程序迁移技术,读者可以看出,由发送者引发的程序迁移囊括原始、

弱以及强迁移 3 种技术,而由接收者引发的程序迁移一般只涉及原始迁移技术。

4.4.2 程序迁移中的资源管理

细心的读者可能已经发现,当我们定义一个(运行)程序的成分术语时,我们列举

了 4 种成分,即代码、数据、资源和执行状态。当我们讨论程序迁移技术时,却没有考

虑资源,也就是说,我们尚有一个遗留的问题:一个程序的资源是否也应该随着程序的

迁移而迁移?可以说,这是在实现程序迁移时最令人头痛、最为复杂的问题。毫无疑问,

有些资源是根本无法迁移的,如 CPU、内存等,而有些资源是可以迁移的,如 URL、动态库程序等。在无法迁移的那类资源中,有的可以在迁移后重新分配,如内存,我们

只要在恢复程序状态时完成从旧空间到新空间的地址影射就可以了。但有的却无法进行

简单的重新分配,例如,假定一个程序拥有一个特殊的 TCP 端口,通过这个端口与其

他程序通信,那么,当这个程序迁移后,它可以重新申请一个新的 TCP 端口,但又怎

么才能使得其他程序都知道呢?为了充分理解各类资源在程序迁移时所扮演的角色和

不同的管理策略,Fuggetta 等人提出了 3 种区分程序对资源的绑定类型:标识绑定

(binding by identifier),值绑定(binding by value),以及类型绑定(binding by type)。

1. 标识绑定

程序用标识符或名字来引用资源称为标识绑定,这是 3 种绑定类型中最强的一类资

源引用方式,也就是说,无论这个程序迁移到哪里,都自动地隐喻着携带该资源,都可

以用这个标识来引用资源。例如,如果一个程序使用某个 URL 来访问网站、或者使用

某个 IP 地址来访问远程文件服务器,则该程序可以携带这类资源绑定一同迁移,而迁

移后丝毫不影响对这类资源的使用。然而,如果程序用标识绑定的资源是一个局部资源,

如 TCP 端口,则在迁移后就要采取较为复杂的资源恢复策略。

Page 67: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·101·

2. 值绑定

值绑定指的是程序仅对资源的“值”感兴趣,因此,如果迁移后的运行环境能够有

同样的资源来提供所需要的“值”,就不会影响到程序迁移。例如,一个基于某种语言

的软件代理在运行时需要调用标准库程序,其绑定方式就属于值绑定,因为只要该软件

代理所迁移的运行环境里安装有标准库程序,我们就可以假定该软件代理携带着所需要

的资源一同“迁移”了,然而,与标识绑定相比,值绑定就相对较弱,其间的道理很简

单,标识绑定对迁移后的局部运行环境没有任何要求,而值绑定却依赖于迁移后的运行

环境能够保障所需要的资源。

3. 类型绑定

最弱的一种资源绑定是类型绑定,即程序仅仅指出所需要的特定资源类型,例如,

程序所引用的打印机、显示器等都属于此类。不言而喻,这类资源是不可能随着程序而迁

移的,即便采用重新分配策略,也会有一些克服不了的副作用。试想一下,一个程序在当

前的打印机上输出了几行数据,然后迁移到另一个运行环境,重新绑定到另一台局部打印

机,这样的话,打印输出就变得七零八落;再如,一个程序在当前的显示器上开了一个视

窗,然后迁移到一台新机器,则不仅在原来的环境里遗留了一个“垃圾”,而且在新的环

境里显示的杂乱无章。因此,大多数支持程序迁移的系统,尤其是移动软件代理系统,都

不允许可迁移的程序绑定到这样一类的资源。 在程序迁移时,尽管我们可以允许程序改变对资源的标识,如从一个名字改变成另一

个名字,但我们却不可能改变程序对资源的绑定属性,即如果某种资源是按值绑定,则

无论怎样换名,它还是按值绑定的资源。 除了程序对资源的绑定类型之外,我们在讨论资源迁移时还要考虑到资源对计算机

(运行环境)的依赖关系。第一类称做非隶属资源(unattached resource),它的存在与具

体的计算机毫不相干。由于这类资源并不隶属于任何机器(运行环境),我们可以容易

地实现资源迁移。在本书的前几章中,我们曾把数据也看成是资源。不错,数据确实是

一种资源,但有的数据,如程序携带的数据,应归类于非隶属资源,而有的数据,如数

据库管理的数据,就不算作此类。事实上,当我们讨论程序迁移时,我们已经把一个程

序数据当成程序的组成部分(而非计算机的隶属资源),随着程序一同迁移了。第二类

称为紧致资源(fastened resource),这类资源可以随着程序一同迁移,但代价很高。例

如,如果程序绑定到一个局部数据库,这个数据库就是当前运行环境的紧致资源。当程

序迁移时,我们可以不惜一切代价把这个数据库全盘拷贝,随着程序一起传输出去,但

这样做的开销令人咋舌。所以,虽然在理论上紧致资源可以被松绑(脱离其运行环境)、

可以被迁移,但实践中这种迁移的可行性几乎不存在。最后一类资源对环境的依赖称为

固定资源(fixed resource),这类资源与其运行环境合为一体,根本不能迁移。 综合我们讨论的 3 种程序/资源的绑定类型和 3 种资源/环境的依赖关系,我们在实

现程序及其资源迁移时,有 9 种组合需要考虑,对每种组合都有不同的管理策略,如

表 4.4 所示。表中枚举了不同情况下的资源管理策略,其中括号外的策略为首选,而括

号内的策略为候选。迁移和重分配这两种策略的含义很明显,我们就不再赘述。全局策

略表示把资源设置成一种全局共享资源,程序迁移不会影响到全局资源,可以在任何环

Page 68: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·102·

境中使用。实际上,我们前面提及的网页 URL 和远程文件服务器的 IP 地址都属于此类。

但实现资源全局化并不如想像的那么简单,例如,当程序绑定到一个局部 TCP 端口时,

我们如何使得这个资源全局化,该程序在迁移后仍旧能与其他程序通信呢?解决的方案

有两种,其一,我们可以在迁移前的环境中设置一个通信转发代理,任何来自该 TCP端口的信件都被转送到程序迁移后的目的地;其二,迁移者向所有的通信程序广播“更

改”通信端口信件,藉以建立新的“全局”共享资源。

表 4.4 程序迁移中不同的资源分类及其管理策略

非隶属资源 紧致资源 固定资源

标识绑定 迁移(全局) 全局(迁移) 全局(禁用)

值绑定 拷贝(迁移、全局) 全局(拷贝) 全局(禁用)

类型绑定 重分配(全局、拷贝) 重分配(全局、拷贝) 重分配(全局、禁用)

由此可见,具体情况不同,全局资源策略的实现方法也大相径庭,有的很简单,有

的却涉及复杂的算法和昂贵的开销。拷贝策略包括两类情况:迁移后的环境中保证有同

样的资源存在,否则,必须在迁移前复制这类资源,随同程序一同移动。当然,后者的

系统开销太大,在实践中几乎无人采用拷贝/迁移策略。 最后也是最简单的资源管理策略就是禁用,即不允许程序绑定到这类资源。禁用的

原因有两种:第一,无法迁移、无法复制、即便重分配也无法消除使用资源的副作用;

第二,系统的安全性可能会受到威胁(如局部磁盘存储器)。然而,只有在万不得已的

情况下才能采取禁用策略,因为这种策略破坏了资源共享的透明性,也损害了应用程序

的灵活性。

习 题

4.1 比较一下用户级(用户空间)线程和系统级(内核空间)线程之间的优点,比

较的重点如下:效率、可移植性、调度以及同步互斥。 4.2 我们在图 4.8 的例子中指出,并发线程 T,S 一共有 20 种合法的指令执行序列。

我们是如何得出这个结果的?如果线程 T 由 M 条指令组成,而线程 S 有 N 条

指令,请给出计算合法的指令执行序列的通用表达式。 4.3 两个生产者线程(P1,P2)和两个消费者线程(C1,C2)共享一个栈。所允许

使用的栈操作是推入(PUSH)和弹出(POP)。显然,线程必须以互斥的方式

访问栈中数据。如果我们规定消费者Ci仅能从栈顶移出生产者Pi存入的数据,

请用线程互斥机制编写程序。 4.4 用进程编写上面的生产者/消费者问题,比较一下线程/进程方案的运行效率。 4.5 进程同步和进程间通信有什么关系?我们能用进程同步机制实现进程通信吗? 4.6 控制多线程对共享文件的读/写是一个古典互斥问题,即 reader/writer 问题。在

没有 writer 正在进行写操作的情况下,多个 reader 可以同时执行读操作;而当

某个 writer 访问该文件时,必须严禁其他的线程以任何方式进行读/写操作。

编写一个通过互斥机制解决该问题的线程程序,注意,在程序的算法上,要力

图防止“饿死”现象。

Page 69: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第四章 并 发 计 算 ·103·

4.7 客户/服务器模型的优点是什么?缺点是什么?局限性是什么? 4.8 假定我们已经有一个“聊天室”服务器,用某种支持 GUI 的语言编制一个“聊

天”的客户界面。 4.9 如果让你设计一套“聊天室”服务器软件,你将采用哪一种服务器实现方案?

请详细陈述选择的理由,并给出初始设计框架。 4.10 考虑一个文件服务器模型,如果文件数据保存在缓存(cache)中,该服务器

平均每 15ms 可以处理一个服务请求,其中包括接收请求、分配请求、处理

请求等一系列工作;而如果文件数据在磁盘中,则还要加上 75ms 的磁盘访

问时间。假定有三分之二的请求命中缓存,而余下的三分之一涉及磁盘操作,

那么单线程服务器每秒钟可以处理多少请求?多线程服务器呢? 4.11 有一种观点认为,一个程序中的并发实体越多,效率就越高。那么,如果采

用多线程技术编制服务器软件,是否线程个数越多越好?如果回答是肯定

的,请给出理由;如果回答是否定的,你认为应该用什么标准来限制线程的

个数? 4.12 当操作系统提供 LWP 支持时,我们可以把用户线程分配给 LWP 由系统调度。

但如果一个 LWP 仅对应于一个用户线程,我们可能会丧失线程系统的某些

优点,为什么? 4.13 分别用进程技术和线程技术设计一种简单的服务器,两种方案均采用为每个

请求都创建一个并发实体的方法。对每个请求的处理过程都用随机睡眠的调用

来模拟,处理完成后并发实体自动消亡。比较一下这两种技术的优异及效率。 4.14 假定网页服务器保持一个客户 IP 地址的数组,数组元素对应于客户前一次访

问的网页。一旦客户重新连接到该服务器,就可以通过对该数组的查询而返

回客户前次索取的网页,那么,这种服务器是有状态还是无状态? 4.15 在浏览器/服务器模型中,如果服务器一端希望保持对客户的认证,以及客户

的访问轨迹,如何实现这种有状态服务器? 4.16 为什么需要软件代理?软件代理概念的优点何在? 4.17 请在网络上寻找出 5 个移动软件代理系统的网站,对这些系统的实现方案作

一比较,包括程序设计语言、软件代理通信语言、迁移方案、应用领域等。 4.18 移动软件代理可以任意地在网络环境中迁移,那么,当一个软件代理企图与

另一个软件代理通信时,而接收者正在或已经迁移,如何保证通信的可靠

性?怎样才能对迁移者动态跟踪定位?

Page 70: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理

事务处理(transaction)一词原本来自于数据库,表示一个访问数据库程序的一次

执行过程。与单一的数据库访问不同,事务处理一般都涉及多次不同阶段的数据更新操

作。例如,发货事务处理包括检查订单、接收货款、开发票、安排货物提交等一系列步

骤,这些步骤一定要井然有序,不能出现货物已经提交却还没有收到货款的情况。分布

式系统出现后,事务处理这个术语被用于文件服务器,代表对某个客户一系列文件访问

请求的执行过程,或者对某个客户一系列远程数据库操作的执行过程。从客户的角度来

看,这一系列动作必须一步完成,也就是说,服务器一端所管辖的数据必须从前一个一

致性的状态安全过渡到下一个一致性状态。 在这一章里,我们要讨论事务处理的基本模型、事务处理的分类,以及如何解决并

发问题。讨论的重点将放在分布式事务处理上,其中包括两阶段提交协议、并发控制以

及如何检测并防止分布式死锁。分布式事务处理可能涉及到多复制副本的分布式数据

库,保证多复制副本数据的一致性是分布式系统中的一个重要研究课题。我们把这个问

题留到下一章做详细讨论。

7.1 基 本 概 念

追根溯源,事务处理的原始模型来自于工商业的购销模型。在传统的购销模型中,

购买方和销售方可以对货物的品质、数量、价格、交货日期等等进行多轮的谈判。谈判

期间,任何一方都有权力终止会晤,使得购销意向流产。购销双方对流产的谈判不承担

任何义务与责任。然而,一旦购销双方达成协议并签订了合同,这个合同就把签约的双

方捆绑在一起。合同具备法律效力,任何一方在签字后都无权更改合同。与此相仿,计

算机领域里的电子商务模型用进程来模拟传统的购销模式。一个进程可以发起与另一个

或多个进程进行一次事务处理,它们可以根据不同的客户要求,协商各种选择,生成或

删除某些条款,乃至完成某些操作。一旦事务处理的发起者得到满意的结果,便要求所

有参与协商的进程“提交”它们所完成的工作。如果所有进程都一致同意,则协商结果

就类似于一份“合同”,具备永久的效力。反之,只要有一个参与协商的进程反对(由

于故障或其他原因),协商结果便不复存在,就好像这次事务处理根本就没有发生一样。 实际上,事务处理这一概念并不仅仅适用于电子商务,在许多计算机应用中,尤其

在客户/服务器应用及分布式应用中,人们发现很多数据处理过程类似于事务处理。例如,

在远程文件服务系统中,文件服务器必须按照事务处理的模式来提供文件的读/写服务。

当一个客户委托文件服务器进行一系列修改文件操作时,服务器必须保证要么修改操作

全部完成,要么文件还保持原样,没有受到任何破坏,否则的话,客户就可能面临一个

“半途而废”的文件。为了使事务处理的概念更加一般化,计算机科学家把这个术语的

原初含义抽象成一种计算模型,并且刻画了这种模型应该具备的性质。

Page 71: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·151·

7.1.1 事务处理模型

如前所述,事务处理模型是一种抽象化的计算模型。几乎所有对事务处理的定义都

要求整个处理过程的原子性(atomicity)。对某个客户(进程)的一系列请求而言,事务

处理的原子性体现在要么这些请求全部成功地执行,要么这些请求一个也没有执行

(all-or-nothing)。这种“不成功则成仁”的要求隐喻着原子性的两重含义:① 故障原子

性(failure atomicity):即便服务器出现故障也要保证执行过程的原子性;② 持久性

(durability):当一次事务处理成功后,所有与该事务处理相关的结果都必须永久地保存

下来。事务处理应该具备的第二特征是隔离性(isolation),即每一个事务处理过程不允

许受到其他事务处理的干扰,犹如一个黑盒子,其内在的中间处理步骤是完全隐蔽的。

事务处理的第三个特征是一致性(consistency),一致性意味着如果一个系统必须保持某

些一成不变的东西,则无论事务处理发生前或发生后,这些东西依旧不变。 显然,为了保证故障原子性和持久性,服务器管辖的数据必须是可恢复数据,也就

是说,当服务器遭遇到硬件故障或软件错误时,所有已经成功完成的事务处理数据都必

须保存在长存存储器中(如磁盘或者磁带),一旦故障排除就可以恢复使用;而对所有

未曾完成的事务处理必须消除遗留的副作用,确保长存数据没有受到任何破坏。为了满

足隔离性,服务器必须做到事务处理的同步与互斥。单一服务器只要顺序执行每一个事

务处理过程就可以了,但共享数据库的多服务器系统就必须谨慎对待。众所周知,采用

多服务器的目的是尽可能地并发执行事务处理,如果并发的事务处理能够达到顺序执行

的效果,即并发事务处理彼此隔离(互斥),就可以增强整个系统的效率。更进一步,

如果数据分布在不同的服务器上,实现事务处理的隔离性就愈加复杂,系统设计者不仅

要考虑多服务器的协调,也要考虑分布式数据的一致性管理。有的文献把持久性和原子

性分离开来,为事务处理模型归纳了四种应该具备的基本性质,即原子性、一致性、隔

离性以及持久性,并且用每个性质的英文首字母构成一个缩写:ACID,以方便记忆。

在某些文献里,为了强调 all-or-nothing 这一特征,人们也将事务处理称为原子事务处理。 从某种意义上说,事务处理模型是临界区模型的特殊化:临界区是对各种共享资源

(打印机、文件、存储器等)进行互斥访问的抽象,而事务处理是对共享数据进行互斥

访问的抽象。当然,事务处理也有其特殊性,如允许一个进程用原子操作的概念访问、

修改多个数据,并且对执行事务处理的次序也有额外的要求。 为了在程序设计中体现事务处理概念,支持这种概念的(分布式)操作系统或程序设

计语言就必须提供相应的系统调用或原语。为了使我们的讨论更加直观,便于理解,在本

章中我们采用银行服务的例子,并假定银行服务系统提供表 7.1 所列出的基本服务调用。 在本章的各种例子中,我们将用 T,U,V 代表事务处理标号,用 K,M,N 代表

不同的银行分行,用 A,B,C 代表客户的分行账号,一个客户发出的一系列服务过程

调用就可以合并为一次事务处理。例如: 开始事务处理(T) K:取款(A,100); K:存款(B,100); K:取款(C,200);

Page 72: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·152·

K:存款(B,200)。 结束事务处理(T)

表 7.1 银行基本业务服务

服务过程 解 释

存款(账号,数额) 将指定数额的款项存入给定账号

取款(账号,数额) 从给定账号取出指定数额的款项

平衡(账号) 返回给定账号的当前平衡

总平衡() 返回该客户所有账号的总平衡

开始事务处理(标号) 开始指定标号的事务处理

结束事务处理(标号) 结束指定标号的事务处理

流产事务处理(标号) 迫使指定标号的事务处理流产

实现事务处理的过程被称为事务处理服务(transactional service):一个事务处理由

客户给出的一系列服务请求构成,而事务处理服务由服务器提供,并保证这个服务请求

系列的原子性。例如,上面的例子代表一个客户在 K 分行的两次转账,即从账号 A 取

出 100 元并存入到账号 B,然后从账号 C 取出 200 元并存入账号 B。显而易见,这种转

账过程必须是原子动作,否则就会出现账号不平衡的现象。为了使一个事务处理的界面

更为清晰,我们在例子中用“开始事务处理(T)”表示 T 的开始,用“结束事务处理(T)”代表 T 的成功结束。如果整个服务正常完成,服务器就通知客户“事务处理已被提交

(committed)”,这个通知意味着该事务处理所导致的所有改变都已经“铁板钉钉”,被存

放在长存存储器中。反之,如果出自于某种原因,如该事务处理与其他事务处理有冲突,

或软件/硬件系统故障等,服务器就要向客户送出“流产(abort)”报告。当然,客户自

身也可以调用“流产事务处理(T)”,命令服务器以流产的方式停止该客户所委托的事

务处理服务。无论一个事务处理以何种方式流产,服务器都要确保无副作用,换句话说,

该事务处理必须被清除的“片甲不留”。

7.1.2 事务处理分类

在前一小节中,我们给出了事务处理模型应该具备的 ACID 性质。实际上,满足这

四个性质的事务处理是 简单的一类事务处理,人们将此类事务处理称为平面事务处理

(flat transaction)。平面事务处理是 常见, 广泛采用的事务处理模式。然而,它却有

一些局限性。其主要局限在于不允许提交局部处理结果,也就是说,它所要求的强原子

性从另一个角度看却是一种弱点。 例如,假定银行在每个季度结束时计算利息。一种方法是为每一个账号执行一次事

务处理,处理内容包括利息计算、修改平衡额以及其他相关信息。如果银行管理 100000个账号,我们就必须执行 100000 次不同的事务处理。表面上看,这种处理方法没有问

题,每一次事务处理都是平面事务处理,因而处理后的数据应该是正确的。可是,仔细

考察一下这种方法,我们就发现一个潜在的问题,在事务处理期间,整个银行数据库的

状态不一致。如果某个审计部门在利息事务处理期间启动审计事务处理,其处理工作要

Page 73: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·153·

计算所有账号的总平衡,那么,审计事务处理所得到的结果毫无意义,因为有的账号已

经完成利息计算,而有的账号尚未开始。从这个情况看,用一个大的平面事务处理来计

算所有账号的利息才是正确选择。采用一个平面事务处理计算 100000 个账号的利息可

能会花费几个小时,如果在处理了 90000 个账号后系统突然发生故障,整个平面事务处

理就被迫流产,这样的话,已经计算的结果就全然浪费了。 那么,我们是否可以有一种新的事务处理类型,使得事务处理过程更加包容、更加

灵活呢?嵌套事务处理(nested transaction)回答了这个问题。嵌套事务处理是一种结构

化的事务处理类型:一个事务处理可以包含若干个子事务处理,而每一个子事务处理又

可以嵌入若干个子事务处理。理论上说,嵌套的深度没有限制。位于 底层的子事务处

理类似于平面事务处理,必须具备 ACID 性质。嵌套事务处理类型具有两个优点:① 处于同一层次的子事务处理可以并发执行,于是提高了事务处理的速度;② 嵌套的子事

务处理可以独立地提交或流产,一个子事务处理的流产并不意味着父事务处理过程也必

须流产,高层的事务处理可以根据低层事务处理的结果(提交或流产)来决定下一步的

动作;与其相反,子事务处理的提交却依赖于父事务处理的提交,也就是说,如果 高

层的事务处理宣布流产,则所有嵌套的子事务处理都必须流产。如果上述银行利息计算

的例子采用嵌套事务处理模式,就可以利用其并发优点提高处理的速度,通过一个父事

务处理派生出 100000 个子事务处理来计算账号利息。但整个事务处理还是一个原子动

作,也就是说,父事务处理的提交取决于所有派生出的子事务处理的成功执行。我们有

另外一些例子可以充分利用嵌套事务处理的所有优点。例如,一个事务处理要向若干接

收者发送一封信件,我们就可以利用嵌套事务处理把每一个发送任务派生为一个子事务

处理。即便一个或多个子事务处理因发生故障而流产,父事务处理只需要记载这些错误,

而提交其他成功的发送,也就是说,父事务处理提交的是局部计算结果。 嵌套事务处理在分布式系统中显得格外重要,因为这种事务处理类型自然而然地适

合分布式系统的并发计算结构。然而,嵌套事务处理并不等同于分布式事务处理

(distributed transaction),后者是另外一种新的事务处理类型。概言之,一个嵌套事务处

理可以在逻辑上分解成若干层次的子事务处理;而一个分布式事务处理可以把一个平面

/嵌套事务处理的操作分布到不同的服务器上执行。因此,分布式事务处理实际上包括两

种子类型:分布式平面事务处理和分布式嵌套事务处理。我们在图 7.1 中给出这两种分

布式事务处理的例子,其中方框代表事务处理,圆形代表执行操作的服务器。 分布式事务处理的关键在于服务及数据的分布,即一个事务处理所需的服务与数据

可能分散在不同的服务器上,因此,事务处理过程就必须在多台服务器上执行。例如,

图 7.1(a)中的平面事务处理被分布到 3 台服务器上并行完成。多台服务器联合执行一

个事务处理时需要彼此协调,才能做到整个事务处理的成功提交。常用的方法是由一个

协调者(coordinator)通过服务器之间的通信来实现 终提交。为了说明这一点,让我

们考虑下面的例子: 开始事务处理(T) K:取款(A,100); M:存款(B,100); N:取款(D,200);

Page 74: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·154·

M:存款(C,200)。 结束事务处理(T)

T

S1

T22

T21

T12

T11

T2

T1

T

S3

S2

S2

S6

S5

S4

S1

S3

(a) 分布式平面事务处理 (b) 分布式嵌套事务处理

S7

S0

图 7.1 分布式事务处理图例

从这个例子可以看出,某客户要在K,M,N银行分行的A,B,C,D账号上执行转

账业务,即从K分行的A账号取出 100 元,存入M分行的B账号去,然后从N分行的D账

号取出 200 元并存入到M分行的C账号。假定这三个分行的数据库分别位于三台服务器

上,其中S1管理K分行的A账号,S2管理M分行的B,C两个账号,S3管理N分行的D账号,

由于分布式事务处理引入了多服务器概念,系统就必须提供相应的服务调用,如 加入服务器(事务处理标号,协调者服务器) 我们在图 7.2 中给出这个分布式事务处理的示意以及每一台服务器所进行的操作。

T

S1

S3

S2

(1.1) 开始事务处理(T) ; (1.2) K:取款(A,100) ; (1.3) 结束事务处理(T) 。

(2.1) 加入服务器(T,S1) ; (2.2) M:存款(B,100) ; (2.3) M:存款(C,200) 。

(3.1) 加入服务器(T,S1) ; (3.2) N:取款(D,200) 。

K 分行

M 分行

N 分行

协调者

参与者

参与者

图 7.2 分布式银行事务处理

Page 75: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·155·

由于每个服务器可能同时执行不同的分布式事务处理,因此在整个系统中事务

处理标号必须是唯一的。首先启动分布式事务处理的那台服务器是整个事务处理的

协调者服务器,在图 7.2 中,协调服务器是K分行的服务器S1。协调者负责整个事务

处理的提交或者流产,为了做到这一点,协调者要记住与其合作的服务器,同样,

参与合作的服务器要记住协调者所在的服务器。从客户的角度来看,这个事务处理

只是一个平面事务处理,如何把事务处理分布到不同的服务器以及如何协调这些服

务器的处理过程对客户来说是完全透明的。为了区分协调者和其他服务器上的事务

处理过程,有的文献把那些非协调者的过程称为参与者(participant)。在图 7.2 中,

我们为每一个操作冠以标号,用来说明这些操作的相对执行次序,例如,操作(1.1)(1.2)和(1.3)位于服务器S1,因而在S1顺序执行,而分属 3 台不同的服务器的操作序列则并

发执行。

7.2 事务处理的实现

事务处理模型在分布式数据库系统、分布式商务系统中扮演着重要的角色。具体到

实现来说,我们怎样才能保证事务处理的 ACID 性质呢?我们如何提供事务处理的并发

性,以达到优化的性能呢?在实现并发的时候,我们会遇到哪些问题,而且如何解决这

些问题呢?这些将是本节要讨论的题目。 首先,我们将进一步解释事务处理原子性的实质,尤其在并发场合下,一方面我们

要保证多个事务处理可以同时进行,另一方面我们还要保证其隔离性,这样就导出了事

务处理的并发控制算法。其次,我们要讨论原子提交协议,无论是简单的平面事务处理

还是分布式事务处理,我们都需要一种提交协议来完成一次事务处理。在各种并发控制

算法中,有些可能会存在死锁的隐患,在 后一小节我们将介绍分布式死锁的检测及预

防算法。

7.2.1 并发控制

我们曾在第四章和第六章中分别讨论过各种并发模型以及分布式系统中的同步

与互斥问题。分布式事务处理模型的并发概念与前面讨论过的概念既存在共性又有

其特性。为了理解事务处理并发控制的特殊性,让我们首先考察一下并发事务处理

所面临的两个著名的问题:更新丢失( lost update)和非一致检索( inconsistent retrievals)问题。

根据第四章中讨论过的例子,我们知道任何一个更新操作实际上都含有若干低级操

作,以存款(账号、数额)这个操作为例,可以被分解为两个基本动作: 存款(账号,数额) :平衡←账号.读出(); // 从数据库读出存款余额

账号.写入(平衡+数额); // 把更新的余额写回数据库 为了说明并发事务处理的更新丢失问题,首先让我们看一下表 7.2 给出的例子。

表中含有两个转账事务处理 T 和 U。这两个事务处理都在分行 K 的同一台服务器上执

行:事务处理 T 把 40 元从账号 A 转存到账号 B,而事务处理 U 把 30 元从账号 C 转

Page 76: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·156·

入账号 B。假定 T 和 U 同时运行,而且没有任何强制性顺序控制,这两个事务处理的

分解操作就可能出现表 7.2 所示的交替执行情况。本来账号 B 的正确平衡应该是 270元,却由于两个事务处理的“无序”并发而导致错误结果,账号 B 在 U 中的更新操作

被“丢失”了。

表 7.2 事务处理并发时更新丢失问题

开始事务处理(T)

K:取款(A, 40)

K:存款(B, 40)

结束事务处理(T)

开始事务处理(U)

K:取款(C, 30)

K:存款(B, 30)

结束事务处理(U)

分解操作 平 衡 分解操作 平 衡

A.平衡 A.读出() (A) 100 元

A.写入(A.平衡 – 40) (A) 60 元

C.平衡 C.读出() (C) 300 元

C.写入(C.平衡 – 30) (C) 270 元

B.平衡 B.读出() (B) 200 元

B.平衡 B.读出() (B) 200 元

B.写入(B.平衡 + 30) (B) 230 元

B.写入(B.平衡 + 40) (B) 240 元

表 7.3 给出了另外两个并发事务处理交替执行的例子。事务处理 T 依旧是一个转账

型事务处理,从账号 A 转存 100 元到账号 B;而事务处理 U 却是一个计算总平衡的事

务处理,把该客户的所有账号余额相加到一起。如果这两个事务处理的分解操作如表 7.3那样交替执行,就出现非一致检索问题,其结果是总平衡少加了 100 元。造成这个问题

的原因是总平衡事务处理 U 访问了 A,B 两个账号的非一致性状态:账号 A 的状态位

于更新之后,而账号 B 的状态处在更新之前;从转账事务处理 T 的角度看,这两个账号

的更新必须捆绑在一起,即必须是一个原子动作。 那么,假如我们把每一个事务处理都当作临界区,从头到尾地保护起来,还会出现

上述两个问题吗?当然不会!由此可见,事务处理模型与各种并发模型的共性是类似保

护临界区那样的互斥机制。可是,如果我们把每一个事务处理都作为临界区来保护,我

们就在很大程度上丧失了并发性。通过仔细研究,我们发现如果把事务处理的分解操作

编排成某种顺序,不仅可以实现并发执行,而且可以达到与临界区相同的效果。因此,

我们把这种并发事务处理的特性称为顺序等价性(serial equivalence)。在表 7.4 中,我

们重新编排了表 7.2 中两个转账事务处理的分解操作顺序,这个顺序就与以临界区方式

执行两个事务处理的效果完全等价。

Page 77: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·157·

表 7.3 事务处理并发时非一致检索问题

开始事务处理(T)

K:取款(A, 100)

K:存款(B, 100)

结束事务处理(T)

开始事务处理(U)

K:总平衡()

结束事务处理(U)

分解操作 平 衡 分解操作 总 平 衡

A.平衡 A.读出() (A) 200 元

A.写入(A.平衡 – 100) (A) 100 元

总平衡 A.读出() 100 元

总平衡 总平衡 + B.读出() 100 + 200 元

总平衡 总平衡 + C.读出() 300 + 200 元

B.平衡 B.读出() (B) 200 元

B.写入(B.平衡 + 100) (B) 300 元

表 7.4 事务处理并发时顺序等价

开始事务处理(T)

K:取款(A, 40)

K:存入(B, 40)

结束事务处理(T)

开始事务处理(U)

K:取款(C, 30)

K:存款(B, 30)

结束事务处理(U)

分解操作 平 衡 分解操作 平 衡

A.平衡 A.读出() (A) 100 元

A.写入(A.平衡 – 40) (A) 60 元

C.平衡 C.读出() (C) 300 元

C.写入(C.平衡 – 30) (C) 270 元

B.平衡 B.读出() (B) 200 元

B.写入(B.平衡 + 40) (B) 240 元

B.平衡 B.读出() (B) 240 元

B.写入(B.平衡 + 30) (B) 270 元

从上面的例子可以看出,当两个进行更新操作的事务处理读出某个变量的旧值,然

后再计算新值时,就出现更新丢失现象。而如果其中一个事务处理全部完成更新操作,

然后另一个事务处理在前一操作的基础上开始更新操作,就避免了这种现象。同样,当

一个进行检索操作的事务处理与一个进行更新操作的事务处理同时执行时,就出现非一

致检索问题。而如果检索事务处理在更新事务处理之前或者之后进行,就得到了一致性

的检索结果。 采用顺序等价来实现事务处理的交替并发可以防止更新丢失和非一致检索这两个

Page 78: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·158·

问题。当多个事务处理访问同一个数据时,顺序等价性要求必须把每一个事务处理对该

数据的完整(读/写)访问一一排序,严格禁止任何冲突。几乎所有的事务处理并发控制

算法都以顺序等价作为基准,也就是说,我们将要讨论的各种并发控制协议都试图用顺

序等价的方式来访问数据。在这一小节中,我们介绍 4 种并发控制算法,分别为互斥锁

(exclusive lock)、两阶段锁(2PL,two phase lock)、乐观并发(optimistic concurrency)以及时间戳(timestamp)。

1. 互斥锁算法

利用互斥锁来实现顺序等价是 简单的一种并行控制方法。在这种方法中,服务器

试图锁定一个事务处理所要访问的数据,一旦某个数据被锁定之后,其他的访问请求都

被挂起,直到这个数据的互斥锁被释放为止。我们在表 7.5 中给出如何使用互斥锁来模

拟两个转账事务处理并发时的顺序等价。

表 7.5 利用互斥锁进行事务处理并发控制

开始事务处理(T)

K:取款(A, 40)

K:存款(B, 40)

结束事务处理(T)

开始事务处理(U)

K:取款(C, 30)

K:存款(B, 30)

结束事务处理(U)

分解操作 互 斥 锁 分解操作 互 斥 锁

开始事务处理(T) 开始事务处理(U)

A.平衡 A.读出() 锁定 A C.平衡 C.读出() 锁定 C

A.写入(A.平衡 – 40) C.写入(C.平衡 – 30)

B.平衡 B.读出() 锁定 B

B.平衡 B.读出() 等待 B 的锁

B.写入(B.平衡 + 40) .

结束事务处理(T) 释放 A,B .

. 锁定 B

B.写入(B.平衡 + 30)

结束事务处理(U) 释放 B,C

在表 7.5 的分解操作中,我们把事务处理 T 对账号 A 的更新操作和事务处理 U 对

账号 C 的更新操作放在同排顺序上,表示这些分解操作没有冲突,可以随意交替执行。

然而,一旦事务处理 T 锁定了账号 B,事务处理 U 对账号 B 的读操作就被挂起,一直

到事务处理 T 终完成了提交并释放了账号的锁,事务处理 U 才得以继续下去。为了

保证互斥的正确性,我们规定当一个事务处理释放了一把锁之后,就不能再申请任何新

锁,也就是说,任何一个事务处理都分成两个阶段:第一阶段称为膨胀阶段(growing phase),在这个阶段里可以申请(任意多的)新锁;第二阶段称为收缩阶段(shrinking phase),在这个阶段里只准释放锁。一个事务处理必须遵循从膨胀到收缩的周期,这种

周期被称为两阶段上锁(two-phase locking)。

Page 79: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·159·

一旦某个数据被锁定,其他事务处理就不可能对这个数据进行读/写操作。持有该锁

的事务处理必须牢牢地控制这把锁,直到完成所有数据更新操作并且实现成功提交,即

更新后的数据已存入长存存储器。有时人们把这种互斥锁算法称为严格两阶段锁(strict two-phase locking)。可是,事务处理服务器一般都管理大量的数据,而一个典型的事务

处理往往只访问小批量的数据,很有可能与其他的并发事务处理相安无事,和平共处。

于是,我们就产生了两个问题:① 什么时候需要锁定数据?② 当锁定数据时,数据的

范围该有多大?显然,对问题① 而言,锁定数据的时间越短越好;而对于问题② 来说,

锁定数据的范围决定了并发颗粒度(concurrency granularity):锁定的数据越少,并发程

度越高。以银行系统为例,如果任一个事务处理都锁定所有客户账号,则银行系统在任

何时间只能服务于一个事务处理,完全丧失了并发性。 因此,当一个并发控制算法实现顺序等价时,所涉及的数据范围越小越好,所占据

的互斥时间越短越好。为了实现这一点,我们就必须对事务处理的分解操作,即基本的

读/写操作进行深入的研究。值得指出的是,我们必须把基本的读/写操作视为原子动作。

从前面的讨论中我们得知,并发控制的目的是防止不同事务处理对同一个数据的访问冲

突。当我们说一对基本操作有冲突(conflict),则意味着它们的组合效果取决于它们的

执行次序。表 7.6 给出了两个事务处理 T 和 U 在执行读/写操作时的冲突规则。

表 7.6 读/写操作的冲突规则

T U 冲 突 理 由

读 读 无 一对读操作的效果与其执行次序无关

读 写 有 一对读/写操作的效果取决于它们的执行次序

写 写 有 一对写操作的效果取决于它们的执行次序

从表 7.6 所示的规则可以看出,不同事务处理对同一个数据的读操作不存在冲突,

因而为每一个读操作都采用互斥锁的做法并非必要。于是,我们可以改进互斥锁算法,

采用多读/单写方案:或者只允许多个事务处理同时读一个共享数据,或者只准唯一一个

事务处理对该数据执行写操作。

2. 两阶段锁算法(2PL)

在这个改进算法中,我们需要两类锁,一类是前面所使用的互斥锁,用来锁定写操

作(也可称为写锁);而另一类是共享锁或无冲突锁,用来锁定读操作(亦称为读锁)。

顾名思义,共享锁可以由多个事务处理所“共享”,也就是说,当某个数据被共享锁锁

定之后,其他事务处理对该共享锁的请求依然会成功。据此,我们给出两阶段锁算法的

具体步骤: (1)膨胀阶段 当一个事务处理要求访问某个数据时: 1)如果该数据尚未锁定,则服务器锁定数据,操作可以继续; 2)如果该数据已经被另一个事务处理用写锁(互斥锁)锁定,则必须等待,直到

写锁被释放为止;

Page 80: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·160·

3)如果该数据被其他事务处理用读锁(共享锁)锁定,则申请锁定成功,操作可

以继续; 4)如果该数据被这个事务处理自身锁定,在必要情况下可以将锁的类型提升,操

作可以继续。 (2)收缩阶段 当一个事务处理提交或流产,服务器释放所有被锁定的数据。 在上述算法中,由于读/写操作都是系统内部的基本操作,故委托事务处理的客户无

权干涉对数据的锁定和释放工作,而是由服务器自动进行。此外,在膨胀阶段的第 4 个

步骤中,我们使用了“类型提升” 这一术语。锁类型提升表示系统可以将一把锁转换成

互斥性更强的锁,如把读锁提升成写锁。实际上,每一种类型的锁都具备某种程度的互

斥性,例如,读锁可以共享读操作,却排斥写操作;而写锁不仅排斥读操作,也排斥写

操作。从这个意义上看,写锁的互斥性强于读锁的互斥性。 实现互斥锁算法的服务器都有一个称为锁管理员(lock manager)的程序模块。锁

管理员的主要职责是维护一张锁管理表,一般而言,表内每一栏都包括如下信息: 1)锁类型; 2)锁定数据的标识符; 3)持有该锁的事务处理标号(共享锁可能有多个事务处理标号); 4)条件变量。 其中,数据标识符必须是读/写操作可以识别的参数,如银行系统中的客户账号。另

外,大多数系统都采用线程来实现事务处理,因此,当一个事务处理因为等待某个锁而

被挂起时,它的线程被插入到相应的条件变量等待队列中。稍后这个锁被释放时,系统

就会向该条件变量发出信号,从而解挂等待着的线程。除了维护锁管理表之外,锁管理

员模块还必须提供两个系统原语:上锁(lock)和开锁(unlock),如同读/写操作一样,

这两个原语也必须是原子动作。我们在第四章里已经讨论过进程/线程的同步与互斥,这

里就不再赘述。 在分布式事务处理中,每一台服务器都用互斥锁来管理自身的数据,就锁管理模块

的功能而言,分布式系统与单机并发系统相仿。唯一不同的是,分布式系统中的锁管理

模块不能仅仅依靠局部信息就释放锁定的数据,它必须等到所有参与分布式事务处理的

其他服务器都做出了提交或流产之后,才能释放自己锁定的数据。另外,分布式嵌套事

务处理不允许父事务处理与子事务处理并发执行,以防止不同层次之间的访问冲突。当

一个子事务处理提交时,它所持有的锁都交给父事务处理,由父事务处理继承;而当一

个子事务处理流产时,它所持有的锁便由系统回收。 虽然大多数事务处理的并发控制采用互斥锁算法,这个方案还是有一些缺点的。首

先,互斥锁的维护工作花费许多系统开销,即使有的事务处理(只读型)根本不会更新

数据,互斥锁算法也无法优化,必须锁定共享数据。例如,假定两个计算总平衡的事务

处理并发执行,它们只需要读出每一个账号的余额,把这些余额相加到一起,不会对数

据的完整性造成任何损害。而采用互斥锁算法,无论怎样都必须使用读锁来锁定数据,

形成系统的额外开销。第二,使用互斥锁可能会造成系统死锁,我们将在后面的小节里

详细讨论这个问题。这里值得一提的是,要想防止死锁,事务处理的并发性就大大降低;

Page 81: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·161·

要想在发生死锁后解除死锁,就需要复杂的死锁检测,到目前为止都没有令人满意的解

决方法。第三,两阶段锁算法只允许在事务处理提交后才能释放锁定的数据,这种规定

使得我们无法挖掘事务处理潜在的并发性。

3. 乐观并发控制算法

乐观并发控制算法试图克服互斥锁算法的缺点。我们之所以“乐观” ,是因为大多

数事务处理应用并不一定存在冲突,它们共享数据的可能性很低。于是,我们不必采用

“悲观” 的方式来层层加锁,而可以用“乐观” 的态度允许事务处理尽可能地并发执行,

并期望它们圆满成功。万一出现冲突,则选择某个发生冲突的事务处理令其流产,通知

客户该事务处理需要重新启动。在乐观并发控制下,每一个事务处理需要经历 3 个控制

阶段。 (1)读阶段 在读阶段,该事务处理所访问的数据都有一套暂时版本,这套版本不对外,只由拥

有者使用。采用暂时版本可以使事务处理流产而不会影响到长存数据。当执行一个读操

作时,如果数据的暂时版本已经存在,则读操作立即访问之,否则,就必须访问那个数

据 近提交的值。写操作把每一数据的新值作为暂时值记录在案。显然,如果若干个并

发事务处理共享同一个数据,则这个数据可能有不同的暂时值。除了上述规则外,对每

一个访问的数据,事务处理还要维护两个数值集合:读集合包括该事务处理读出的数据,

写集合囊括该事务处理写入的数据。 (2)验证阶段 当事务处理试图提交时,就进入验证阶段,其目的是检测是否它所访问的数据与其

他事务处理的操作有冲突。如果验证无冲突,该事务处理可以提交;否则我们就必须消

解冲突。消除冲突的方法很简单:或者命令该事务处理流产,或者从卷入冲突的事务处

理中选择一个令其流产。 (3)写阶段 如果该事务处理已经通过验证,暂时版本中所记录的数据更新就成为永久性的。如

果该事务处理是只读型事务处理,则它马上提交;否则就要等到暂存数据全部写入长存

存储器后,执行提交操作。 验证工作必须遵循我们前面给出的读/写冲突规则,以确保被验证的事务处理与其他

重叠(并发)的事务处理达成顺序等价。所谓“重叠” 事务处理,指的是当被验证的事

务处理启动时,那些尚未实现提交的正在运行的事务处理。为了便于验证,我们为每一

个进入验证阶段的事务处理赋予一个事务号。事务号是一个整型数,按照递增的方式分

配给事务处理,用以定义事务处理的验证时序:如果事务处理T结束读阶段,并开始验

证阶段,则在它之后结束读阶段的事务处理所得到的事务号必然大于T的事务号。我们

用T代表任何事务处理,把事务号作为下标,则Ti在时序上先于Tj(如果i<j)。 当一个事务处理完成验证并且成功提交,则它保持所赋予的事务号;而如果验证失

败,并且该事务处理被迫流产,则系统收回它的事务号,重新分配给其他的进入验证阶

段的事务处理。验证工作要在每一对Ti和Tj之间进行:要使得事务处理Ti与重叠事务处

理Tj顺序等价,它们的分解操作必须满足表 7.7 列举的规则。

Page 82: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·162·

表 7.7 乐观并发控制的验证规则

Ti Tj 规 则

读 写 Ti决不允许读Tj写入的数据

写 读 Tj决不允许读Ti写入的数据

写 写 Ti决不允许复写Tj写入的数据;Tj决不允许复写Ti写入的数据

一般而言,一个事务处理的验证阶段和写阶段比读阶段所花费的时间要短的多,我

们可以采用比较简单的方法来防止验证阶段和写阶段的重叠:把一个事务处理的验证阶

段和写阶段合并成一个临界区,保证任何时候只有一个事务处理执行验证、写入和提交。

对分布式事务处理来说,验证阶段的工作要复杂一些,因为一个分布式事务处理可能涉

及多台服务器,每一台服务器都要验证自身管辖的数据操作。为了说明这一点,让我们

看一看表 7.8 给出的例子。

表 7.8 分布式事务处理的验证阶段

事务处理(T) 服 务 器 事务处理(U) 服 务 器

A.读出() S1 B.读出() S2

A.写入() S1 B.写入() S2

B.读出() S2 A.读出() S1

B.写入() S2 A.写入() S1

表 7.8 中,分布式事务处理 T,U 都要在服务器 S1 和 S2 上执行部分操作。当它们

同时进入验证阶段时,假定服务器 S1 首先验证 T,而 S2 首先验证 U。如果我们把验证

工作视为临界区,则两台服务器分布锁定各自的临界区,而无法访问对方的临界区(我

们必须访问对方的数据才能通过验证),于是发生死锁现象。解决这个问题的方法之一

是采用两阶段提交协议,我们将在下面的小节中讨论事务提交问题和死锁问题。 从概念上看,互斥锁算法基于逻辑模型,而乐观并发算法基于经验模型。也就是说,

乐观并发算法的初衷并非来自某种理论,而是来自于实践中的观察。实践的经验告诉我

们,大多数事务处理在并发时可能没有冲突。于是,我们就“乐观”地赌一次。如果赌

赢了,系统达到 高并发性;若赌输了,有些事务处理就算白作了,回头重新启动。然

而,重新启动一个事务处理的潜在问题是饿死现象。如果这个被迫流产而重新启动的事

务处理每次都遇到冲突,每次都被打回票,则它永远得不到执行。尽管这种情况在实践

中难得发生,我们也不能掉以轻心,在设计算法时要考虑加入适当的解决方法。

4. 时间戳算法

后一个并发控制算法基于Lamport逻辑时间,被称为时间戳算法。对每一个事务

处理T,我们要赋予一个启动时间戳ts(T);对T的每一个操作,都要赋予ts(T)。注意,时

间戳必须遵循全局排序关系。除了对事务处理的操作打时间戳之外,我们还要对系统中

每一个数据,如客户账号A,打上读/写时间戳,记为tsR(A)和tsW(A),当然与A相关的时

间戳总是代表 近那次读/写的时间。采用时间戳排序的方案,系统要有一个调度程序来

Page 83: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·163·

管理数据。每当一对操作发生冲突时,调度程序率先处理那个时间 小的操作。与乐观

并发算法类似,写操作都被记录在暂时数据版本中,而且暂时版本仅在事务处理提交时

才存入长存存储器。假定调度程序接收到来自事务处理T的读出(A) 操作请求,T的时间

戳为ts(T) ,但如果调度程序发现ts(T) < tsW(A) ,也就是说,在T启动之后曾有另外某个

事务处理在账号A上执行过写操作,于是,系统迫使T流产。反之,如果ts(T) > tsW(A) ,调度程序便允许T执行读操作,同时,调度程序还要更新账号A的时间戳,使得A的读时

间戳tsR(A) max(ts(T) ,tsR(A)) 。 时间戳算法调度程序的主要任务是检查事务处理的读/写请求是否与时间戳次序

有冲突。假定被检查的操作请求来自当前的事务处理Tj,则该请求有可能与另一个事

务处理Ti曾经发出的操作相冲突,换句话说,按照时间次序Tj本来应该早点执行那个

操作,但Tj的操作发出的太晚了。表 7.9 给出时间戳算法采用的时间次序冲突规则,为

了简化我们的讨论,我们直接用带下标事务处理标号代表时间戳,其中,Ti > Tj表示

Ti晚于Tj。

表 7.9 时间戳排序冲突规则

事务处理(Tj) 规 则

写操作 假如某个Ti曾进行过读操作而且Ti > Tj,则Tj不得执行写操作

写操作 假如某个Ti曾提交过写操作而且Ti > Tj,则Tj不得执行写操作

读操作 假如某个Ti曾提交过写操作而且Ti > Tj,则Tj不得执行读操作

为了更清楚地理解时间戳算法,让我们假设有四个事务处理T1,T2,T3和T4,并

且 T1 < T2 < T3 < T4

如果此刻事务处理T3请求A.写入(新值),即把一个新值写入账号A,T3必须满足

两个检测:T3大于等于A的 大读时间戳;T3大于等于A的已经提交的写时间戳。在图

7.3 中,我们给出T3可能面临的四种情况,图中我们仅考虑已经针对账号A完成的写操作,

灰色方框代表已经提交的写操作,而白色方框为暂时写入的版本(尚未提交),每个方

框中都用带下标的事务处理标号作为时间戳。 从图 7.3 可以看出,子图(a)~(c) 中,T3均大于A的提交时间戳,因此,调度程序允

许T3执行写操作,然后把对A更新后暂时版本插入到适当的位置上,但是在子图(d) 中,

账号A的提交时间戳大于T3,则表示T3的请求来迟了,迟到就要受到惩罚,于是系统强

制T3流产。 时间戳算法与互斥锁算法全然不同,当一个事务处理和某个大时间戳冲突时,它就

被流产;而在同样的情况下,互斥锁算法或者让它等待,或者让它马上执行请求的操作。

由于时间戳算法基于逻辑时间的全局排序关系,即便用来控制分布式事务处理,也不会

出现死锁现象。但是,这种算法并不公平,它可能会迫使一个运行了很长时间的事务处

理流产。 这一小节里我们讨论了事务处理的并发控制问题,同时描述了 4 种并发控制算法。

这些算法需要不同程度的系统资源(空间与时间)开销,而且也在不同程度上局限了事

Page 84: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·164·

之前 T 2

T3 T2

T1

T1

T4

T4

T1

T1

T4 T3

T4

T3

T2

T2 之后

之前 之前

之前

之后 之后

之后

时间 时间

时间 时间

(a)

(d) (c)

(b)

T3流产

图 7.3 事务处理T3请求写入(A)可能遇到的情况

务处理潜在的并发性。如果读者希望对事务处理并发机制作进一步的了解,可以参阅

Bernstein 等人的文章。在分布式系统研究中,人们还在探讨一些新的事务处理并发控

制算法,如语义锁、多版本时间戳等等,这些算法还处于学术研究阶段,有待于大量的

试验与验证才能推广使用。

7.2.2 原子提交协议

在前面的讨论中,我们频繁地使用“提交”这一术语,表示一个事务处理已经成功

完成,它所做出的数据更新都已经安全地存入长存存储器中。在单机系统中,事务处理

的提交等同于该事务处理退出临界区,实现起来很简单。在分布式系统中,一个事务处

理被分散在不同的服务器上执行,在这种情况下,我们怎样才能使得这些服务器要么一

同提交,要么一同流产呢? 早期的分布式提交通常采用单阶段提交(one-phase commit)协议。在这种协议中,

系统需要一个协调者,它与所有涉及该事务处理的服务器通信,通知这些参与者进行提

交或者流产操作,然后收集来自这些参与者的回应,直到所有服务器都完成指定的操作

为止。然而,单阶段提交协议有一个明显的缺点,如果某一台服务器无法执行协调者指

定的操作,协调者也无能为力,甚至无法知道这一点。例如,当协调者向服务器发出提

交请求时,我们就不允许任一台服务器单方面地决定流产,而这一点恰恰是无法得到保

证的,其原因来自于事务处理的并发性。譬如某台采用乐观并发算法的服务器正在对该

事务处理的一部分工作进行验证,却发现与其他并发的事务处理有冲突而且必须流产,

于是无法执行来自协调者指定的提交操作。 为了解决上述问题,我们可以采用两阶段提交(2PC,two-phase commit)协议。简

言之,依照事务处理的原子性,如果一个事务处理的部分执行发生问题,则整个事务处

Page 85: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·165·

理必须流产。因此,我们把提交工作分成两个阶段。在第一个阶段中,每一台服务器对

该事务处理是否提交或流产进行选举,一旦做出提交选举后,该服务器就不能改变自己

做出的承诺。换句话说,做出提交选举的服务器必须已经成功完成它那一部分事务处理,

而且已经准备好所有更新的数据,保证这些数据能够写入长存存储器。在第二阶段,每

一台服务器都将根据选举信息对该事务处理做出 后决定:如果任何一个参与者选举

流产,则 终决定是流产;如果所有参与者都选举提交,则整个事务处理得到提交。 下面我们讨论一下 2PC 的具体实现过程。2PC 协议亦需要协调者和参与者这个概

念,而且由协调者首先启动 2PC 算法。为了便于讨论,我们在表 7.10 中给出 2PC 所

使用的基本操作。

表 7.10 2PC 基本操作

操 作 返回值 解 释

能否提交(标号) 同意/否定 协调者询问参与者是否可以提交,参与者做出回答

执行提交(标号) 无 协调者通知参与者提交它们各自的事务处理

执行流产(标号) 无 协调者通知参与者流产它们各自的事务处理

已经提交(标号,参与者) 无 参与者通知协调者已经完成它那一部分的事务提交

询问结果(标号) 同意/否定 参与者向协调者询问 终选举结果(用于容错机制)

实际上,表 7.10 中列举的操作代表协调者和参与者之间的通信,带返回值的操作需

要双向往返通信,而不带返回值的操作表示单向通信。图 7.4 展示协调者和一个参与者

之间的 2PC 通信步骤。

协调者:

步骤 状态

(1) 准备提交

(等待选举)

(3) 提交

(5) 结束

参与者:

步骤 状态

(2) 准备提交

(未确定)

(4) 提交

能否提交

同意

执行提交

已经提交

图 7.4 2PC 协调者和参与者的通信步骤

对照表 7.10 和图 7.4,我们给出 2PC 协议如下: 第一阶段:选举 1)协调者向所有参与者发送能否提交信件。 2)当一个参与者接收到能否提交信件,根据自身的状态返回“同意/否定”。注意,

在回答“同意”之前,参与者必须准备需要写入长存存储器的数据;反之,若回答“否

Page 86: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·166·

定”,则参与者可以立即流产。 第二阶段:根据选举结果完成指定操作 1)协调者收集选举结果(包括自己的选举结果):如果所有结果都是“同意”,则

协调者决定提交,向所有参与者发送执行提交信件;否则,协调者决定流产,向所有曾

经返回“同意”的参与者发送执行流产信件。 2)曾经返回“同意”信件的参与者必须等待来自协调者的 终命令。当它接收到

执行提交或执行流产信件后,则立即执行相应操作。如果执行的是提交操作,则在提交

后向协调者返回一封已经提交信件。 3)为了增强算法的容错能力,参与者在等待协调者的命令时可以采用“超时”技

术,即当长时间后尚未得到协调者的信件(如信件丢失),参与者便可以向协调者发出

信件询问结果,然后回到第 4 步继续等待。 4)当协调者接收到所有已经提交回应后,协调者工作结束。 如果采用简单的 2PC 协议,在系统出现故障的情况下,可能会发生这样或那样的问

题。例如,无论协调者或参与者都存在“等待”状态,于是,只要任何一台服务器出现

故障,2PC 算法就可能永远地等待下去。从算法中我们知道,协调者在发起选举后必须

等待所有参与者的回应,如果某个参与者的服务器出错或者返回信件丢失,协调者就无

法决定 终选举结果。解决这个问题的 简单方法就是利用“超时”技术,当协调者等

待长时间后尚未接到所有回答,便可以假定系统出错,立即命令所有参与者流产。这种

假定虽然并不一定正确,但不会影响到事务处理的原子性,只不过可能流产了一个本来

已经应该完成的事务处理而已。反之,如果协调者的服务器发生故障,事情就不那么简

单了。尽管我们在算法的第 3 个步骤中采取了“超时”技术,但也只能克服信件丢失的

现象,无法应付协调者服务器的软硬件错误。在没有得到协调者命令的情况下,参与者

只能等待,不可能单方面地做出任何假定。 一种变通的解决方法是让等待超时的参与者访问另一个(一些)参与者的状态,如

果另一个参与者已经提交,则唯一的可能是那个参与者曾接收到来自协调者的提交命

令,于是,无论协调者服务器出现故障还是协调者的信件丢失,这个等待超时的参与者

都可以做出正确判断,执行提交操作;如果另一个参与者的状态是流产,则等待超时的

参与者马上就可以执行流产操作。这种变通方法只适用于特殊情况,即协调者已经发出

若干执行提交信件后才出现故障。假如所有的参与者都处于“未确定”状态,也就是说,

谁也没有接收到来自协调者的命令,则除了等待就没有其他选择了。 现在让我们来看一下 2PC 协议的性能。假定一个分布式事务处理涉及 N 台服务器,

在理想的情况下,即协调者服务器和参与者服务器都工作正常而且通信畅通无阻,则

2PC 算法需要大致 3N 封信件完成提交工作,其中 N 封为能否提交信件,N 封同意/否定

信件,以及 N 封执行提交信件。这里我们没有统计协议中使用的已经提交信件,原则上

说,取消这类信件并不影响到算法的正确性,这些信件只是用来帮助协调者对已经提交

的事务处理做一些善后工作。如果执行环境不够理想,频繁出现信件丢失或者系统故障,

则 2PC 算法就会显现出 坏性能,乃至无限期地等待(直到发生故障的服务器重新启动,

重新执行该事务处理为止)。

Page 87: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·167·

从上面的讨论中可以看出,2PC 协议的第一阶段是参与者对自身事务处理的承诺,

而第二阶段是由协调者根据全局情况作出的决定。无论 后决定是执行提交还是执行流

产,协调者都必须将决定记入局部日志。分布式日志不仅记载分布式事务处理的提交情

况,也记载着数据更新的相关信息,在系统发生故障的情况下,我们可以利用日志记录

来恢复被故障中断的事务处理,有的操作需要取消(undo),有的操作需要重做(redo),我们将在稍后的章节里专门讨论故障恢复问题。

2PC 协议适用于分布式平面事务处理,那么,对于分布式嵌套事务处理来说,我们

需要做出什么改动呢?首先,我们指定一个分布式嵌套事务处理的 高层(即开始事务

处理的那一层)为协调者,如图 7.5 中的 T。当协调者启动运行后,将创建若干子事务

处理并将它们分布到不同的服务器上。随后,这些处于第二层的子事务处理亦可能创建

下一层的子事务处理并分布其运行环境,如此等等,我们在图 7.5 中给出了一个 3 层嵌

套的分布式事务处理的例子。

T22

T21

T12

T11

T2

T1

T

S2

S5

S4

S1

S3

S0

T11流产

T12临时提交

T2流产

T22临时提交

T1临时提交

协调者

T21临时提交

图 7.5 分布式嵌套事务处理 T 决定是否提交

当某台服务器上的子事务处理完成工作时,服务器记录该子事务处理的状态:或者

流产,或者临时提交。所谓临时提交,表示子事务处理已经准备好提交工作,但无权决

定是否 终提交,必须等待来自协调者的命令。我们曾在前面的讨论中说过,子事务处

理的提交取决于父事务处理,即便某个子事务处理流产,父事务处理仍然有权力决定提

交。例如,我们可以把一个银行的批量转账工作编写为一个分布式嵌套事务处理,每一

次转账(即取款/存款)都由一个子事务处理完成。那么,当某个账号在执行取款操作时,

账号发生透支现象(即该账号没有足够多的余额),取款操作失败,从而子事务处理流

产。但是,这并不影响其他子事务处理的转账工作,因此,父事务处理可以提交成功的

转账,而对流产的转账做出错误报告。 在图 7.5 中,我们在每一台服务器旁标记子事务处理的状态,如S3的T11宣布流产,

而S4的T12准备临时提交;位于S1的父事务处理T1全然不顾T11流产,决定向 高层事务处

Page 88: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·168·

理T做出临时提交。反之,对位于S2的父事务处理T2来说,尽管它的两个子事务处理,

即位于S4的T21和位于S5的T22都已经做出了临时提交决定,但由于T2自身流产,它下属的

子事务处理也不得不被迫流产。 一般而言,仅当所有已经临时提交的子事务处理都能保证安全提交时, 高层事务

处理才能提交。于是,每一层事务处理都要掌握下层(乃至子孙层)的信息。当一个子

事务处理流产时,它只需要向父事务处理报告流产;而当一个子事务处理做出临时提交

时,它就必须把所有位于其下的子孙事务处理的状态报告给父事务处理。根据图 7.5 给

出的例子,当事务处理T决定是否提交时,它所在的服务器以及各台子事务处理服务器

掌握的信息在表 7.11 列出,其中T2一栏的临时提交表被横线划掉,表示它的子事务处理

虽然报告了临时提交,却因为T2的流产而作废。用一句形象的话来说,“提交”的潜在

含义是“下级服从上级”;而“流产”的潜在含义是“株连后代”(而不是“株连九族”)。

表 7.11 嵌套事务处理提交时的信息分布

参与服务器 事务处理标号 子事务处理 临时提交表 流产表

S0 T T1 ,T2 T1 @ S1,T12 @ S4 T11,T2

S1 T1 T11,T12 T1 ,T12 @ S4 T11

S2 T2 T21,T22 T21 @ S4,T22 @ S55 T2

S3 T11 T11

S4 T12,T21 T12,T21

S5 T22 T22

假定事务处理T决定提交,与上面讨论过的 2PC协议一样,分布式嵌套事务处理的

整体提交工作由协调者( 高层事务处理T)启动,向所有做出临时提交的下属子事务

处理所在的服务器发送能否提交信件。当某台参与服务器接收到能否提交信件,就检索

做出临时提交的子事务处理,并且返回“同意”。可惜的是,我们前面所使用的能否提

交操作缺少一些必要的信息。例如,当服务器S4接收到能否提交信件时,它所管理的两

个子事务处理T12,T21都曾做过临时提交,那么S4应该选择哪一个提交呢?毫无疑问,

我们不能提交T21,因为它的父事务处理T2已经宣告流产,它也必然受到株连。为了解

决这个问题,我们必须在能否提交操作的参数表中增加一个参数:流产表。这样的话,

当一台参与服务器接收到能否提交信件,就要剔除所有因父事务处理(或更高层事务

处理)流产而影响到的那些子事务处理,准备好提交工作,然后向协调者返回“同意”

信件。如表 7.11 所示,服务器S4接收到的能否提交信件里附带着流产表(T11,T2),

于是,S4剔除以T2为父事务处理的T21,只对T12准备好提交,然后回答“同意” 。然而,

如果参与服务器无法找到已经临时提交的子事务处理信息,则表示该服务器在子事务

处理做出临时提交之后,而在选举之前的这段时间里发生了故障,因此向协调者返回

“否定”信件。 2PC 协议是 为常用的分布式事务处理提交协议,但是,由于协议中涉及“等待”

问题,人们也把这种协议称为阻塞提交(blocking commit)协议。为了避免“阻塞”,人

们试图给出不同的提交方法,如三阶段提交(3PC)协议等。这些新的提交方法目前还

仅限于学术讨论和文献引用,并没有得到广泛应用。而且,在服务器和通信系统都比较

可靠的情况下,2PC 的阻塞现象难得出现,故而为大多数分布式事务处理系统所采用。

Page 89: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·169·

7.2.3 分布式死锁与检测

在各种涉及互斥的算法中,只要算法采用互斥锁,就有可能发生“死锁” 现象。以单机

并发事务处理为例,假定我们采用两阶段锁协议来控制表 7.12 所示的并发事务处理 T 和 U。

根据两阶段锁协议的原则,在膨胀阶段,每个事务处理可以申请锁,而在收缩阶段(即提

交时),每个事务处理才能释放锁。于是,我们可能有表 7.12 给出的分解操作,事务处理 T和 U 共享账号 B 的读锁,然后都陷入无休止的等待,企盼对方释放 B 的读锁以便执行写操

作,可是谁也没有到达收缩阶段,不会释放自己掌握的锁,这种情况就被称为死锁。

表 7.12 两阶段锁协议下的死锁现象

开始事务处理(T)

K:取款(A, 40)

K:存款(B, 40)

结束事务处理(T)

开始事务处理(U)

K:取款(C, 30)

K:存款(B, 30)

结束事务处理(U)

分解操作 互 斥 锁 分解操作 互 斥 锁

开始事务处理(T) 开始事务处理(U)

A.平衡 A.读出() 锁定 A 的读锁 C.平衡 C.读出() 锁定 C 的读锁

A.写入(A.平衡 – 40) 锁定 A 的写锁 C.写入(C.平衡 – 30) 锁定 C 的写锁

B.平衡 B.读出() 锁定 B 的读锁

B.平衡 B.读出() 共享 B 的读锁

B.写入(B.平衡 + 40) 等待 U 释放 B

B.写入(B.平衡 + 30) 等待 T 释放 B

… …

死锁的典型特征是一组事务处理形成了一条循环等待链,如上例中 T 等待 U 而且 U等待 T。有的死锁情况很简单,所有等待着的事务处理构成一个环;而有的死锁情况比

较复杂,等待着的事务处理可能涉及多条循环链。我们在图 7.6 中给出两种死锁的例子,

其中(a) 形成一条 T→U→V→W→T 的简单循环链,而(b) 中含有 V→W→T→V 和

V→W→V 两条循环等待链。显然,如果我们迫使(a) 中任一个事务处理流产,那条循环

等待链就被打断,死锁就不存在了,而在(b) 中,只有迫使事务处理 V 或 W 流产,才

能同时解除两条链的死锁。 死锁是任何并发系统中的致命伤,那么,我们能否防患于未然,从根本上杜绝死锁

现象发生呢?回答是肯定的,但我们要为此而付出代价。 简单的方法是让一个事务处

理在开始运行前锁定所有需要的数据,于是它就不会与其他事务处理发生冲突。可如果

这样做的话,我们就完全排除了数据资源的共享。此外,在许多情况下,我们无法预先

知道应该锁定哪些数据,尤其当事务处理的程序含有若干条件转移时,数据的访问依照

运行时的动态条件而变化,把所有条件分支的数据全部锁定不仅浪费资源而且可能影响

到其他事务处理的并发性。另外一种防止死锁的方法是按照一种预先定义的次序来申请

锁,这样可以防止形成循环等待,但是机械规定申请次序会损害事务处理的并发性。

Page 90: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·170·

T

U V

W

W U

T

V

(a) 简单循环链 (b) 复杂循环链 图 7.6 死锁-循环等待链

防止死锁花费的代价太大,而且死锁的出现是随机性的,同一个事务处理,在不

同时间不同系统负载下可能会死锁也可能不会死锁。这样就导出了另外一种论点:我

们不必担心死锁,任凭事务处理并发执行,以期达到 高的系统性能,如果没有出现

死锁,则皆大欢喜;倘若出现死锁,系统就选择一个卷入死锁的事务处理,迫使它流

产,从而打破循环等待链。根据这个论点,事务处理系统就必须扩充锁管理程序,增

加一个死锁检测算法。死锁检测算法需要维护一张等待图,图里的结点代表事务处理,

而图里的边都是有向边。每当锁管理程序试图执行上锁或开锁操作时,等待图中就可

能添加一条边或者去掉一条边。显而易见,当等待图中的若干条边构成一个有向环的

时候,就发生了死锁。于是,每当添加一条边时,我们就可以启动死锁检测算法,当

然,我们也可以适当减少死锁检测的频率,以提高系统性能。一旦发现死锁,系统就

必须选择一个事务处理流产,同时从等待图中删除与该事务处理有关的任何记录。至于选

取哪一个事务处理流产,不同的系统可以采用不同的策略。例如在卷入死锁的事务处理中

选取那个运行时间 短的,或者选取一个尚未流产过的,或者选取一个使用资源 少的等

等。这些策略各具优缺点,算法的设计者应该根据应用程序的需求而做出抉择。 在分布式事务处理系统中,由于事务处理的操作被分散到许多服务器上,死锁问题

就变得更加复杂,任何单独一台服务器可能都不存在等待循环链,而全局却有一条循环

等待链,这种情况被称为分布式死锁。为了直观地说明分布式死锁,让我们看一下表 7.13给出的例子。假定我们有 3 台服务器S1,S2,S3,其中S1管理账号A,S2管理账号B,而

S3管理账号C和D。如果 3 个事务处理U,V,W同时开始执行,每个事务处理都分别访

问 3 台服务器上不同的账号,则可能出现表 7.13 所示的交错运行状况:事务处理U锁定

了D和A,等待B;事务处理V锁定了B,等待C;而事务处理W锁定了C,等待A。于是,

这 3 个事务处理形成了一条循环等待链。

表 7.13 分布式事务处理的死锁现象

事务处理 U 事务处理 V 事务处理 W

存款(D,100) 锁定D @ S3

存款(B,300) 锁定B @ S2

存款(A,200) 锁定A @ S1

存款(C,500) 锁定C @ S3

取款(B,200) 等待B @ S2

取款(C,100) 等待C @ S3

取款(A,300) 等待A @ S1

死锁

Page 91: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·171·

我们把表 7.13 的死锁形象化,就得到图 7.7 给出的分布式死锁示意图,不难看出,

图中 3 个分布式事务处理构成一条 U→V→W→U 的有向环。

S1

A

S2

S3

D C

B

V

W

U

等待

锁定

锁定

锁定

锁定

等待

等待

图 7.7 分布式死锁示意图

要想检测分布式死锁,我们就必须搜集所有服务器的等待状态,根据这些状态来判

别是否存在一条有向环。从上面的例子可以看出,我们可以借助于服务器之间的通信搜

集到如下局部等待状态: S1 :U → V S2 :V → W S3 :W → U

简单的方法是采用中央检测程序来判别是否系统陷入分布式死锁。这个程序周期

性地向所有服务器询问等待状态,一旦全局等待状态形成一条如上例所示的循环链,则

启动解除死锁算法,即向某台服务器发出通知,命令它迫使某个事务处理流产。中央检

测程序实现起来很容易,但却不是一个理想的方案。首先与其他中央控制算法一样,成

为系统的瓶颈,容错能力很差,而且调节能力弱。其次,频繁地收集局部状态会增加系

统开销,而收集状态的时间间隔过长,又无法及时发现死锁。 为了克服中央检测算法的缺点,我们可以采用分布式死锁检测技术,称之为边跟踪

(edge chasing)算法。这个算法并不需要构造全局等待图,而是由每一台服务器根据自

己掌握的等待信息(局部等待图的边)来判断是否出现死锁。这个算法的关键是在服务

器之间传送的一种叫做探测(probe)的信件,一封探测信件代表全局等待图里的一条有

向(等待)路径(path)。如果这封探测信件到达某个服务器,而该服务器发现信件里描

述的路径已经构成一条有向环,则这条路径上的结点(事务处理)便陷入死锁。

Page 92: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·172·

那么,一台服务器应该在什么时刻发送一封探测信件呢?让我们再来看一下图 7.7给出的例子,当服务器S1在它的局部等待图里添加等待边U → V的时候,事务处理V正

在等待服务器S2中事务处理W所锁定的C锁,于是,这条新添加的边就有可能形成一条

循环链。为了防止潜在的分布式死锁,服务器S1就要向S2发送一封探测信件。反之,假

定在早些时候服务器S3添加W → U,而那一时刻事务处理U尚未等待,因此S3就没有必

要发出探测信件。 前面我们曾经提到,启动一个事务处理的服务器是该事务处理的协调者,而分布运

行该事务处理的其他服务器为参与者。在任何一个瞬间,该事务处理或者正在运行,或

者在某一台服务器上进入等待状态。协调者有责任记录整个事务处理的当前状态,而参

与者可以从协调者那里得到这些状态。每当某个事务处理因申请锁而进入等待状态时,

局部锁管理程序就必须通知该事务处理的协调者,而当申请成功该事务处理恢复运行

时,局部锁管理程序也必须通知它的协调者。另一方面,当一个事务处理为解除死锁而

不得不作出牺牲时,它的协调者就必须通知所有参与者流产该事务处理,释放所有锁定

的资源,并且消除局部等待图中的所有记录。 根据上面给出的描述和规定,我们把边跟踪算法的具体步骤归纳如下: 1)初始:当服务器Si发现事务处理T开始等待事务处理U,而U已经在等待另一台服

务器Sj管辖的数据,则Si向Sj发送一封探测信件,信中内容为等待边T → U。假如U所等

待的是共享锁,则这封探测信就必须发往所有相关的服务器。 2)检测:当服务器Sj接到探测信件,便根据自己掌握的局部等待图判断是否出现死

锁,并且进一步决定是否要把探测信件转发到其他服务器。例如,当Sj接收到探测信T → U,它首先检查U是否也在等待。如果U正在等待V,则Sj把这条边加入到探测信的路径

中,T→U→V,如果V所等待的是服务器Sk中的数据锁,则这封更新后的探测信被转发

到Sk。按照这种方法,探测信件沿着全局等待图逐步形成一条路径,每次经过转发时,

都在路径上添加一条新边。检测死锁的方法很简单,在转发一封探测信之前,只要检查

一下信中的路径,如果头尾都是同一个事务处理,如T→U→V→T,则出现有向环,发

生死锁。 3)解除:当发现死锁后,就必须在那个有向环内选择一个结点(事务处理),勒令

它流产。 假定处于等待状态的事务处理不会自行流产,而且系统自身的容错能力很强(如服

务器工作可靠,不会出现信件丢失等),边跟踪算法一定能够检测出存在的死锁。从性

能上看,这个算法似乎需要大量的信件传输,因为每一次决定是否转发探测信件时,参

与服务器都要向协调服务器查询下一结点的状态,如转发 T→U 的前提条件是 U 也处于

等待状态。为了不失一般性,假定一封形成有向环的探测信件涉及 N 个事务处理,该算

法就需要传送 2(N-1)封信件后才能做出死锁判断,其中(N-1)封状态查询信件,

(N-1)封转发的探测信件。尽管表面上看开销很大,但大量的实践证明,通常卷入死

锁的事务处理不会多于二三个,我们也就不必为性能担心了。

习 题

7.1 假定事务处理 T 和 U 分别对账号 A,B,C 进行下列分解操作:

Page 93: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第七章 分布式事务处理 ·173·

T:读出(B) ;读出(A) ;写入(B,44) ;写入(A,33) ; U:读出(C) ;写入(A,55) ;读出(B) ;写入(C,66) ; 给出 T 和 U 交替执行的 3 种顺序等价序列。

7.2 假定表 7.4 中的事务处理 T 和 U 被分解成下面的 4 个嵌套子事务处理(注意,

下面的取款/存款操作不是原子动作,都包括若干原子读出/写入操作): T1:取款(A,40) ;T2:存款(B,40) ; U1:取款(C,30) ;U2:存款(B,30) ; 比较一下T1,T2,U1,U2的顺序等价序列个数和原来T,U的顺序等价序列个数。

解释一下为什么采用嵌套方式所获得的顺序等价序列要比非嵌套方式多? 7.3 顺序等价性有这样一种要求:某事务处理一旦释放了一把锁,就不允许它再获

得任何新锁。请解释为什么。 7.4 假定事务处理 T 和 U 带标号的分解动作如下:

T:(1) 读出(A) ;(2) 写入(B,100) ; U:(3) 写入(A,50) ; (4) 写入(B, 200) ; 我们用标号代表操作,给出 4 个执行系列:(1)(3)(2)(4) ;(1)(2)(3)(4) ;

(3)(4)(1)(2) ;以及(3)(1)(4)(2)。请指出哪些序列是顺序等价,哪些序列可能出

现在两阶段锁协议之下? 7.5 如果我们把两阶段锁控制算法稍微改动一下,允许只读型事务处理提前释放读

锁(即不必等到提交时,而可以在读操作之后马上释放)。那么,一个只读事

务处理是否会出现非一致检索?用下面的例子来说明你的回答: T:读出(A) ;读出(B) ; U:写入(A, 100) ;写入(B, 200) ; 你可以假定 A,B 两个账号原来的平衡额分别是 700 和 900。

7.6 请你设计一个具体的单机死锁检测算法。每当一条边被添加到等待图,或者从

等待图里删除,你的算法中必须给出详细的步骤和准确的描述。 7.7 假定事务处理 T 和 U 的分解动作如下:

T:读出(B) ;读出(A) ;写入(B,44) ;写入(A,33) ; U:读出(C) ;写入(A,55) ;读出(B) ;写入(C,66) ; 如果这两个事务处理分别在两阶段锁算法和乐观并发算法下执行,请比较分

解操作的执行顺序。 7.8 两阶段提交(2PC)协议由协调者命令参与者完成提交,我们可以把这个中央

控制(协调者)算法改成分布式算法:在第一阶段,协调者向所有参与者发出

“选举”通知;在第二阶段,如果协调者的选举结果是“否定”,则所有参与者

执行流产操作,而如果协调者的选举结果是“同意”,则每一个参与者不仅要

把自己的选举结果发往协调者,同时也要发送到所有其他的参与者,然后协调

者/参与者便综合选举结果,执行相应的操作。计算这个算法需要传送几轮信

件?总共多少封信件?与中央协调算法相比,其优点是什么?缺点是什么? 7.9 在两阶段提交协议中,如果我们采用超时技术,能够克服协议中的阻塞问题吗? 7.10 两阶段提交协议存在阻塞问题,为了克服阻塞,我们可以采用三阶段提交

Page 94: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·174·

(3PC)协议: 第一阶段:协调者向所有参与者发出选举通知; 第二阶段:协调者搜集选举结果并且做出决定:如果结果是“否定”,则通知

所有曾回答“同意”的参与者执行流产操作,同时自己亦执行流产操作;如果

决定是“同意”,则向所有参与者发送“预提交”请求。参与者在这个阶段等

待来自协调者的通知,如果通知“流产”,则执行流产操作;如果通知是“预

提交”,则向协调者返回“收到预提交”回应。 第三阶段:协调者搜集来自参与者的回应。当收到全部回应后,向所有参与

者发送“执行提交”通知,同时自己亦执行提交操作。协调者接收到“执行提

交”通知后立即提交。 假定协调者和参与者有采用超时技术判断故障,那么,当协调者出现故障时,

3PC 协议能够防止参与者发生阻塞的现象吗?请详细解释你的回答(你可以假

定通信是可靠的,不会有信件丢失现象)。 7.11 当分布式嵌套事务处理采用 2PC 协议时,该协议如何保证当最高层事务处理

提交时,它的直接下属子事务处理都能够提交或流产? 7.12 假设我们有两个分布式事务处理,交替地在若干服务器上执行。那么,是否

会出现这样一种情况:在每一台服务器上这两个事务处理的分解操作都顺序

等价,但把所有服务器的分解操作都综合到一起,却不是全局顺序等价?请

用具体的例子证明你的回答。 7.13 把两阶段锁并发控制算法扩展到分布式事务处理,并描述分布式事务处理如

何保证两阶段锁的局部性(即一台服务器的锁只能用来锁定该服务器管辖的

数据,不能跨越锁定其他服务器里的数据)。 7.14 假定事务处理服务器采用时间戳算法来控制局部并发。那么,如何改进时间

戳算法,使得该算法适应分布式事务处理?在什么样的条件下,时间戳的排

序关系使得两阶段提交协议成为多余的呢? 7.15 在分布式死锁检测算法中,当发现“死锁”而实际上却没有形成真正死锁的

现象称为“伪死锁”。例如,无论采用哪种分布式算法,都要利用通信来收

集信息,于是,当发现一条有向等待环时,可能环中某个结点发生流产,而

“流产”的信件尚在通信线路上传输。因此,鉴别“伪死锁”也是死锁检测

算法的一个重要任务。如果我们采用中央死锁检测程序,该程序维护一张全

局等待表。那么,当该程序进行死锁检测时,等待表中的某台服务器出现流

产,怎样才能鉴别“伪死锁”呢?请用具体例子进行解释。 7.16 如果采用边跟踪死锁检测算法,又如何鉴别“伪死锁”呢?请做出具体说明。

Page 95: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第九章 容 错 机 制

世界上不存在百分之百的完美,任何事物都有这样或那样的缺陷,计算机也不例外。

一台计算机由各种各样的硬件和软件组成,这些部件时不时地会出现故障或错误,导致

死机或运行失败。这些故障或错误往往是随机出现的,计算机用户无法预料这些情况的

出现,有时甚至察觉不到错误的出现。例如,人们曾发现过一台出故障的硬件一直以一

种令人难以理解的方式执行一段正确的程序,而且产生出非常奇怪的结果。如果一个计

算机系统能够对非预期的软件/硬件故障有适当的对策和应变措施,则我们说这个系统具

备一定的容错(fault tolerance)能力。在现实生活中,我们有很多计算机应用需要系统

的容错能力。例如,当飞机自动导航系统的计算机发生故障时,我们希望计算机能够检

测出故障,进行某种切换后继续正确地运行,否则就会机毁人亡。再如,当银行系统的

计算机出现故障时,我们希望系统至少能够把当前的账务处理保存下来,以便故障排除

后继续运行,否则就可能出现账目混乱。不同的应用对系统的容错能力有不同的要求,

其要求越高,所付出的代价也就越大。 在设计一个分布式系统的时候,我们同样要关心系统的容错能力。然而,与单机系

统相比,分布式系统的特殊之处在于故障的局部化,即系统的某个(些)局部成分出现

故障,这种故障可能会影响到系统的局部功能,而对系统的其他一些部分毫无影响。因

此,当局部故障出现时,系统能够自动地检测、分离、排除故障并且恢复运行,同时对

系统的全局性能不造成太大的损害,这就是分布式系统的一个重要设计目标。我们将在

这一章里着重讨论分布式系统的容错机制,其中包括容错处理的基本概念、要求和模型,

如何实现可靠的通信,以及当发现故障时如何排除并恢复运行。

9.1 基本概念和模型

简单地说,分布式系统是一组在不同计算机上运行的进程,这些进程可以通过某种

网络彼此通信,以期达到协同工作的目的。与进程所赖以运行的计算机相比,网络通信

的效率相对较慢而且不太可靠。当我们为分布式系统设计一套容错机制的时候,有两个

重要的出发点: 1)分布式系统中一个进程 P 可能依赖于不同计算机上其他进程提供的服务,如果

那些进程由于出现错误或故障而失去联系,则 P 无法正常运行。值得指出的是,在失去

联系的情况下,进程 P 甚至无法知道出错的原因,或许计算机死机,或许网络断开,或

许对方根本没有出错,只不过由于负载太重,而暂时无法提供所需的服务。 2)分布式系统中含有多台计算机,如果选取一组计算机联合执行同一个任务,当

个别或少数计算机出现错误和故障时,大多数计算机仍然能够正常地完成任务,从而避

免了局部故障所引起的全局崩溃。我们在前一章中讨论的分布式复制系统就是一个典型

的例子。

Page 96: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·208·

第一个出发点告诉我们,一个进程所依赖的服务可能会以各种各样、相互独立的错

误而宣告失败。第二个出发点告诉我们,利用多进程/多计算机的优点,可能会掩去潜在

的错误或故障。这两点看上去既相互关联又相互矛盾,设计者的责任就是从关联和矛盾

中找到答案。从这两点出发,我们需要首先弄清楚错误或故障的基本概念、出现范围、

故障种类,以及与容错处理技术相关的术语。 具备容错能力的系统与可信赖(dependable)的系统之间的关系非常紧密。所谓可

信赖系统指的是该系统应该具有下述性质: (1)可用性(availability) 一个系统可以即时投入使用(提供服务)的程度。在前一章关于分布式复制系统的

讨论中,我们曾指出复制的动机之一就是为了强化可用性,同时我们还给出具体的例子,

说明多副本的可用性要远远高于单副本的可用性。换句话说,一个可用性很高的系统几

乎在任何时刻都能够为用户提供服务。 (2)可靠性(reliability) 一个系统可以无故障持续运行的程度。与可用性相反,可靠性以时间周期为基准,

而不是以某个时刻为基准。也就是说,一个高度可靠的系统在相当长的时间周期里可

以无间断地为用户提供服务。可用性与可靠性之间差别看上去不显著,但却很重要。

例如,假定一个系统在每小时期间内死机 1 秒钟,即在 3600 秒中,有 3599 秒可用,

只有 1 秒不可用,则该系统的可用性为 99.997%,但这个系统的可靠性却令人失望之

极。反之,如果一个系统除了每年停机两周维修之外,不出任何故障, 一直持续运行,则这个系统的可靠性非常之高,而系统的可用性只能达到 96.2%。

(3)保险性(safety) 一个系统由于暂时故障而无法正常运行时,不会出现灾难性损失。对一般用户而

言,保险性并不起着关键作用,当系统发生故障时,大不了损失一点时间,或丢失一

些运行数据。但对高危险性的应用,例如原子能发电站的控制系统、航空/航天自动控

制系统等,如果没有一定程度的保险系数,系统出现的任何微小故障都会造成无法挽

回的灾难性后果。实现一个保险的系统是非常困难的,譬如经过大量的疲劳试验,我

们知道某种电子开关的寿命是 20000 次,但在实际使用中,某个刚刚启用的电子开关

可能立即出现故障。提高保险系数的通常作法是采用冗余机制,我们会在下面的小节

里做出比较详细的介绍。值得指出的是,一个可信赖的系统还需要考虑安全性

(security),保险性并不等价于安全性,我们将在下一章里专门讨论安全性问题。 (4)可维护性(maintainability) 当一个系统出现故障时,排除故障的容易程度。毫无疑问,如果一个系统能够自动

检测并且自动排除故障,这个系统的可维护性就相当高,其潜在含义是,如果一个系统

维护起来越容易,该系统的可用性也就越高,一般来说,实现故障自动检测相对简单,

而实现故障自动排除要困难得多。 如果一个系统无法满足对用户的承诺,这个系统被称为失灵(fail)。一个分布式系

统对用户的承诺通常是通过一组服务兑现的,如果该系统无法兑现其中的某些服务,则

我们说这个分布式系统失灵。一个系统在正常工作时会在若干种运行状态之间变迁,一

Page 97: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第九章 容 错 机 制 ·209·

旦出现异常,则该系统进入错误(error)状态。一个系统的错误状态可能是导致系统失

灵的原因。这里我们使用了一个模糊的术语“可能”,因为有的错误状态并不一定导致

系统失灵,如系统死锁是一种错误状态,当死锁被排除后,系统又可以恢复正常运行。

反之,有的错误状态,如网络断开、电源中断、信件乱码等,就会引发系统失灵。造成

错误的原因是故障(fault),故障的种类繁多,软件和硬件都有可能产生故障,而且在

某些场合下,与系统无关的外部环境也可能引发故障。例如,当我们发现某些信件包乱

码时,造成乱码的原因可能是由于网卡故障,或者链路中转器故障。如果的确是由这些

部件造成的乱码,我们可以更换发生故障的器件。但是,有时候信件乱码的原因可能来

自于恶劣的天气,尤其在无线通信环境下,恶劣天气造成的影响就更为严重。对这样一

类外部环境引发的故障,我们就变得无能为力了。 在设计一个可信赖的系统时,重要的一面是控制故障,其中包括故障预报、故障检

测以及故障排除等方面的工作。这些工作涉及很多其他领域里的知识,超出了本书的范

围。这里我们所关心的是在出现错误的情况下,如何保证一个分布式系统仍然可以兑现

服务,即如何体现和提高一个分布式系统的容错能力。

9.1.1 故障分类

一个分布式系统中可能出现的故障多种多样,不可枚举。然而,我们可把各种故障按

照其属性加以分类,并且根据不同的故障类别来考虑相应的处理技术。从存在时间方面来

看,我们可以把故障分为 3 类:瞬间故障、间歇故障以及永久故障。瞬间故障一纵即逝,

来去无踪。如果某个操作发生瞬间故障,而我们重复那个操作的话,故障就不再发生。例

如,当我们利用微波通信发送信件时,可能由于飞鸟突然穿越微波束而导致乱码,那么,

把这封信件重发一次就成功了。间歇故障一般指那些会重复出现但无规律可寻的故障。例

如,当网络接口没有插牢的时候,微小的震动就会引发无规律的间歇故障。间歇故障的来

源很难诊断,往往是你检查的时候,它不出现,而投入运行时,它又冒了出来。永久故障

不难理解,凡是一直存在的故障,如芯片烧毁、硬盘划破、软件错误等,都属于这个范畴。

除非我们更换了出现故障的部件,否则永久故障会一直存在。 从分布式系统所承诺的服务来看,我们有另外一些故障分类方法。典型的分类法由

Cristian 提出,这个方法不仅对故障进行分类,而且为每一类故障定义出故障语义(failure semantics)。定义故障语义的重要性在于防止或避免继承性故障。例如,当我们设计一

种新服务时,如果这个新服务依赖于某些已经存在的旧服务,那么在掌握旧服务故障语

义的基础上,我们就可以在新服务的设计中力图屏蔽旧服务潜在的缺陷。TCP/IP 协议就

是一个典型的例子。IP 是一种不可靠的数据包通信协议,如果说不可靠是一种潜在的故

障的话,则 IP 的故障语义可描述为“信息包可能丢失、可能错序”。TCP 的设计者完全

了解这种故障语义,于是利用 IP 提交的服务构造了高层协议,与此同时掩去了 IP 协议

中的“故障”,为用户提供了一种可靠的数据流通信服务。 我们知道,当客户的请求发送到服务器执行后,服务器一端的资源状态可能会改变,

而且服务器可能会向客户返回执行结果。于是,Cristian 分类法假定仅当一台服务器的

状态和返回给客户的结果都正确无误时,该客户请求的服务才算正确完成。根据这个假

定,我们在表 9.1 中给出 Cristian 的服务故障分类。

Page 98: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·210·

表 9.1 Cristian 服务故障分类

故 障 类 故障子类 故障语义

服务器崩溃(停机) ,但停机前工作正常

失忆型崩溃 服务器只能从初始状态启动,遗忘了崩溃前的状态

中顿型崩溃 服务器可以从崩溃前的状态启动 崩溃故障

停机型崩溃 服务器完全停机

服务器无法兑现请求的服务

接收型失职 服务器无法接收信件 失职故障

发送型失职 服务器无法发送信件

服务器对服务请求做出错误反应

返回值故障 返回值出现错误 应答故障

状态变迁故障 服务器偏离正确的运行轨迹

时间故障 服务器反应迟缓,超出规定的时间间隔

任意故障 服务器在任意时间产生的任意错误

1. 崩溃故障

一台服务器崩溃(crash)表示该服务器由于某种异常事故而停机,对来自外界的请求

(无论来自客户还是来自其他服务器)都毫无反应。对客户而言,当得不到来自服务器的反

应时,很难判定该服务器是否崩溃还是出自于其他原因。一般情况下,客户要多次尝试连

接或者发送服务请求,如果这些尝试都宣告失败,客户便假定服务器崩溃。而对服务器而

言,解决崩溃的方法无非是找到事故原因,然后重新启动。服务器崩溃故障的恢复技术取

决于故障的子类别。例如,当产生中顿型崩溃(pause-crash)时,系统记载崩溃前那一刻的

状态,因此可以从崩溃前的状态恢复运行。而当服务器发生失忆型崩溃(amnesia-crash)时,

所有崩溃前的运行状态都已经丢失,系统只能从初始状态启动。由于大多数个人计算机用

户已经习惯了计算机崩溃,在重启计算机时,所看到的都是失忆型崩溃后的恢复技术。无

需多言,当服务器硬件损坏时,便产生停机型崩溃(halting-crash)。这时我们无法重新启动

系统,只能在更换硬件后重新安装系统,然后进行原始启动。

2. 失职故障

如果一台服务器还在运行但不能兑现服务时,就发生了失职(omission)故障。产

生服务器失职的原因很多,有些时候我们不能把责任完全推到服务器头上。例如,服务

器失职的一个子类是接收型失职,也就是说,服务器之所以无法兑现服务可能是因为它

根本就没有收到来自客户的请求。丢失客户请求的原因有多种,可能信件包在传送过程

中遗失,也可能服务器没有监听通信端口。无论如何,由于服务器尚没有执行来自客户

的服务请求,这类故障不会影响到服务器自身的状态。另一方面,当服务器执行了服务

请求而返回结果失败时,就出现了发送型失职故障,造成这类故障的原因也不少,例如

返回信件丢失,或者发送缓冲溢出等。麻烦的是,当出现发送失职故障时,服务器的状

Page 99: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第九章 容 错 机 制 ·211·

态可能已经被改变。因此,服务器要采取适当的措施,以应付客户重新发来的服务请求。

3. 应答故障

在授理一个服务请求时,如果服务器对这个请求做出了错误反应,就产生了应答

(response)故障。应答故障有两个子类:返回值故障和状态变迁故障。如果服务器返回

给客户的值是错误的,则称为返回值故障。反之,如果服务器对客户请求错误理解,因

而变迁到一种非预期的状态时,就称为状态变迁故障。这一类故障的后果很严重,因为

服务器看上去在正常运行,但运行的效果要么误导客户,要么误导服务器。 为了进一步理解失职故障和应答故障的不同之处,让我们来看两个具体的例子。用

户数据包协议 UDP 存在失职故障,因为该协议不保证信件的可靠提交,有丢失信件的

可能性。然而,UDP 却没有应答故障,因为它采用校验码屏蔽了 IP 协议中可能出现的

乱码现象。再如,我们曾在第三章中讨论过各种 RPC 语义,诸如至少一次语义,至多

一次语义等。由于信件传送协议存在失职故障,RPC 的至少一次语义就利用重发技术来

屏蔽这种故障。但是,至少一次语义的重发技术可能造成远程过程的多次调用,如果服

务器一端没有采取适当的措施,就会出现应答故障(状态变迁故障),而 RPC 的至多一

次语义采用客户端的调用重发技术和服务器端的副本过滤加结果重发技术,这样不仅屏

蔽了失职故障,也屏蔽了应答故障。当然,实现至多一次语义需要更大的系统开销。

4. 时间故障

另一类故障与时间有关,其关键是在给定的 大时间间隔里,客户发出的服务请求

没有得到任何回应。实际上,如果我们把系统的范围从客户/服务器模型扩大到各种其他

模型上,服务回应来得太早或者太晚,都会产生时间故障。回应太晚容易理解,当一个

服务器负载过重时,就无法对客户服务请求做出及时的回应,尽管 终兑现了服务,但

客户等待超时,这种现象就属于时间故障。我们在第三章讨论的流式通信中,提到等时

传输模式,即在多媒体应用中,数据单元的传输被限定在 大和 小这一对延迟时间内,

所请求的数据服务既不能滞后,也不能超前。如果服务回应太快了,也属于时间故障的

范畴。

5. 任意故障

为严重的故障是任意故障,也称作拜占庭(Byzantine)故障。Cristian 认为这类

故障囊括了上述所有故障的故障语义,并且用拜占庭这个名词来描述服务器可能出现的

坏故障。拜占庭一词来自于中世纪著名的拜占庭帝国。拜占庭帝国的版图曾以巴尔干

半岛和今天的土耳其为主要部分。从文化的角度看,拜占庭文化是世界历史上的一颗耀

眼的明珠。第一个伟大的拜占庭皇帝是查士丁尼一世(482~565),他的野心是恢复古

罗马帝国,只可惜功败垂成。有趣的是,我们这里所援引的含义并不是拜占庭文化优秀

的一面,而是其卑劣的统治手段和军事手段。譬如拜占庭的军队常透过间谍网络和秘密

特工提供有关敌军计划的资料,并且常以贿赂和诈骗诱惑敌人。拜占庭政府的官僚体系

错综复杂,阴谋诡计层出不穷,因而使得“拜占庭”一词含有“奸诈、撒谎、迂回、偷

Page 100: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

分布式系统 ·212·

偷摸摸”的语义。于是,当一个分布式系统出现拜占庭故障时,客户就必须应付 坏的

情况。例如,一台服务器可能会返回给客户一种不该出现的错误结果,而客户却不知道

也检测不出这种错误。更糟糕的是,一台出现拜占庭故障的服务器可能有意影响其他服

务器,合作产生错误结果,而使得整个系统陷入拜占庭故障。 拜占庭故障与前面讨论的崩溃故障密切相关,因为两者都会导致系统崩溃。然而,

崩溃故障语义要比拜占庭故障语义清晰的多,有人把崩溃故障称为失灵停机(fail-stop)故障,即失灵的服务器立即停止,不再产生任何输出,故而其他服务器可以检测出失灵

的服务器。反之,由于拜占庭故障而崩溃的服务器还可能不停地产生错误的输出,导致

其他服务器的误解。

9.1.2 硬件容错机制

如果一个分布式系统的硬件出现故障, 好的解决方法是把故障隐藏起来,使得

这个故障不影响其他正常工作的部件。我们把隐藏故障的想法称为故障屏蔽(masking),而常用的故障屏蔽技术是使用冗余(redundancy)部件。一般而言,根据不同的故障类

型,我们可以有 3 种冗余方法:信息冗余、时间冗余以及物理冗余。 作为一个例子,我们前一章中讨论的复制技术在某种程度上起到信息冗余的作用。

此外,在数据传输过程中,为了防止噪音干扰,我们采用的海明(Hamming)校验也是

信息冗余技术。海明码的原理就是增加一些额外的字位,当正常字位出现错误时,可以

利用这些冗余字位进行判别或者校正。所谓时间冗余,一般指超时重发技术。我们在前

面的章节里多次讨论过这种技术,无论硬件或软件都可以利用超时技术来判断是否出现

故障,于是在故障情况下重新执行前一个失败的操作。尤其当故障属于瞬间故障或者间

歇故障时,时间冗余技术就显得非常有效。 在 3 种冗余技术中,物理冗余是 为常用的冗余技术。这种技术把额外的硬件设备

或者软件进程添加在系统中,使之作为一个功能整体,当个别部件发生故障的时候,其

他部件仍然能够提供正确服务。在我们的日常生活中,物理冗余的例子几乎无处不在。

例如,人人都生有两只眼睛、两只耳朵、两只肾脏,这就是与生俱来的生物冗余。再如,

波音 747 飞机只需要用 3 个引擎就可以安全飞行,但为了防止某个引擎发生故障,飞机

上安装了 4 套引擎,这就是人为的设备冗余。 在计算机领域里,为了提高外部存储器的容错能力,我们可以采用磁盘阵列(RAID,

redundant array of independent (or Inexpensive) disks),即将普通硬盘组成一个磁盘阵列,

当主机写入数据时,RAID 控制器把主机要写入的数据分解为多个数据块,然后并行写

入磁盘阵列;主机读取数据时,RAID 控制器并行读取分散在磁盘阵列中各个硬盘上的

数据,把它们重新组合后提供给主机。由于采用并行读写操作,RAID 不仅提高了存储

系统的存取效率,还可以采用镜像、奇偶校验等不同的 RAID 等级来提高系统的容错能

力,保证数据的可靠性。例如,RAID 被分为若干等级,分别为 0,1,2,3,4,5,6,10,50 以及 0+1,不同等级的系统具有不同的容错能力。严格地说,零级 RAID 并不

具备容错能力,只是一个磁盘阵列,提供高速访问能力而已。一级 RAID 采用镜像复

制方案,具备了一定的容错能力,如图 9.1(a)所示,而到了二级 RAID,就显示了

更强的容错能力。我们在图 9.1(b)中给出一个二级 RAID 的例子。图中,每一个数

Page 101: 重 点 院 校 推 荐 教 材 - abook.cn 布式系统7030167600-  · PDF file本书是作者在国外多年讲授分布式 ... 算、域名服务、同步与互斥、时间与协作、分布式事务

第九章 容 错 机 制 ·213·

据都被复制在不同的磁盘上,如 A0 到 A3 都是数据 A 的副本,此外,每一个数据的

海明码都被记录在一组错误校验码(ECC,error checking code)磁盘上。当执行读出

操作时,就可以使用 ECC 来验证数据并且纠正错误。RAID 的级别越高,容错能力越

强,价格也越昂贵。

B

A

B

A

F

E

F

E

J

I

J

I

N

M

N

M

镜像 镜像 镜像 镜像 (a) 一级 RAID:镜像复制

C

D

C

D

G

H

G

H

K

L

K

L

O

P

O

P

B0

A0

B1

A1

B2

A2

B3

A3

Bx

Ax

By

Ay

Bz

Az

例: A0~A3 为数据 A 的副本 例:Ax~Az 为数据 A 的 ECC (b)二级 RAID:海明码 ECC

C0

D0

C1

D1

C2

D2

C3

D3

Cx

Dx

Cy

Dy

Cz

Dz

图 9.1 磁盘阵列实例

除了磁盘之外,可冗余的设备还有 CPU(即多个 CPU 同时执行同样的指令流)、散

热风扇(一般服务器会采用 N+X 冗余,可以在 X 个风扇失灵的情况下确保正常降温)、

内存(一般服务器都应采用 ECC 容错内存,可使内存中的数据出错可能性减小为 0)、网卡(即多网卡冗余,保证网络连接和传输速度)、电源(一般服务器是采用 N+1 冗余

电源,即当一个电源出现故障时,服务器仍然能正常工作)等。毫无疑问,采用硬件设

备冗余技术可以大大提高系统的容错能力,但系统价格也相对提高许多。常用的冗余技

术是著名的模三冗余(TMR,triple modular redundancy)。显然,之所以以三为模,因为

三是实施“少数服从多数”原则的 少选举人数。于是,当三者中有两个意见相同时,

结论便等于这个多数的意见;而如果三者意见都不同(如同选举中一人同意,一人反对,

一人弃权),则无定论。当然,并非所有具备容错能力的分布式系统都必须采用 TMR 技

术,这里我们要说明的只是一种思想,使得读者能够清楚地理解什么叫做冗余容错能力。

9.2 进程容错机制

前面我们已经介绍了容错处理的概念、术语、故障分类、故障语义以及基本硬件容

错机制。这一节我们将要把重点放在分布式系统上,首先讨论处理进程故障的基本思想,

在这个基础上,我们引入如何在某些进程发生故障的情况下,其余的进程能够通过某种

协议达成一致,保证系统的正常运行。