分布式系统概念原理以及应用介绍

※发布时间:2016-4-19 20:07:00   ※发布作者:小编   ※出自何处: 

  分布式系统是什么意思?分布式系统原理又是怎样?分布式系统有哪些应用?本文将详细解释。

  分布式系统

  分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。内聚性是指每一个数据库分布节点高度自治,有本地的数据库管理系统。透明性是指每一个数据库分布节点对用户的应用来说都是透明的,看不出是本地还是远程。在分布式数据库系统中,用户感觉不到数据是分布的,即用户不须知道关系是否分割、有无副本、数据存于哪个站点以及事务在哪个站点上执行等。

  分布式系统概念

  在一个分布式系统中,一组的计算机展现给用户的是一个统一的整体,就好像是一个系统似的。系统拥有多种通用的物理和逻辑资源,可以动态的分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。系统中存在一个以全局的方式管理计算机资源的分布式操作系统。通常,对用户来说,分布式系统只有一个模型或范型。在操作系统之上有一层软件中间件(middleware)负责实现这个模型。一个著名的分布式系统的例子是万维网(World Wide Web),在万维网中,所有的一切看起来就好像是一个文档(Web页面)一样。

  在计算机网络中,这种统一性、模型以及其中的软件都不存在。用户看到的是实际的机器,计算机网络并没有使这些机器看起来是统一的。如果这些机器有不同的硬件或者不同的操作系统,那么,这些差异对于用户来说都是完全可见的。如果一个用户希望在一台远程机器上运行一个程序,那么,他必须登陆到远程机器上,然后在那台机器上运行该程序。

  分布式系统和计算机网络系统的共同点是:多数分布式系统是建立在计算机网络之上的,所以分布式系统与计算机网络在物理结构上是基本相同的。

  他们的区别在于:分布式操作系统的设计思想和网络操作系统是不同的,这决定了他们在结构、工作方式和功能上也不同。网络操作系统要求网络用户在使用网络资源时首先必须了解网络资源,网络用户必须知道网络中各个计算机的功能与配置、软件资源、网络文件结构等情况,在网络中如果用户要读一个共享文件时,用户必须知道这个文件放在哪一台计算机的哪一个目录下;分布式操作系统是以全局方式管理系统资源的,它可以为用户任意调度网络资源,并且调度过程是“透明”的。当用户提交一个作业时,分布式操作系统能够根据需要在系统中选择最合适的处理器,将用户的作业提交到该处理程序,在处理器完成作业后,将结果传给用户。在这个过程中,用户并不会意识到有多个处理器的存在,这个系统就像是一个处理器一样。

  专业测评

      分布式软件系统(Distributed Software Systems)是支持分布式处理的软件系统,是在由通信网络互联的多处理机体系结构上执行任务的系统。它包括分布式操作系统、分布式程序设计语言及其编译(解释)系统、分布式文件系统和分布式数据库系统等。

  分布式操作系统

  负责管理分布式处理系统资源和控制分布式程序运行。它和集中式操作系统的区别在于资源管理、进程通信和系统结构等方面。

  分布式程序设计语言用于编写运行于分布式计算机系统上的分布式程序。一个分布式程序由若干个可以执行的程序模块组成,它们分布于一个分布式处理系统的多台计算机上被同时执行。它与集中式的程序设计语言相比有三个特点:分布性、通信性和稳健性。

  分布式文件系统

  具有执行远程文件存取的能力,并以透明方式对分布在网络上的文件进行管理和存取。

  分布式数据库系统

  由分布于多个计算机结点上的若干个数据库系统组成,它提供有效的存取手段来这些结点上的子数据库。分布式数据库在使用上可视为一个完整的数据库,而实际上它是分布在地理分散的各个结点上。当然,分布在各个结点上的子数据库在逻辑上是相关的。

  分布式邮件系统

  分布式邮件系统的部署设计,即同一域名下,跨地域部署的邮件系统。适用 于在各地设有分部的机构或者大型集团,有效管理各地的人员结构,同时提高了邮件服务器应用效率。[1] 分布式邮件系统由多个数据中心组成,大量分支机构或较小的分散站点与数据中心的连接。分支机构需要建立自己的邮件服务器,来加快处理当地分支机构的邮件。承载相应的数据处理量。以提高邮件处理能力,邮件收发速度,邮件功能模块化。

   

      在了解了分布式系统的基本概念之后,我们来看看分布式系统的原理是怎样的?

      【分布式系统原理】

      分布式系统基础要点

      对外提供无状态节点,内部实现具体有状态或者无状态节点逻辑,节点即可以是提供服务,也可以是存储数据。

      拜占庭问题,在分布式系统中的使用,目的是服务可用,而不是找出错误的节点,如果。

      异常常见情况,机器宕机、网络异常、消息丢失、消息乱序、数据错误、不可靠的TCP。可能是收到消息后宕机、也可能是处理完成以后机器宕机、处理完成任务后发送确认消息是网络异常。也有可能是发出去的消息丢失,或者发送确认消息时丢失。可能先发送出去的数据后收到

      分布式状态、成功、失败、超时。超时的情况,不能判断是否成功,原有同上。

      数据存储在机械硬盘上,随时有可能发生异常,导致数据没有能正确存储。

      无法归类的异常,比如,系统的处理能力时高、时低,的诡异行为。

      即使是小概率事件,在每天百万、千万、及以上的运算量时也会上升为大概率事件。

      副本提高数据的冗余,提高系统的可用性,但是在使用副本代来好处的同时,也导致副本需要成本。如副本的一致性,多个副本一致性,多个副本直接可能到不一致。

      一致性级别:强一致性、单调一致性,读取最新数据、会话一致性,通过版本读取统一值。最终一致性、弱一致性。

      分布式系统性能指标:吞吐量、响应延迟、并发量;常用单位QPS,即每秒钟的处理能力。高吞吐量会带来低响应、他们之间是相互制约关系。

      可用性指标:可以服务时间和非服务时间的比率和请求的成功和失败次数来衡量。

      可扩展性指标:实现能水平扩展,增加低配置的机器即可以实现更大的运算量,和更高的处理能力。

      一致性指标:实现副本间的一致性能力,一致性需要严格考量是否业务允许。

      二、分布式系统原理:

      1.哈希方式,把不同的值进行哈希运算,映射到,不同的机器或者节点。考虑冗余的时候可以把多个哈希值映射到同一个地方。哈希的实现方式,取余。其实现扩展时,比较困难,数据分散在很多机器上,扩展的时候要从个机器上获取数据。而且容易出现分布不均有的情况。

      常见的哈希,用IP、URL、ID、或者固定的值进行哈希,总是得到相同的结果。

      2.按数据范围分布,比如ID在1~20的在机器A上,ID在21~40的在机器B上,ID在40~60的在机器C上实现,ID在60~100的分布在机器D上,数据分布比较均匀。如果某个节点处理能力有限,可以直接该节点。数据分布的元信息,可能出现单点瓶颈。几千机器,每个机器又划分为N个范围,导致需要的数据分布范围元数据过大,导致可能需要几台机器实现。

      一定要严格控制元数据量,进可能的减少元数据的存储。

      3.按数据量分布,另一类常用的数据分布方式则是按照数据量分布数据。与哈希方式和按数据范围方式不同,数据量分布数据与具体的数据特征无关,而是将数据视为一个顺序增长的文件,并将这个文件按照某一较为固定的大小划分为若干数据块(chunk),不同的数据块分布到不同的服务器上。与按数据范围分布数据的方式类似的是,按数据量分布数据也需要记录数据块的具体分布情况,并将该分布信息作为元数据使用元数据服务器管理。

      由于与具体的数据内容无关,按数据量分布数据的方式一般没有数据倾斜的问题,数据总是被均匀切分并分布到集群中。当集群需要重新负载均衡时,只需通过迁移数据块即可完成。集群扩容也没有太大的,只需将部分数据库迁移到新加入的机器上即可以完成扩容。按数据量划分数据的缺点是需要管理较为复杂的元信息,与按范围分布数据的方式类似,当集群规模较大时,元信息的数据量也变得很大,高效的管理元信息成为新的课题。

      4.一致性哈希,构造哈希环,有哈希域[0,10],则构造3个部分,[1,4)/[4,9)/[9,10),[0,1)/分成了3个部分,这3部分是一个环状,增加机器时,变动的是其附近的节点,分担的是附近节点的压力,其元数据的和按数据量分布一样。其未来的扩展,可以实现多个需节点。

      5. 构建映射元数据,建立映射表的方式。

      6. 副本与数据分布,把一个数据副本分散到多台服务器上。比如应用A的数据,存储在A、B、C ,3台机器上,如果3台机器中,其中一台出现问题,请求被处理到其他2台机器上,如果加机器恢复,还需要从另外2台机器上,Copy数据,又增加了这2台机器的负担。如果我们有应用A和应用B,各自有3台机器,那么我们可以把A应用分散在6台机器上,B应用也分散在6台机器上,可以实现相同的数据备份,但是应用存储的数据被分散了。某台机器损害,只是把该机器所承担的负载平均分配到了,另外5台机器上。恢复数据从5台机器恢复,其速度快和给各台服务器的压力都不大,而且可以实现机器损害,更换完全不影响应用。

      其原理是多个机器互为副本,是比较理想的实现负载分压的方式。

      7.分布式计算思想,移动数据不如移动计算,就进计算原则,减少跨进程、跨网络、等跨度较大的实现,把计算所需的资源尽可能的靠近。因为可能出现网络、远程机器的瓶颈。

      8. 常见分布式系统数据分布方式: GFS、HDFS:按数据量分布;Map reduce 按GFS的数据分布做本地化;BigTable、HBase按数据范围分布;Pnuts按哈希方式或者数据范围分布,可以选择;Dynamo、Cassndra按一致性哈希;Mola、Armor、BigPipe按哈希方式分布;Doris按哈希方式和按数据量分布组合。

      三、数据副本协议

      1. 副本一定要满足一定的可用性和一致性要求、具体容错能力,即使出现一些问题也能提供可靠服务。

      2. 数据副本的基本协议,中心化和去中心化2种基本的副本控制协议。

      3.中心化副本控制协议的基本思是由一个中心节点协调副本数据的更新、副本之间的一致性。中心化副本控制协议的优点是协议相对较为简单,所有的副本相关的控制交由中心节点完成。并发控制将由中心节点完成,从而使得一个分布式并发控制问题,简化为一个单机并发控制问题。控制问题,简化为一个单机并发控制问题。所谓并发控制,即多个节点同时需要修改副本数据时,需要解决“写写”、“读写”等并发冲突。单机系统上常用加锁等方式进行并发控制。对于分布式并发控制,加锁也是一个常用的方法,但如果没有中心节点统一进行锁管理,就需要完全分布式化的锁系统,会使得协议非常复杂。中心化副本控制协议的缺点是系统的可用性依赖于中心化节点,当中心节点异常或与中心节点通信中断时,系统将失去某些服务(通常至少失去更新服务),所以中心化副本控制协议的缺点正是存在一定的停服务时间。即存在单点问题,即使中心化节点是一个集群,也只不过是一个大的单点。

      4.副本数据同步常见问题,1)网络异常,导致副本没有得到数据;2)数据脏读,主节点数据已经更新,但是由于某种原因,没有得到最新数据;3)增加新节点没有得到主节点数据,而读数据时从新节点读数据导致,没有得到数据。

      5.去中心化副本控制协议没有中心节点,协议中所有的节点都是完全对等的,节点之间通过平等协商达到一致。从而去中心化协议没有因为中心化节点异常而带来的停服务等问题。然而,没有什么事情是完美的,去中心化协议的最大的缺点是协议过程通常比较复杂。尤其当去中心化协议需要实现强一致性时,协议流程变得复杂且不容易理解。由于流程的复杂,去中心化协议的效率和性能较低。

      6. Paxos是唯一在工程中得到应用的强一致性去中心化副本控制协议。ZooKeeper、Chubby,就是该协议的应用。

      Zookeeper用Paxos协议选择Leader,用Lease协议控制数据是否有效。用Quorum协议把Leader的数据同步到follow。

      Zeekeeper,实现Quorum写入时,如果没有完全写入成功,则所有的follow机器,反向向Leader写数据,写入数据后follow又向Leader同步数据,保持一致,如果是失败的数据先写入,你们follow同步到原来的数据,相对于回滚;如是是最新的数据先写入Leader则就是完成了最新数据的更新。

      7. Megastore,使用的是改进型行Paxos协议。

      8. Dynamo / Cassandra使用基于一致性哈希的去中心化协议。Dynamo使用Quorum机制来管理副本。

      9. Lease机制是最重要的分布式协议,广泛应用于各种实际的分布式系统中。1)Lease通常定义为:颁发者在一定期限内給予持有者一定的协议。2)Lease 表达了颁发者在一定期限内的承诺,只要未过期颁发者必须严格遵守 lease 约定的承诺;3)Lease 的持有者在期限内使用颁发者的承诺,但 lease 一旦过期必须放弃使用或者重新和颁发者续约。4)的影响。中心服务器发出的lease的含义为:在lease的有效期内,中心服务器不会修改对应数据的值。5)可以通过版本号、过多上时间、或者到某个固定时间点认为Lease证书失效。

      其原理和我们的Cache一样,比如浏览器缓存道理一致。其要求时间时钟同步,因为数据完全依赖于期限。

      10. 心跳(heartbeat)检测不可靠,假如检测及其Q,被检测机器A,可能由于Q发起检测,但是A的回应被阻塞,导致Q 认为A宕机,阻塞很快恢复,导致根据心跳检测来做判断不可靠;也可能是他们之间的网络断开;也可能是Q机器本身异常导致认为A机器宕机;如果根据Q的检测结果,来判断很可能出现多个主机的情况。

      11. Write-all-read-one(简称WARO)是一种最简单的副本控制规则,顾名思义即在更新时写所有的副本,只有在所有的副本上更新成功,才认为更新成功,从而所有的副本一致,这样在读取数据时可以读任一副本上的数据。写多份,读从其中一份读取。

      12. quorum协议,其实就是读取成功的副本数大于失败的副本数,你们读取的副本里面一定包含了最新的副本。

      13. Mola和Armor系统中所有的副本管理都是基于Quorum,即数据在多数副本上更新成功则认为成功。

      14. Big Pipe中的副本管理也是采用了WARO机制。

      四、日志技术

      1.日志技术是宕机恢复的主要技术之一。日志技术最初使用在数据库系统中。严格来说日志技术不是一种分布式系统的技术,但在分布式系统的实践中,却广泛使用了日志技术做宕机恢复,甚至如BigTable等系统将日志保存到一个分布式系统中进一步增强了系统容错能力。

      2. 两种比较实用的日志技术Redo Log与No Redo/No undo Log。

      3. 数据库的日志主要分为Undo Log、Redo Log、Redo/Undo Log与No Redo/No Undo Log。这四类日志的区别在更新日志文件和数据文件的时间点要求不同,从而造成性能和效率也不相同。

      4. 本节介绍另一种特殊的日志技术“No Undo/No Redo log”,这种技术也称之为“0/1目录”(0/1 directory)。还有一个主记录,记录当前工作目录,比如老数据在0目录下,新数据在1目录下,我们访问数据时,通过主纪录,记录当前是工作在那个目录下,如果是工作在目录0下,取目录0数据,反之取1目录数据。

      5. MySQL的主从库设计也是基于日志。从库只需通过回放主库的日志,就可以实现与主库的同步。由于从库同步的速度与主库更新的速度没有强约束,这种方式只能实现最终一致性。

      6. 在单机上,事务靠日志技术或MVCC等技术实现。

      7.两阶段提交的思比较简单,在第一阶段,协调者询问所有的参与者是否可以提交事务(请参与者投票),所有参与者向协调者投票。在第二阶段,协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有的参与者执行该决定。在一个两阶段提交流程中,参与者不能改变自己的投票结果。两阶段提交协议的可以全局提交的前提是所有的参与者都同意提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。可以这么认为,两阶段提交协议对于这种超时的相关异常也没有很好的容错机制,整个流程只能阻塞在这里,且对于参与者而言流程状态处于未知,参与者即不能提交本地节点上的事务,也不能放弃本地节点事务。

      8. 第一、两阶段提交协议的容错能力较差。

      9.第二、两阶段提交协议的性能较差。一次成功的两阶段提交协议流程中,协调者与每个参与者之间至少需要两轮交互4个消息“prepare”、“vote-commit”、“global-commit”、“确认global-commit”。过多的交互次数会降低性能。另一方面,协调者需要等待所有的参与者的投票结果,一旦存在较慢的参与者,会影响全局流程执行速度。

      10.顾名思义,MVCC即多个不同版本的数据实现并发控制的技术,其基本思想是为每次事务生成一个新版本的数据,在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取。在使用MVCC时,每个事务都是基于一个已生效的基础版本进行更新,事务可以并行进行。其思想是根据版本号,在多个节点取同一个版本号的数据。

      11. MVCC的流程过程非常类似于SVN等版本控制系统的流程,或者说SVN等版本控制系统就是使用的MVCC思想。

      五、CAP理论

      CAP理论的定义很简单,CAP三个字母分别代表了分布式系统中三个相互矛盾的属性:1)Consistency (一致性):CAP理论中的副本一致性特指强一致性(1.3.4 );

      2)Availiablity(可用性):指系统在出现异常时已经可以提供服务;

      3)Toleranceto the partition of network (分区):指系统可以对网络分区,这

      种异常情况进行容错处理。

      2.CAP理论指出:无法设计一种分布式协议,使得同时完全具备CAP三个属性,即1)该种协议下的副本始终是强一致性,2)服务始终是可用的,3)协议可以任何网络分区异常;分布式系统协议只能在CAP这三者间所有折中。

      

      在看完分布式系统的原理之后,相信你对分布式系统有了一定了解,如果你想更深入地研究分布式系统,请看下面的内容:分布式系统设计原理与方案

      【分布式系统设计原理与方案】

      一直在思考分布式系统设计的问题,业务对象原封不动的情况下部署在客户端和服务器端,可以根据配置文件选择是连接服务器还是连接本地的数据库,这个问题让我,我总是设想的客户端与服务器端通信的方式是最低端的Socket。花了两个晚上研究框架关于数据门户这块代码,才发现问题的关键所在:客户端与服务器端通信不能采用最低端的Socket,而要用高端的WebService、.NET Remoting或者是自己定义一种协议等,只要它们支持客户端直接根据服务器端的服务URL、类名、方法名和方法参数四个信息就可以调用服务器对应的类和方法就行。

      说明:本文中所表达的思想与CSLA.NET有很大区别,不要看了本文就以为是CSLA.NET的设计思想,也不要以为本文错误的解释了CSLA.NET,这不是一篇介绍CSLA.NET的文章,但纯思想上它们是相同的。

      分布式系统的部署

      平常我们都说三层架构,我认为它是一个广义的模型,更多层的设计可以合并相邻几层的方式最终回归到三层这个宽泛的概念上来,我的意思是:这些都只是概念,忘记这些概念去实际分析设计会离这些概念更近一些。

      接下来我要把三层变的更简单点,两层,数据访问层合并到业务层,统称为业务层,因为我们面对的问题不是分层的问题,而是分布式系统中各层应该怎么部署的问题。在CSLA.NET书中也说到业务层和数据访问层放到同一台机器上可以提高性能和容错性。因此他们俩的合并不影响分布式系统的部署。

      不过要解释的是数据库系统(CSLA.NET中说的数据存储和管理层)并没有考虑到三层中来,也就是它不包含在数据访问层中,如果把它算进来,那么它是在数据访问层之下单独存在的。

      综上,在分布式系统部署角度考虑的分层实际是三层:界面层、业务层(包含数据访问层的业务层)、数据存储层。

      下面举例说明可能的部署情景,带阴影的框框表示一台机器,虚线框表示根据使用场合可有可无,虚横线表示从此处划开单独出服务器。在B/S应用中,Web浏览器为客户端,其他全部为服务器。在C/S应用中,处在最上层的界面层业务层为客户端,其他为服务器。

      非分布式系统的部署

      分布式的C/S系统

      有几点要说明:

      1. 客户端上的验证等业务逻辑是不可信的,因此任何一种部署都需要服务器端包含业务层;

      2.为了开发、和部署中的高度可伸缩性,图中的各业务层所包含的代码都是一模一样的;

      3.因为第2点,所以我遇到了业务层的同一个操作是与其他机器上的业务层通信还是访问数据库这个难题。

      解决业务层的数据访问问题

      这个问题是关键问题,也就是几点说明中的第3个问题,为了解决这个问题我们引入数据门户的概念。

      下面以WebService为例说明:界面层访问本机的业务对象的增删改查中的“查”方法时,跳过数据库的查询操作,访问另一台机器中的同一个业务对象类的“查”方法。

      以上是向另一台机器发送请求,该请求并不直接调用另一台机器上的业务对象类的“查”方法,而是将要调用的业务对象和方法参数信息转为一个“二进制包”,作为参数去调用另一台机器上通用的“查”方法,另一台机器上的“查”方法再解开这个包,然后去调用解开的包中所表示的业务对象类型,下面的静态图是另一台机器接受到请求后的工作。

      又有些说明:

      1. 关于原理都已在图中做了描述,不另写大段文字解释了;

      2. 两个图中,除了“实际业务对象类”以外的部分全部属于架构或者框架部分;

      3.如果用OO的思想去审查的两个图,你一定会为这糟糕的设计而抱怨,这里只是为了尽可能简单的表述分布式系统的工作原理,你可以采用策略模式使数据门户不改变的情况下适应各种请求响应场合,采用工厂模式实现不同的请求响应场合的切换。

      关于数据库的分布

      为了解决数据库服务器的负担,我们可能希望把数据分布存储在多个服务器上,我设想的数据库分布方案是,各服务器上的数据库在结构上一模一样,而的数据存储到不同服务器上,这样数据访问层在查数据的时候分别向所有数据库服务器发送同样的sql命令,然后数据访问层得到数据后整合,这样减轻每台服务器的工作量。亦或者根据的某个代表性的字段(如:省份)分布数据到不同服务器。

   

  介绍完分布式系统相关原理之后,我们来了解下分布式系统的优势分析

      【分布式系统定义以及优势分析】

      分布式系统是个由多个互相连接的处理资源组成的计算机系统,它们在整个系统的控制下协同执行同一个任务,最少依赖于集中的程序、数据或硬件。这些资源可以是地理上相邻的,也可以是在地理上分散的。分布式系统隐含的共同特征是:场地分布、数据分布、硬件平台多样化、操作系统多样化、应用平台多样化。

      分布式系统的定义

      当讨论分布式系统时,我们面临许多以下这些形容词所描述的 同类型:分布式的、删络的、并行的、并发的和分散的。分布式处理是一个相对较新的领域,所以还没有‘致的定义。与顺序计算相比、并行的、并发的和分布式的计算包括多个PE问的集体协同动作。这些术语在范围一卜相互覆盖,有时也交换使用。

      “并行的”意味着从一个单一控制线程对数据集的锁步(1ockst ep)动作。

      在并行计算机级别上,指令流多数据流(SIMD)计算机就是一个使用多个数据处理单元在许多数据项上同时进行相同或相似操作的例子。

      “并发的”意味着某些动作可以以任意次序执行。例如,在史岛级别,卜和在多指令流多数据流(MIMD)并行计算机上进行部分的操作。

      “分布式的”意味着计算的成本或性能取决于数据和控制的通信。

      如果个系统的部件局限在一个地方,它就是集中式的:如果它的部件在不同地l20方,部件之间要么不存在或仅存在有限的合作,要么存在紧密的合作,它是分散式的。

      当一个分散式系统不存在或仅存在有限的合作时,它就被称作网络的;否则它就被称作分布式的,表示在不同地方的部件之间存在紧密的合作。在给出分布式系统具体定义的模型中,分布式系统可以用硬件、控制、数据这三个维度加以检验。

      分布式系统=分布式硬件 分布式控制 分布式数据

      分布式系统有很多不同的定义,但其中没有一个是令人满意或者能够被所有人接受的。介绍分布式系统,对它的特点的下列大致的描述足够了:

      “一个分布式系统是一些的计算机的集合,但是对这个系统的用户来说,系统就象一台计算机一样。”

      这个定义有两个方面的含义:第一,从硬件角度来讲,各个计算机都是自治的;第二,从软件角度来讲,用户将整个系统看作是一台计算机。这两者都是必需的,缺一不可。在简要介绍有关硬件、软件的一些背景材料之后,我们将再回到这两点上来进行讨论。

      由于给出分布式系统的一些实例可能要比进一步的深入研究定义更有帮助,下面就给出一些分布式系统的例子。第一个例子,设想一个大学或公司部门内的工作站网络。除了每个用户的个人工作站外,机房中可能还有一个共享的处理机池(pool of processor),这些处理机并没有分配给特定的用户,而是在需要的时候进行动态分配。这样的系统可能会有一个单一的文件系统,其中所有的文件可以从所有的计算机上以相同的方式并且使用相同的径名存取。另外,当一个用户输入一条命令时,系统能够找到一个最好的地方执行该命令。这可能是在用户自己的工作站上,可能是在别人空闲的工作站上,也可能在机房里一个未分配的处理机上。如果这个从系统整体上看以及运行起来看都像一个典型的单处理机分时系统,那么就可以称它为一个分布式系统。

      第二个例子,考虑一个到处是机器人的工厂。每个机器人都有一台功能强大的计算机用于处理视觉、进行计划、通信以及其它任务。当装配线上的某个机器人发现一个它要安装的零件有缺陷时,它就要求该零件供应部门的另一个机器人给它送一个替代品。如果所有的机器人都如同连接于同一中心计算机上的外设一样工作,而且系统的程序也是以这种方式进行编制的话,那么它也是一种分布式系统。

      最后一个例子是一个界各地有数百个分支机构的大银行。每个分支机构有一台主计算机存储当地帐目和处理本地事务。此外,每台计算机还能通过串口服务器与其他分支机构的计算机及总部的计算机对话。如果交易不管顾客和帐目在哪里都能够进行,而且用户也不会感到当前这个系统与被替代的老的集中式主机有何不同,那么这个系统也被认为是一个分布式系统。

      分布式系统的优势

      分布式系统与集中式系统相比较而言的优点

      系统倾向于分布式发展潮流的真正驱动力是经济。25年前,计算机权威和评论家Herb Grosch指出CPU的计算能力与它的价格的平方成正比,后来成为Grosch。也就是说如果你付出两倍的价钱,就能获得四倍的性能。这一论断与当时的大型机技术非常吻合,因而使得许多机构都尽其所能购买最大的单个大型机。

      随着微处理机技术的发展,Grosch不再适用了。现在人们只需花几百美元就能买到一个CPU芯片,这个芯片每秒钟执行的指令比80年代最大的大型机的处理机每秒钟所执行的指令还多。如果你愿意付出两倍的价钱,将得到同样的CPU,但它却以更高的时钟速率运行。因此,最节约成本的办法通常是在一个系统中使用集中在一起的大量的廉价CPU。所以,倾向于分布式系统的主要原因是它可以潜在地得到比单个的大型集中式系统好得多的性能价格比。实际上,分布式系统是通过较低廉的价格来实现相似的性能的。

      与这一观点稍有不同的是,我们发现微处理机的集合不仅能产生比单个大型主机更好的性能价格比,而且还能产生单个大型主机无论如何都不能达到的绝对性能。例如,按目前的技术,我们能够用10,000个现代CPU芯片组成一个系统,每个CPU芯片以50 MIPS(每秒百万指令)的速率运行,那么整个系统的性能就是500,000 MIPS。而如果单个处理机(即CPU)要达到这一性能,就必需在2×10-12 秒(2 微微秒,0.002纳秒)的时间内执行一条指令,然而没有一个现存的计算机能接近这个速度,从理论上和工程上考虑都认为能达到这一要求的计算机都是不可能存在的。理论上,爱因斯坦的指出光的速度最快,它能在2 微微秒内0.6毫米。实际上,一个包含于边长为0.6 毫米大小的立方体内的具有所说的计算速度的计算机产生大量的热量就能将它自己立即熔掉。所以,无论是要以低价格获得普通的性能还是要以较高的价格获得极高的性能,分布式系统都能够满足。

      另一方面,一些作者对分布式系统和并行系统进行了区分。他们认为分布式系统是设计用来允许众多用户一起工作的,而并行系统的唯一目标就是以最快的速度完成一个任务,就像我们的速度为500,000 MIPS的计算机那样。我们认为,上述的区别是难以成立的,因为实际上这两个设计领域是统一的。我们更愿意在最广泛的意义上使用“分布式系统”一词来表示任何一个有多个互连的CPU协同工作的系统。

      建立分布式系统的另一原因在于一些应用本身是分布式的。一个超级市场连锁店可能有许多分店,每个商店都需要采购当地生产的商品(可能来自本地的农场)、进行本地销售,或者要对本地的哪些蔬菜因时间太长或已经腐烂而必须扔掉作出决定。因此,每个商店的本地计算机能明了存货清单是有意义的,而不是集中于公司总部。毕竟,大多数查询和更新都是在本地进行的。然而,连锁超级市场的高层管理者也会不时地想要了解他们目前还有多少甘蓝。实现这一目标的一种途径就是将整个系统建设成对于应用程序来说就像一台计算机一样,但是在实现上它是分布的,像我们前面所描述的一个商店有一台机器。这就是一个商业分布式系统。

      另一种固有的分布式系统是通常被称为计算机支持下的协同工作系统(CSCW,Computer Supported Cooperative Work)。在这个系统中,一组相互之间在物理上距离较远的人员可以一起进行工作,例如,写出同一份报告。就计算机工业的长期发展趋势来说,人们可以很容易的想像出一个全新领域--计算机支持的协同游戏(CSCG:Computer Supported Cooperative Games)。在这个游戏中,不在同一地方的游戏者可以实时的玩游戏。你可以想像,在一个迷宫中玩电子捉迷藏,甚至是一起玩一场电子空战,每个人自己的本地飞行模拟器去试着击落别的游戏者,每个游戏者的屏幕上都显示出其飞机外的情况,包括其它飞入它的视野的飞机。

      同集中式系统相比较,分布式系统的另一个潜在的优势在于它的高可靠性。通过把工作负载分散到众多的机器上,单个芯片故障最多只会使一台机器停机,而其它机器不会受任何影响。理想条件下,某一时刻如果有5%的计算机出现故障,系统将仍能继续工作,只不过损失5%的性能。对于关键性的应用,如核反应堆或飞机的控制系统,采用分布式系统来实现主要是考虑到它可以获得高可靠性。

      最后,渐增式的增长方式也是分布式系统优于集中式系统的一个潜在的重要的原因。通常,一个公司会买一台大型主机来完成所有的工作。而当公司繁荣扩充、工作量就会增大,当其增大到某一程度时,这个主机就不能再胜任了。仅有的解决办法是要么用更大型的机器(如果有的话)代替现有的大型主机,要么再增加一台大型主机。这两种作法都会引起公司运转混乱。相比较之下,如果采用分布式系统,仅给系统增加一些处理机就可能解决这个问题,而且这也允许系统在需求增长的时候逐渐进行扩充。表1-1中总结了以上这些优点。

      从长远的角度来看,主要的驱动力将是大量个人计算机的存在和人们共同工作与信息共享的需要,这种信息共享必需是以一种方便的形式进行的,而不受地理或人员、数据,机器的物理分布的影响。

      分布式系统与PC机相比较的优点

      既然使用微处理机是一种节省开支的办法,那么为什么不给每个人一台个人计算机,让他们各自地工作呢?一则,许多用户需要共享数据。例如,机票预订处的工作人员需要访问存储航班以及现有座位信息的主数据库。假如给每个工作人员都备份整个数据库,那么在实际中这是无法工作的,因为没有人知道其他工作人员已经卖出了哪些座位。共享的数据是上例和许多其它应用的基础,所以计算机间必须互连。而计算机互连就产生了分布式系统。

      共享并不只是仅仅涉及数据。昂贵的外设,例如彩色激光打印机,排版机以及大型存储设备(如自动光盘点唱机)都是共享资源。

      把一组孤立的计算机连成一个分布式系统的第三个原因是它可以增强人与人之间的沟通,电子邮件比信件、电话和传真有更多的诱人之处。它比信件快的多,不像电话需要两人同时都在,也不像传真,它所产生的文件可在计算机中进行编辑、重排和存储,也可以由文本处理程序来处理。

      最后,分布式系统可能比给每个用户一个的计算机更灵活。尽管一种可能的模式是给每个人一台个人计算机并把它们通过LAN联在一起,但这种方式并不是唯一的。另外还存在一种模式是将个人计算机和共享计算机混合连接在一起(这些机器的型号可能并不完全相同),使工作能够在最合适的计算机上完成,而并不总是在自己的计算机上完成。这种方式可以使工作负荷能更有效地在计算机系统中进行分配。系统中某些计算机的失效也可以通过使其工作在其它计算机上进行而得到补偿。表1-2总结了以上所介绍的各点。

       分布式系统的缺点

      尽管分布式系统有许多优点,但也有缺点。本节就将指出其中的一些缺点。我们前面已经提到了最棘手的问题:软件。就目前的最新技术发展水平,我们在设计、实现及使用分布式系统上都没有太多的经验。什么样的操作系统、程序设计语言和应用适合这一系统呢?用户对分布式系统中分布式处理又应该了解多少呢?系统应当做多少而用户又应当做多少呢?专家们的观点不一(这并不是因为专家们与众不同,而是因为对于分布式系统他们也很少涉及)。随着更多的研究的进行,这些问题将会逐渐减少。但是目前我们不应该低估这个问题。

      第二个潜在的问题是通信网络。由于它会损失信息,所以就需要专门的软件进行恢复。同时,网络还会产生过载。当网络负载趋于饱和时,必须对它进行替换或加入另外一个网络扩容。在这两种情况下,一个或多个建筑中的某些部分必须花费很高的费用进行重新布线,或者更换网络接口板(例如用光纤)。一旦系统依赖于网络,那么网络的信息丢失或饱和将会抵消我们通过建立分布式系统所获得的大部分优势。

      最后,我们作为优点来描述的数据易于共享性也是具有两面性的。如果人们能够很方便地存取整个系统中的数据,那么他们同样也能很方便地存取与他们无关的数据。换句话说,我们经常要考虑系统的安全性问题。通常,对必须绝对保密的数据,使用一个专用的、不与其它任何机器相连的孤立的个人计算机进行存储的方法更可取。而且这个计算机被保存在一个上锁的十分安全的房间中,与这台计算相配套的所有软盘都存放在这个房间中的一个保险箱中。分布式系统的缺点如表1-3所示。

       表 1-3. 分布式系统的缺点

      尽管存在这些潜在的问题,许多人还是认为分布式系统的优点多于缺点,并且普遍认为分布式系统在未来几年中会越来越重要。实际上,在几年之内许多机构会将他们的大多数计算机连接到大型分布式系统中,为用户提供更好、更廉价和更方便的服务。而在十年之后,中型或大型商业或其它机构中可能将不再存在一台孤立的计算机了。

      分布式系统的应用

      分布式系统被用在许多不同类型的应用中。以下我们列出了一些应用。对这些应用而言,使用分布式系统要比其他体系结构如处理机和共享存储器多处理机更优越:

      并行和高性能应用

      原则上,并行应用也可以在共享存储器多处理机上运行,但共享存储器系统不能很好地扩大规模以包括大量的处理机。HPCC(高性能计算和通信)应用一般需要一个可伸缩的设计,这种设计取决于分布式处理。

      容错应用

      因为每个P E是自治的,所以分布式系统更加可靠。一个单元或资源(软件或硬件)的故障不影响其他资源的正常功能。

      固有的分布式应用

      许多应用是固有分布式的。这些应用是突发模式(burstmode)而非批量模式(bulk mode)。这方面的实例有事务处理和Internet Javad,程序。

      这些应用的性能取决于吞吐量(事务响应时阳J或每秒完成的事务数)而不是一般多处理机所用的执行时间。

      对于一组用户而言, 分布式系统有一个特别的应用称为计算机支持的协同工作(computer supported Cooperati veworking,CSCW)或群件(groupware), 支持用户协同工作。另一个应用是分布式会议,即通过物理的分布式网络进行电子会议。同样,多远程教学也是一个类似的应用。由于在不同的平台上如:Pc、工作站、局域网和广域网上可获得非常多样的应用,用户希望能超出他fliP c的以获得更广泛的特十牛、功能和性能。不同网络和(包括分布式系统)下的q 操作性变得越来越重要。为了达到互操作性,用户需要一个标准的分布式计算,在这个里,所有系统和资源都可用。

      DCE (分布式计算)是OSF (系统基金会)开发的分布式计算技术的工业标准集。它提供和控制对数据访问的安全服务、容易寻找分布式资源的名字服务、以及高度可伸缩的模型用于组织极为分散的用户、服务和数据。D C E可在所有主要的计算平台上运行, 并设计成支持异型硬件和软件下的分布式应用。

      DCE已经被包括TRANSVARL在内的一些r一商实现。TRANSVARL是最早的多厂商组(multi vendor team)的之一,它提出的已成为DC E体系结构的基础。在中可以找到利用DCE开发分布式应用的指南。具有标准接口和协议的系统也叫做系统。一些其它标准基于一个特别的模型,比如CORBA (公用对象请求代理程序体系结构),它是由OMG (对象管理组)和多计算机厂商联盟开发的一个标准。CORBA使用面向对象模型实现分布式系统中的透明服务请求。工业界有自己的标准,比如微软的分布式构件对象模型(DCOM)和Sun Microsystem公司的Java Beans。

      分布式系统的测试

      在测试执行过程中,对测试结果的分析是一个需要进行深入思考的重点问题。分布式系统测试的重点在于对后端服务器集群的测试,而判定系统中是否存在Bug则是我们需要解决的重要问题。那么应该如何确定是否存在Bug呢?

      对于测试结果的分析,我们通常观察下面几种情况。

      观察前端应用的返回结果。这里需要分两种情况来考虑:第一,按照前端应用业务功能点及流程进行操作,观察返回结果是否符合业务方的需求预期;第二,操作后端的服务器(通常是重启、宕机、断网等操作),观察前端应用的返回结果是否符合系统的设计需求。

      分析服务器日志。在功能测试过程中,当我们在启动服务器的时候,需要将日志级别定义为Debug级别(最低级别)。这样做的主要目的是为了能便于测试工程师来分析日志和定位问题。为了能更好地定位问题,常常需要在服务器程序代码中进行日志打桩,把程序中的一些重要数据通过日志的方式展现出来。通常情况下,我们需要对日志的格式进行约定,在日志行中增加一些关键字来进行分类,这将便于测试工程师进行日志分析,也有利于开展分布式系统的自动化测试。另外,值得注意的是,我们尽可能地将打桩代码放在Debug代码中,避免影响系统代码,引入新问题。

      分析操作系统的一些重要信息。我们测试的分布式系统绝大多数是基于Linux操作系统开发的,在测试的过程中,除了详细分析程序日志以外,还需要对操作系统的一些重要数据信息进行分析,从而来诊断服务器程序是否存在异常。以Linux操作系统为例,我们常常会使用top命令、netstat命令及sar命令来查看操作系统的一些数据信息。例如,可以通过netstat命令检查服务器程序是否正确地了指定的端口等。

      借助其他分析工具。例如,如何判断服务器程序是否产生了内存泄漏?通常需要借助于内存检测工具来进行分析。在Linux下,我们常用Valgrind来进行内存检测。这是一款非常好用、功能强大的分析工具,可以帮助测试或者开发工程师快速发现很多隐藏的程序Bug,尤其是在内存检测方面(同时它还具有很多其他优秀的功能,读者可以自己查看官网中的使用手册)。

      分布式系统压力测试与性能测试

      对于分布式系统而言,压力测试和性能测试非常重要。在进行压力测试和性能测试的时候,可能会碰到下面一些难点。

      数据准备。如何准备海量的测试数据并模拟数据的真实性?以一个分布式的文件系统为例,预先存入100GB的数据还是存入100TB的数据、存入的文件是大小基本一致差别不大还是各不相同甚至差异很大(例如,从几十字节至几十兆字节不等),这些因素对于分布式系统的性能影响是有很大差异的。另外,如果需要预先存入100TB的数据,若按每秒写入100MB数据来计算,写入100TB数据需要100×1024×1024/100=1048576秒=291.27小时=12天。我们是否能这么长时间的数据准备工作?为了解决这样的问题,我们需要对系统架构设计进行深入分析,设计好测试场景,并提前进行测试用例的设计,以尽早开始准备测试数据。

      性能或压力测试工具。通常来说,分布式系统的测试需要开发一些测试工具来满足性能测试的需求。如果可以的话,这样的测试工具最好由测试工程师自己来实现,因为测试工程师更清楚自己的测试需求。当需要自己开发测试工具的时候,有两个关键问题需要重点关注:第一,一些关键数据的收集方式与计算将成为性能测试工具的关键,例如,TPS(每秒请求数)、Throughput(吞吐量)计算的准确性;第二,要性能测试工具的性能,如果工具本身的性能不好,将无法给予分布式系统足够强大的压力来进行测试。另外,当考虑到多并发(例如有10万客户端同时并发连接)时,如果性能测试工具在一台测试机器上只能运行50个或者更少的话,那么需要的测试机器数量也将会很庞大(例如2000台测试机),这个成本或许是许多公司不能承受的。因此,性能测试工具本身的性能必须要足够好才能满足需求、降低测试成本。

      分布式系统自动化测试

      自动化测试是测试行业发展的必然趋势,对于分布式系统测试而言也不例外。在实施分布式系统自动化测试的过程中,我们可能会碰到下面两个难点问题。

      涉及平台多且硬件杂,测试流程控制困难。在实施自动化测试的过程中,测试脚本需要控制的操作系统和应用程序很多,而且存在跨平台的特性,同时还有可能需要控制一些网络设备。因此,选择一个优秀的自动化测试框架成为了非常重要的工作之一。以我们的实践经验来看,STAF是一个不错的选择,它的平台(Windows及Linux各版本)支持及开发语言的支持都很全面。

      测试结果验证复杂。对于分布式系统的自动化测试来说,我们需要通过测试脚本来收集各种测试结果数据以验证测试结果的正确性。在实施自动化测试的过程中,我们可以将测试结果数据收集部分模块化,通过各子模块来检测各项数据是否正确。例如,我们会设计一个日志分析模块,主要负责从服务器应用程序的日志中收集相应数据进行对比验证(本文前面提到的在打桩日志中增加关键字部分就显得格外重要)。

      随着互联网的发展,大型分布式系统也越来越多、越来越复杂、越来越重要。如何有效地大型分布式系统7×24小时全天候持续稳定地运行也就成为了一个重要课题。

      

      最后,如果你想了解分布式系统编程方面的内容,请认真阅读以下文字。

   

      【分布式系统编程,你到哪一级了?】

      介绍

      当分布式系统编程成为你生活中的一部分时,你需要经历一段学习曲线。这篇文章描述了一下我当前在这个领域大致属于哪个层次,并希望能为你指出足够多的错误,从别人的错误中学习,从而使你能以最优的径通向成功。先声明一下,我在1995年时达到第1级,我现在处于第3级。你自己属于哪一级呢?

      第0级:完全一无所知

      每个程序员都从这一级开始。我不会在此浪费太多口舌,因为这实在没什么太多可说的。相反,我会引用一些我曾经经历过的对话,为从未接触过分布式系统的开发者们提供一些。

      对话1:

      NN:“在分布式系统中,复制是个很容易的操作,你只需要让所有的结点同时存储你要复制的东东就行了”。

      另一段对话(从我记忆深处挖出来的):

      NN: “为了我们的第一人称射击游戏,我们得写一个自己的网络处理引擎。”

      我:“为什么?”

      NN: “虽然已经有一些优秀的商业引擎了,但获取license的费用非常高昂,我们不想为此买单。”

      我:“你之前对于分布式系统有什么经验吗?”

      NN:“是的,我之前写过一个套接字服务器。”

      我:“你觉得你要花多久能完成这个网络引擎?”

      NN:“我想2周吧。保险起见,我计划用4周时间。”

      好吧,有时候还是保持沉默比较好。

      第1级:RPC

      RMI是一种非常强大的用来构建大型系统的技术。事实上,这个技术用Java来描述的话,结合一些工作的例子可以在短短几页纸内描述清楚。RMI技术非常令人振奋,而且它很容易使用。你可以调用你所能绑定到的任何服务器资源,而且你可以构建出分布式的网络对象。过去人们常常为构建复杂的软件系统犯难,现在RMI打开了这道大门。——Peter van der Linden, Just Java(第4版, Sun Microsystems)

      我先声明,我并不是说这本书很烂。我清楚的记得这本书读起来很有趣(尤其是章节之间插入的轶闻),我曾习Java的时候就是用的这本书(太久以前了,简直不像在一个时空里似的)。一般情况下,我觉得作者说的挺好。他对RMI的态度就是典型的分布式系统设计的第1级水平。处于这个等级的人对统一的对象有共同的看法。事实上,Waldo在他们著名的论文“a note on distributed computing”(1994)上曾深入描述过,这里我做下总结:

      我所的写分布式应用的策略可分为3个阶段。第1阶段,写这个应用时不用担心对象存储的,以及它们之间的通讯如何实现。第2阶段,通过具体化对象的以及通讯方法来调整程序性能。第3阶段,真枪实弹的测试(网络隔离、机器宕机等各种情况)。这里的思想就是,不管一个调用是本地的还是远程的,对程序的正确性都不会产生任何影响。

      同样还是这篇论文,随后进一步挖掘了这个主题并展示了其中的问题。这个观点是错误的,而且已经错了快20年。不管如何,如果说Java RMI达成了一个目标,那就是:就算你从等式中拿掉传输协议、命名、绑定以及序列化,它还是不成立。能记得起CORBA的老程序员们同样也会记得它也是不好使的,但他们有一个借口:CORBA还在同各种底层的问题缠斗中。Java RMI将所有这些都抛开了,但使剩下的问题变得更为突出。其中有两点,第一点纯粹就是个麻烦:

      网络不是透明的

      让我们看看这段简单的Java RMI代码示例(同样取自Just Java一书)

      public intece WeatherIntf extends java.rmi.Remote { public String getWeather() throws java.rmi.RemoteException;}

      想要使用天气服务的客户端需要这样做:

      try { Remote robj = Naming.lookup(“//localhost/WeatherServer”); WeatherIntf weatherserver = (WeatherInf)robj; String forecast = weatherserver.getWeather(); System.out.println(“The weather will be “ forecast);}catch(Exception e) { System.out.println(e.getMessage());

      客户端代码需要将RemoteExceptions考虑在内。如果你想看看你究竟会遇到什么样的异常错误,可以看看那20多个子类的定义。这样你的代码就会变得丑陋,好吧,这个我们就忍了。

      局部性错误

      RMI的真正问题在于这些调用可能会出现局部性失败的情况。比如,调用可能会在对其他层的请求操作执行前失败,又或者请求成功了,但之后的返回值又不正确。引起这类局部性失败的原因非常多。其实,这些故障模式正是分布式系统特性的明确定义:

      “分布式系统就是某一台你根本意识不到其存在的计算机,它的故障会造成你的计算机无法正常使用。”—— Leslie Lamport

      如果这个方法只是去检索天气预报,出现问题时你可以简单的进行重试,但如果你想递增一个计数器,重试可能会导致产生0到2次的更新,结果就不确定了。这个解决方案应该来自幂等操作,但构建这样的操作并不总是可行的。此外,因为你决定改变方法调用的语义,那你基本上就承认了RMI与本地调用是不同的。而这也就承认了RMI实际上是个悖论。

      不论什么情况下,这种范式都是失败的。因为网络的透明度和分布式系统的架构抽象从来就是无法实现的。这也表明了某些软件所采用的方法比其他软件为此所受到的影响更多。Scrum的一些变种方法中倾向于做原型化。原型更集中于“好的方面”(happy path),而好的方面通常都不是问题所在之处。这基本上意味着你将永远停留在第1级的水平。(不好意思,我知道这是个小小的打击)

      那些脱离了第一级水平的人懂得对于需要解决的这个问题,我们要有足够的尊重。他们摒弃了网络透明化的思想,从战略性的角度来处理局部性失败的问题。

      第2级:分布式算法异步消息传递语言级支持

      OK,你已习了分布式计算中的悖论是什么。你决定吞下这颗子弹,然后对消息传递机制建模,以此显式地控制出现失败的情况。你将应用分为两个层次,底层负责网络和消息传递,而上层处理消息的到达,以及需要处理的各种请求。

      这个上层实现了一种分布式状态机,如果你去问设计者这个状态机是用来做什么的,他们可能会这样回答你:这是建立在TCP之上的一个Multi-Paxos算法实现。

      明智的开发,这里用到的策略可以归结为:程序员首先在本地主要采用线程来模拟不同的进程来开发这个应用。每个线程运行分布式状态机的一个部分,基本上就是负责运行一段消息处理的循环。一旦这个应用是本地完整的且运行正确,就可以在远端的计算机上用真正的进程来取代线程。到这个阶段,除去网络中可能出现的问题外,这个分布式应用已经可以正常工作了。到容错阶段时,可以通过配置每个分布式实体来正确反映故障的方式来达成,这种方式很直接。(我引述自“A Fault Tolerant Abstraction for Transparent Distributed Programming”)

      因为分布式状态机的存在,局部性故障可以通过设计来解决。对于线程,其实也有很多种选择,但协程(coroutines)更适合(在各种不同的编程语言中,协程也被称为纤程fiber,轻量级线程,微线程或者就叫线程),因为协程允许我们对并发行为有更细粒度的控制。

      结合“C代码并不会使网络变得更快”的论点,你可以转移到在语言级支持这种细粒度并发控制的编程语言中去。流行的选择如下(排名不分先后)注意,这些编程语言往往都是函数式的:

      1.Mozart

      2.Erlang

      3. OCaml

      4. Haskell

      5. Stackless

      6.Clojure

      举个例子,下面让我们看看在Erlang中这种并发控制的代码看起来是怎样的(取自Erlang concurrent programming)

      -module(tut15)-export([start/0, ping/2, pong/0]).ping(0, Pong_PID) - Pong_PID ! finished, io:format(“ping finished~n”, );ping(N, Pong_PID)- Pong_PID ! {ping, self()}, receive pong - io:format(“Ping received pong~n”, ) end, ping(N – 1, Pong_PID).pong() - receivefinished - io:format(“Pong finished~n”, );{ping, Ping_PID} - io:format(“Pong received ping~n”, ), Ping_PID ! pong, pong() end.start() - Pong_PID = spawn(tut15, pong, ), spawn(tut15, ping, [3, Pong_PID]).

      这看起来绝对是对旧有的RPC机制的一个重大提升。现在你可以推想一下,如果有消息没有到达时会发生什么事情了。Erlang还有附加的超时消息以及一个语言内建的“超时”组件,可以使你以一种优雅的方式来处理超时。

      现在,你选择了你要采用的策略,选择了恰当的分布式算法以及合适的编程语言,然后就可以开干了。你很自信能驾驭分布式编程这头野兽了,因为你再也不是第一级的水平了。

      哎呀,可惜的是这一上并非风平浪静。过了一段时间,当第一个版本发布后,你将陷入泥潭之中。人们会告诉你,你的分布式应用有些问题。问题报告中的主题全都是和变化有关的。开始时会出现“有时”或者“一次”这样的表示频率的词,之后的描述变成了:系统处于不期望的状态,卡住不动了。如果够幸运,你有足够的log信息,可以开始着手检查这些日志。稍后,你发现是一系列不幸的事件序列造成了报告中所描述的情况。确实,这是个新的问题。你从来没有考虑过这些,而且在你做大量的测试和模拟时问题从未出现过。所以,你修改代码以将这种情况也纳入考虑范围。

      因为你试着要超前考虑,你决定构建一个“猴子”组件,它以伪随机的方式让你的分布式系统做些愚蠢的事情。“猴子”在里使劲扑腾着,很快你会发现在很多场景下都会导致出现不期望的情况,比如系统卡住了,或者甚至更糟糕的情况:系统出现不一致的状态,而这在分布式系统中是永远也不应该发生的事情。

      构建一个“猴子”是很棒的主意,而且它确实能减少遇到那些你从未在这个领域内碰到过的怪事的几率。因为你相信,修改一个bug必须和发现这个bug的测试用例联系起来,现在需要回归测试这个用例,以证明bug的消除。你现在只需要再构建一次这个测试用例就可以了。可是现在的问题在于,如果说并非不可能的话,要重现这个错误的场景起码是很困难的。你向,得到的是:当心存疑虑时,就使用法吧。因此,你构建一个测试用例,然后让它跑上无数次,以此来弥补这极小的失败概率。这会使你解决bug的过程变得缓慢,而且你的测试套件会变得笨重。通过对你的测试集做分而治之的处理,你不得不再次做一些补偿。无论如何,经过在时间和精力上的大量投入之后,你终于设法得到了一个较为稳定的系统。

      你在第2级已经到顶了,如果没有新的,你将永远卡在这一级。

      第3级:分布式算法异步消息传递纯函数式

      我们需要花点时间才能意识到:长时间运行“猴子”以此发现系统中的缺陷然后再结合法来重现它们,这种做法并不可取。使用法重现只会显示出你的。你需要的关键性的之一是,如果你可以只将等式中的不确定性拿掉的话,你就可以完美的对每一种场景做重现了。第2级分布式编程的一个重大的缺点是:你的并发模型往往会成为你代码库中的病毒。你希望有细粒度的并发控制,好吧,你得到了,代码里到处都是。因此是并发导致了不确定性,而不确定性造成了麻烦。因此必须得把并发给踢出去。可是你又不能抛弃并发,你需要它。那么,你一定要把并发和你的分布式状态机结合在一起。换句话说,你的分布式状态机必须成为纯函数式的。没有IO操作,没有并发,什么都没有。你的状态机特征看起来应该是这样的:

      module type SM = sigtype statetype actiontype msgval step: msg - state - action stateend

      你传入一个消息和一个状态,你得到一个操作和一个结果状态。操作基本上就是任何试着改变外部世界的东西,需要一定的时间来完成,尝试的过程中可能会失败。典型的操作有:

      发送一个消息安排一次超时将数据存储在持久性的存储介质内…

      这里要意识到的重要部分是:你只能通过一个新的消息来得到新的状态,再无其他。在这种严格的下所得到的好处是很多的。完美的控制,完美的重现能力以及完美的可追踪性。为此而得到的开销也同样存在,你将使所有的操作都变得具体化。而这些基本上就是为了减少程序复杂性而附加的一层间接。你还需要将每一个你关心的外部世界变化都建模为一个消息。

      相比第2级的分布式编程,另一个改变在于控制流。在第2级中,客户端会尝试强制更新并动态设置状态。而在这里,分布式状态机假定有完全的控制力,并且只有当它准备就绪,可以做些有用的事情时才会考虑客户端的请求。因此这些必须分离开来。

      如果你把这些道理解释给一个2级的分布式系统架构师听,他可能或多或少的会把这个当成一种替代方案。然而,你需要经历足够多的痛苦之后才会意识到这是唯一可行的选择,我们姑且把这些痛苦称为经验吧。

      第4级对分布式系统领域的深刻理解:快乐,好心态,好好睡一觉

      老实说,我现在只是第3级水平,我也不知道在这一级里有什么新鲜玩意。我,函数式编程和异步消息传递是分布式系统谜题的一部分,但这些还不够。

      请允许我重申我所反对的东西。首先,我希望我的分布式算法实现能够涵盖到所有的可能情况。这对我而言是个大问题,我已经在系统部署的问题上掉了很多睡眠时间。大部分问题都是PEBKAC类的(Problem Exists Between Keyboard And Chair意指用户引起的错误),但有一些确是真正的问题,这给我造成了一些感。知道自己实现的健壮性程度是很好的。我应该试试证明一下那些吗?我应该做更详尽的测试吗?我不知道。

      附带提一下,github上有一个称为baardskeerder的仅用于插入操作的B-树库,我们知道可以通过详尽的生成插入/删除排列并断言它们的正确性之后,我们就可以涵盖到所有的情况。但这里,并没有那么简单,而且我对于要对整个代码库做Coqify处理(Coq是一个正式的证明管理系统,它在一种半交互式的下提供了一个正式的语言用来编写数学定义、可执行的算法和,用计算机来做检查证明,这里作者生造出了Coqify这个词)还有些犹豫。

      第二,为了保持清晰和简单,我决定不去碰其它一些正交性的需求。比如,服务发现、认证、授权、私密性以及性能。

      说到性能,我们也许是幸运的,至少异步消息传递似乎与性能方面并不产生矛盾。安全性则完全是一个(作者真的爆粗口了…),因为它几乎切断了所有你所做的事情。有些人把安全性看成是一种调味酱汁,你只要把它倒在你的应用程序上就可以安全了。哎,在这方面我从未取得过成功,而且现在我也认为这个问题需要在设计的最初阶段从宏观的角度策略性的去分析解决。

      结语

      开发出健壮的分布式系统是个颇为棘手的问题,实际上根本没有完美的解决方案,或者说至少没有让我觉得完全满意的解决方案。我敢肯定分布式系统的重要性将随着处理器和其它一切事物之间的延迟增加而显著提高。这一结果使得这种类型的应用程序开发变得愈发繁荣。

      至于分布式编程的第4级,也许我该去问问Peter Van Roy。这么些年来,我阅读了很多他写的论文,这些论文对于我自己的一些错误认识给了很多。关于这些的缺点嘛,你常常在大部分时间里看到别人在重复自己的错误,但我无法他们应该换种方式去做。

      也许,这是因为我无法提供他们想要的那种灵丹妙药。他们就想要RPC,而且他们希望这样能搞定问题。这是固执的…就像教一样。

  以上就是分布式系统原理、应用、编程等方面的全部内容,如果你觉得意犹未尽,请阅读下面几篇内容。

  GFS概念解读:可扩展的分布式文件系统

      HDFS概念解读:Hadoop分布式文件系统

      解析:分布式文件系统存储的工作原理

推荐: