Google Code大学
分布式系统设计简介
目录
受众和先决条件
基础
那么它是如何完成的?
远程过程调用
一些分布式设计原则
演习
参考
本教程介绍了分布式系统设计的基础知识。先决条件是使用C ++或Java等语言,对网络的基本理解以及数据结构和算法的重要编程经验。
什么是分布式系统?如果没有先定义许多其他东西,这是很难定义的事情之一。这是分布式系统的“级联”定义:
一个程序
是你写的代码。
一个过程
是你运行它时得到的。
一条消息
用于进程之间的通信。
一个包
是一条可能在电线上传播的消息片段。
一个协议
是对消息格式的正式描述,以及两个进程为了交换这些消息必须遵循的规则。
一个网络
是连接计算机,工作站,终端,服务器等的基础设施。它由通过通信链路连接的路由器组成。
一个组件
可以是运行流程所需的流程或任何硬件,支持流程之间的通信,存储数据等。
一个分布式系统
是一个应用程序,它执行协议集合以协调网络上多个进程的操作,以便所有组件一起协作以执行一组或一组相关任务。
为什么要构建分布式系统?有许多优点,包括以开放和可扩展的方式连接远程用户和远程资源的能力。当我们说开放时,我们的意思是每个组件都不断地与其他组件交互。当我们说可扩展时,我们的意思是系统可以很容易地改变,以适应用户,资源和计算实体数量的变化。
因此,考虑到分布式组件的组合功能,分布式系统可以比独立系统的组合更大,更强大。但这并不容易 - 对于分布式系统来说,它必须是可靠的。由于同时运行的组件之间的交互的复杂性,这是难以实现的目标。
为了真正可靠,分布式系统必须具有以下特征:
这些是高标准,难以实现。可能最困难的挑战是分布式系统即使在组件发生故障时也必须能够继续正确运行。这个问题将在下面的Ken Arnold访谈摘录中讨论。Ken是Sun的研究科学家,也是Jini的原始架构师之一,并且是设计CORBA的架构团队的成员。
失败是分布式和本地编程之间的定义差异,因此您必须设计具有失败预期的分布式系统。想象一下,问人们,“如果事情发生的可能性是10 13,那么它会发生多少次?” 常识是回答“从不”。就人类而言,这是一个无限大的数字。但是,如果你问一位物理学家,她会说,“一直都是这样。在一立方英尺的空气中,这些事情一直在发生。”
在设计分布式系统时,您必须说“失败始终发生”。所以当你设计时,你会设计失败。这是你最关心的问题。设计失败意味着什么?一个经典问题是部分失败。如果我向您发送消息然后发生网络故障,则有两种可能的结果。一个是消息传到了你,然后网络坏了,我只是没有得到回应。另一个是从来没有告诉过你的消息,因为网络在它到达之前就已经破了。
因此,如果我从未收到回复,我怎么知道这两个结果中的哪一个发生了?没有最终找到你,我无法确定。网络必须修复或者你必须上来,因为可能发生的事情不是网络故障,而是你死了。这如何改变我的设计方式?首先,它将简单性的乘数放在一个乘数上。我能做的事情越多,我就越需要考虑恢复。[2]
处理故障是分布式系统设计中的一个重要主题。失败分为两个明显的类别:硬件和软件。直到80年代后期,硬件故障才成为主要问题,但从那时起内部硬件可靠性大大提高。减小较小电路的发热量和功耗,减少芯片外连接和布线,以及高质量的制造技术都在提高硬件可靠性方面发挥了积极作用。今天,问题通常与连接和机械设备有关,即网络故障和驱动器故障。
软件故障是分布式系统中的一个重要问题。即使经过严格的测试,软件漏洞仍占计划外停机时间的很大一部分(估计为25-35%)。成熟系统中的残留缺陷可分为两大类[5]。
Heisenbugs在分布式系统中比在本地系统中更普遍。其中一个原因是程序员难以获得并发过程交互的连贯而全面的视图。
让我们更详细地了解分布式系统中可能发生的故障类型:
我们的目标是设计一个具有上述特性的分布式系统(容错,高可用,可恢复等),这意味着我们必须设计失败。为了设计失败,我们必须小心不要对系统组件的可靠性做出任何假设。
当他们第一次构建分布式系统时,每个人都做出以下八个假设。这些在这个领域是众所周知的,它们通常被称为“8谬误”。
延迟:启动数据请求和实际数据传输开始之间的时间。
带宽:衡量通信信道容量的指标。信道带宽越高,信息带来的信息就越多。
拓扑:构建网络时可采用的不同配置,例如环形,总线,星形或网状。
同构网络:运行单一网络协议的网络。
构建一个在不可靠的通信网络上运行的可靠系统似乎是一个不可能实现的目标。我们被迫处理不确定性。进程知道自己的状态,并且知道最近其他进程处于什么状态。但是这些过程无法了解彼此的当前状态。它们缺乏共享内存的等价物。他们还缺乏准确的方法来检测故障,或者将本地软件/硬件故障与通信故障区分开来。
分布式系统设计显然是一项挑战性的工作。当我们不被允许做任何事情时,我们如何做到这一点,有那么多复杂性?我们首先限制范围。我们将专注于特定类型的分布式系统设计,该设计使用主要是标准协议的客户端 - 服务器模型。事实证明,这些标准协议为可靠的网络通信的低级细节提供了相当大的帮助,这使我们的工作更容易。让我们首先回顾一下客户端 - 服务器技术和协议。
在分布式系统中,可以存在许多特定类型的服务器,例如,多个文件服务器或多个网络名称服务器。术语服务用于表示特定类型的一组服务器。我们说 当需要访问服务的进程与提供服务的特定服务器相关联时,就会发生绑定。有许多绑定策略定义了如何选择特定服务器。例如,策略可以基于位置(Unix NIS客户端首先在自己的机器上查找服务器); 或者它可以基于负载平衡(CICS客户端以这样的方式绑定,即尝试对所有客户端进行统一响应)。
分布式服务可以采用数据复制,其中服务维护多个数据副本以允许在多个位置进行本地访问,或者在服务器进程可能崩溃时提高可用性。缓存是一个相关概念,在分布式系统中非常常见。我们说如果一个进程在本地维护了一个数据副本,就会缓存数据,以便在需要时再次快速访问。一个高速缓存命中是当一个请求来自高速缓存的数据满意,而不是从主要服务。例如,浏览器使用文档缓存来加速对常用文档的访问。
缓存类似于复制,但缓存的数据可能会变得陈旧。因此,可能需要一种用于在使用之前验证缓存数据项的策略。如果主服务主动刷新缓存,则缓存与复制相同。[1]
如前所述,客户端和服务器之间的通信需要可靠。您之前可能听说过TCP / IP。Internet协议(IP)套件是一组通信协议,允许在Internet和大多数商业网络上进行通信。传输控制协议(TCP)是该套件的核心协议之一。使用TCP,客户端和服务器可以创建彼此的连接,通过它们可以在数据包中交换数据。该协议保证从发送方到接收方的数据的可靠和有序传送。
IP套件可以看作一组图层,每个图层都具有仅使用下面图层功能的属性,并且只向上面的图层输出功能。实现由层组成的协议行为的系统称为协议栈。协议栈可以用硬件或软件实现,也可以两者混合实现。通常,只有较低层以硬件实现,较高层以软件实现。
资源:TCP / IP的历史反映了互联网的发展。以下是此历史的简要概述。
IP套件中有四层:
资源:有关IP套件的更多信息,请参阅Wikipedia文章。
许多分布式系统是使用TCP / IP构建的,作为组件之间通信的基础。随着时间的推移,客户端与服务器交互的有效方法演变为RPC,这意味着远程过程调用。它是一种基于扩展本地过程调用概念的强大技术,因此被调用过程可能不存在于与调用过程相同的地址空间中。这两个进程可能位于同一系统上,也可能位于不同的系统上,并且网络连接它们。
RPC类似于函数调用。与函数调用一样,当创建RPC时,参数将传递给远程过程,并且调用者将等待返回响应。在下图中,客户端进行过程调用,向服务器发送请求。客户端进程等待,直到收到回复或超时。当请求到达服务器时,它调用执行所请求服务的调度例程,并将回复发送到客户端。RPC调用完成后,客户端进程继续。
线程在基于RPC的分布式系统中很常见。每个传入服务器的请求通常都会生成一个新线程。客户端中的线程通常会发出RPC然后阻塞(等待)。收到回复后,客户端线程将恢复执行。
编写基于RPC的代码的程序员做了三件事:
通信协议由协议编译器生成的存根创建。存根是一个例程,除了声明自身及其接受的参数之外,实际上并没有做太多的事情。存根包含足够的代码以允许它被编译和链接。
客户端和服务器程序必须通过协议中指定的过程和数据类型进行通信。服务器端注册可由客户端调用的过程,并接收和返回处理所需的数据。客户端调用远程过程,传递任何所需数据并接收返回的数据。
因此,RPC应用程序使用存根生成器生成的类来执行RPC并等待它完成。程序员需要在服务器端提供类,这些类提供处理RPC请求的逻辑。
RPC引入了一组本地过程编程中不存在的错误情况。例如, 当客户端启动时服务器未运行时,可能会发生绑定错误。 如果客户端是针对服务器的一个版本编译的,则会发生版本不匹配,但服务器现在已更新为较新版本。服务器崩溃,网络问题或客户端计算机上的问题可能导致超时。
某些RPC应用程序将这些类型的错误视为不可恢复。但是,容错系统具有关键服务的备用源以及从主服务器到备份服务器的故障转移。
当客户端需要知道请求的结果以便在服务器发生故障后采取下一步骤时,会发生具有挑战性的错误处理案例。这有时会导致不正确的操作和结果。例如,假设客户端进程请求售票服务器检查卡内基音乐厅管弦乐部分的座位。如果可用,服务器会记录请求和销售。但是请求因超时而失败。座位是否可用且销售情况如何?即使有可以重新发出请求的备份服务器,也存在客户将被出售两张票的风险,这在卡内基音乐厅[1]中是一个昂贵的错误。
以下是一些需要处理的常见错误情况:
鉴于我们到目前为止所涵盖的内容,我们可以定义一些每个分布式系统设计人员和软件工程师应该知道的基本设计原则 其中一些可能看起来很明显,但随着我们开始有一个好的起始列表,这将是有帮助的。
如果进程存储了无法重建的信息,则会出现问题。一个可能的问题是,“你现在是一个单点故障吗?” 我现在必须和你谈谈- 我不能跟别人说话。那么如果你下来会发生什么?要解决此问题,您可以复制。复制策略在减轻维护状态的风险方面也很有用。但是这里也存在挑战:如果我与一个复制者交谈并修改一些数据,那么我会与另一个人交谈怎么办?这种修改是否保证已经到达另一个?如果网络被分区并且复制者无法相互通信会发生什么?有人可以继续吗?
在决定维护状态的方式和位置以及何时使用缓存和复制方面存在一系列权衡。由于设置不同机制的开销,在这些场景中运行小测试更加困难。
[1] Birman,Kenneth。可靠的分布式系统:技术,Web服务和应用程序。纽约:Springer-Verlag,2005年。
[2] 采访Ken Arnold
[3] 八大谬误
[4] 关于IP套件的维基百科文章
[5] Gray,J。和Reuter,A。Transaction Processing:Concepts and Techniques。San Mateo,CA:Morgan Kaufmann,1993。
[6] Bohrbugs和Heisenbugs
引自:http://www.hpcs.cs.tsukuba.ac.jp/~tatebe/lecture/h23/dsys/dsd-tutorial.html