| 2.2 分布式文件系统的结构 |

2.2.1 分布式文件系统的运行环境与特性保证

(1)分布式文件系统的构建基础

下面展开对分布式文件系统的实现的讨论。首先需要讨论的一个问题是文件系统的构建基础以及能够对外提供的服务。传统的单机文件系统的构建基础是一块单机的磁盘以及在这个磁盘之上的驱动程序,文件系统是作为一个操作系统的内核模块存在的。对于分布式文件系统来说,不是采用前述的SAN以及在SAN之上建立SANFS的方案,而是采用大规模集群的方案,每一个集群中的节点都是独立的服务器,可以单独运行操作系统。这里会涉及集群中的一些概念,这些概念对于后面的讨论以及阅读一些文献会比较重要,下面对其进行简单介绍。

节点(Node):一般是一台服务器,有时也会被直接称为服务器或计算机。节点的含义是具有完整处理能力的计算机,其具有完整的处理器、内存、网络以及磁盘。在这里之所以被称为是节点,往往是与集群的一些连接关系相关的,在表达为连接图时,图上的点(Vertex)就被称为处理节点,简称节点。在分布式文件系统中,每一个节点都是完整的计算机,包括硬件、操作系统以及其上运行的应用程序。

网络(Network):网络用于将节点连接在一起,网络对于建立分布式文件系统非常重要。关于网络部分的内容主要包括网络连接的技术以及网络连接的拓扑。网络连接技术一直在发展,对于分布式文件系统来说,重要的是数据中心网络的发展。现有数据中心网络连接技术主要包括以太网以及InfiniBand网络。前者是所有网络服务器的标准配置,后者由于其极高的网络带宽以及极低的时延,在数据中心中的应用越来越普遍。网络连接的拓扑往往影响着数据中心的应用程序,包括文件系统的性能。常用的网络连接方式为胖树的连接方式,在中心的位置使用大规模的网络互连设备,进而在进行多机数据传输时仍然可以保证性能。

机柜(Rack):机柜是一组节点的集合,简单来说,就是一组服务器被装到冰箱大小的机柜中。机柜在整个系统的硬件设计中也具有比较重要的地位,因为其是组成大型数据中心的基本单位,也是大型数据中心网络布线的基本节点。机柜的一般高度为2 m左右,可以容纳20多个2U的服务器。U是服务器的标准高度单位,为 4.445 cm,机柜高度通常为42U。机柜的概念对于软件来说通常不是那么重要,因为从软件的角度来看,只需要节点之间互相连通即可。但是,随着系统规模和数据规模的扩大,现有的分布式文件系统已经开始考虑机柜之间的拓扑关系,这不仅会涉及系统的性能,还会涉及系统的可靠性。

集群(Cluster):集群是一组服务器的统称,一组服务器的规模可大可小。集群的描述虽然非常宽泛,但是在实际中,还含有位置较近、集群内的节点之间的可以高速通信的限制条件。一般来说,在设计分布式软件时都会针对一个集群进行设计。集群的大致规模在数千台服务器,例如雅虎公司可以维护一个分布式文件系统的集群,其规模为5 000台服务器。如果需要创建更大规模的系统,就需要考虑使用多个逻辑集群的方式,而不是使用扁平的单一集群。这种层次化的方法是设计超大规模系统的基本思考方法,可以极大降低设计的复杂度。

数据中心(Data Center):一个数据中心通常表示一个在具体地理位置上建设的信息技术基础设施,通常会包含多个集群。这里的多个集群可能是为了完成不同的任务,或者只是因为相同的任务服务于不同的用户进行区分。在系统的构建方面,因为已经有了集群这个扁平的基础接口,绝大多数的系统不会再去考虑数据中心这个逻辑单元。但是,随着数据规模的扩大,越来越多的系统建设者开始考虑在一个数据中心内部如何进行系统构建的问题。

地理分布(Geographically Distributed):随着大数据和云计算的发展,地理分布这个概念逐渐进入系统设计者的考虑范围。一个系统考虑地理分布的主要目的是容灾。近几年信息系统失效造成的损失越来越大,也越来越受到系统建设者的重视,在进行系统设计时不仅需要考虑数据中心的规模,还需要考虑跨数据中心的规模。跨数据中心的规模在处理能力上不见得能够有多大的提高(考虑到网络时延的问题),但是跨数据中心的设计在可靠性方面将会大大提高。出现自然灾害(如地震、洪水等)或整个数据中心被损坏时,跨数据中心的系统仍然可以使用。这样一个能够容忍灾害发生的稳固的基础设施是大数据、云计算应用的运行基础,能够保证系统的极端的可靠性,也是下一代更大规模的系统建设的考虑因素之一。

以上对涉及分布式文件系统的设计与实现的基础环境因素进行了讨论,这些因素都会影响系统的设计。对于本章所需要实现的分布式文件系统来说,不需要考虑涉及多个集群的分布式文件系统,而是将注意力放在一个逻辑上统一的集群上,这也是构建更大规模的存储系统的基础。

这样,在构建基于集群方式的分布式文件系统时,对底层的物理资源有如下一些假设。

• 在集群的规模上,集群包含了数千个节点。这样的假设一方面符合构建集群规模的现实,另一方面是为了保证一个单一名字空间的文件系统可以在这个集群系统中正常运行。

• 从上面的讨论可以看出,由于每一个节点都是完整的节点,在实现分布式文件系统时就没有必要像SANFS那样直接访问物理磁盘,将访问和管理物理磁盘的任务交给本地的文件系统即可。所设计的分布式文件系统可以是应用程序,这会大大降低分布式文件系统的实现负担。

• 由于所运行的分布式文件系统的基础结构是大规模的集群,集群中的各种部件数目是十分庞大的,包括硬盘的数目、网络的数目、交换机的数目等。集群中的许多部件,特别是硬盘部件是非常容易出现错误的。因此,集群在运行的过程中非常有可能出现这样或那样的错误。如此大规模的集群出错是一个常态,每时每刻都可能出现错误。文件系统就是运行在这样一个时时刻刻都可能出现错误的硬件资源环境上。

(2)分布式文件系统的展现形式

这里的分布式文件系统的展现形式相对来说比较简单,对外提供的接口即文件系统的接口。文件系统的接口可以由标准的文件系统(如NFS以及Samba)提供,也可以是特殊的编程接口。由于分布式文件系统的特点,如果使用标准文件系统接口,则非常有可能造成性能的下降(考虑前面所说的带内和带外的数据访问方式),而使用特定的文件系统接口则可以获得更好的性能。但是,因为分布式文件系统也是文件系统,所以对外的展现形式必须有两个基本的模块,一个是关于目录树部分的展现形式,文件系统的各个内容(如目录以及文件)都通过目录树的组织方式展现给用户或应用程序;另一个是关于数据部分的展现形式,无论通过什么方式提供服务,必须能够支持对于文件数据的读写操作,否则不能称之为文件系统。从展现形式来说,分布式文件系统和单机的文件系统是类似的。

关于文件系统的展现方面,又会涉及名字空间的问题。这里就明显体现出了全局的名字空间和局部的名字空间的区别。对于分布式文件系统来说,其对外需要提供一个名字空间,而这个名字空间往往与本地的名字空间不同。因此,可以说分布式文件系统的名字空间与本地的名字空间在原则上是相互独立的。然而,在实践中,大部分的NFS服务器和Samba服务器直接使用本地的名字空间作为全局的名字空间。这只是在小规模系统中使用的简化的手段,随着系统规模的扩大,单个节点的名字空间不能支持大量的网络访问,这就需要一个独立的名字空间,与本地名字空间进行区别和隔离。

(3)文件系统的性能

从前面的讨论中已经可以看到,整个分布式文件系统的基础在于大规模的集群系统,节点的数目可以达到数千个。那么除了完成文件系统的基本功能,这样一个系统还需要具有什么样的特性呢?这涉及分布式系统的3个基本的特性,这3个特性在分布式文件系统中都有特定的含义。

① 可扩展性

第一个特性是关于性能方面的,性能自然是越高越好了。分布式系统的关于性能的一个特别的特性是可扩展性。可扩展性的含义是一个系统可以充分利用所有的节点资源,系统的性能可以随着节点数目的增加而提升。这里的性能提升最好是线性的、成比例的提升。但是,由于系统各个模块之间的耦合关系,往往不能达到线性。在建立系统时,一定要仔细分析构建系统的过程,消除其中的性能影响,保持系统的可扩展性。

对于文件系统来说,性能的可扩展性包括两个部分,一部分是单机文件系统的性能,另一部分是多个机器叠加之后形成的分布式文件系统的性能。对于分布式文件系统来说,单机文件系统的性能也是非常重要的,因为现有的分布式文件系统一般都是通过单机文件系统提供对磁盘的数据读写的。对于单机文件系统的性能提升来说,在现阶段往往需要通过设计新的文件系统来使用新型的硬件,例如通过新型的设计来充分利用SSD的性能。对于分布式文件系统的性能来说,重要的一点是要保证系统的负载均衡以及可扩展性。负载均衡的含义是在进行数据服务时,应用产生的负载会均匀分布在所有的服务器上,而不是仅仅分布在一小部分服务器上。对于任意一个分布式系统来说,这是最为基本的要求,即所有的服务器都应该发挥功效,而不是只有一部分发挥功效。对于分布式文件系统来说,负载具有两个方面的含义,一个是所有的服务器节点存储的数据容量相当,另一个是所有的服务器在提供服务时性能负载(不仅是保存的数据)相似。存储数据容量相当的含义是所有磁盘保存的数据量类似,数据存储量基本同步增加。性能负载相似在文件系统的设计过程中不容易被考虑到,但是在实际系统中非常容易出现一些热点的数据模块,造成对应的服务器节点负载过高,导致性能下降。从这一点来看,考虑系统的性能负载均衡是十分必要的,不能将过多的热点数据集中于少数的服务器节点之上。

② 可靠性

第二个特性是可靠性,其也是分布式系统需要达到的固有的特性。在一个具有数千个节点的系统中,因为少数节点的错误造成整个系统不可用、整个文件系统无法提供服务,是不可接受的。但是,底层的物理资源又非常容易出错,因此在设计系统软件时必须要考虑到这一点,使得所设计的分布式文件系统可以避免底层的物理资源的出错问题。同单机的文件系统一样,分布式文件系统保存的是应用程序以及用户所需要的数据,这部分工作实际上是任何一个分布式系统的基础。因此,在大多数情况下,上层的应用程序需要依赖分布式文件系统的可靠性来保证自身的可靠性。分布式文件系统的可靠性是建立可靠的分布式系统的基石。

与可靠性相关联的还有其他的一些属性,包括持久性、可恢复性、可用性等。仅仅谈论这些属性的概念是没有意义的,重要的是理解其背后的实质含义。可靠性是最为宽泛的概念,通常指的是数据保存在系统中不会丢失。

可靠性往往包含了持久性的概念。持久性的概念是针对内存以及硬盘的相对特性提出的。数据被保存在内存中,随着系统掉电情况的发生,数据会丢失,这种特性就是不持久的。相反,存储在磁盘上的数据可以长久保存,不会因为系统掉电而丢失,因此这种特性被称为持久性。可以看到,持久性的概念非常清晰,其也是保证数据不丢失的基本手段。因此,在保证可靠性的场合必须要依赖于持久性,这样即使发生了系统掉电的情况,至少还可以保证数据在将来可以被取回。

与持久性相关联的概念就是可恢复性。需要指出的一点是,数据具有持久性并不能保证数据的可恢复性。数据虽然被保存在磁盘上,但是在进行读取时,很有可能读取不到。这往往是因为文件系统未考虑出错的情况,如果系统突然掉电,就会破坏磁盘上的数据。这种情况在早期的文件系统中经常发生。现在的设计者已经将可恢复性纳入考虑范围,文件系统的任何一个操作点发生错误都不能破坏整个文件系统的完整性。在出现掉电错误的时候,可能最近的几次操作会发生丢失,但是至少文件系统本身不会被破坏,可以启动使用。可恢复性对于很多系统也是非常重要的概念,如数据库等。一般来说,可以使用日志的方法来保证任何一个应用系统和平台系统的可恢复性。

可用性也是另外一个相关的概念。可用性不仅要求数据不丢失,还要求在出现错误的情况下服务不停止。这对系统的要求是非常高的。针对不同规模的错误情况,可用性有不同的级别。对于小规模的系统来说,需要在少数节点出现错误时提供可用性,系统的表现就跟没有任何节点出错的行为一样。这样的可用性级别是非常低的,因为很有可能由于一个机架的掉电(由于管理员错误断电)造成整个系统不能使用。在一个数据中心范围内的可用性就需要考虑这样的一个可能性,使得一个或几个机架上的上百台服务器出现错误时,整个系统还可以提供正常服务。对这种并发错误同时进行处理是可能的,因为在这样的环境下已经有数千台服务器,10%左右的服务器出错不应当影响整个系统的可用性。但是,在这样大规模的硬件环境中正常运行一个系统已经非常困难了,再进一步保证可用性的难度可想而知。在这个层级之上有更加严厉的可用性要求,即在整个数据中心出现错误、整个数据中心不可用的情况下保证系统的可用性。这就要求所建立的系统必须要跨数据中心,这样才能够保证一部分数据中心出现错误时整个系统的可用性。虽然这样的可用性非常极端,但是在实际环境中还是有可能出现的,并且出现错误时会造成重大的损失,因此这种级别的可用性也开始进入系统设计者的视野当中,在设计系统时开始考虑它。

③ 一致性

一致性的概念涉及系统的正确性,也与可靠性相关,比较不直观。我们通过可靠性引入一致性的概念。为了保证可靠性,在节点出现错误的时候,需保证数据不丢失,一个最为直接通用的方法是通过多副本的方式来保证可靠性。对于分布式文件系统来说,这就意味着需要将一份数据放置在物理位置不同的多个地方。对于这些逻辑上是同一份数据,而物理上是不同的数据副本来说,最为基本的要求就是需要保证这些数据所包含的内容是一样的。这里包含的内容是一样的可以被严格定义为具有一致性,即物理位置不同的数据副本包含的值是一样的。这一点看起来简单,但是实际上做起来是非常困难的。因为这里不仅需要考虑系统正常工作的情况,还需要考虑保存数据副本的机器可能的出错情况,以及网络的出错情况。在这些情况下,有可能无法写入数据,也可能发生数据丢失,不会出现的情况是这些数据之间不一致。但是,可以想见,一部分副本写入成功,一部分副本写入不成功,肯定会出现不一致的情况。因此,如果分布式文件系统采用副本的方式来达到高可靠性,同样要解决这里的一致性问题。

最高要求的一致性是指所有的数据副本都写入成功时,写入操作才算成功,否则会返回一个错误。为了保持这样的一致性,必须让数据以及写入操作能够到达所设定的所有的节点,但是这可能会降低系统的性能。因此,如何优化性能,同时还保证一致性是非常需要仔细考虑的问题。在实际的系统中,往往会因为一致性的问题影响性能,但是有时要求太高的一致性也没有必要,因此需要在一致性和性能之间做出权衡。一致性涉及系统的很多个方面,对于任何一个分布式系统来说都是不可避免的、需要解决的问题。在文件系统中,其典型的表现形式就是维护数据在多个物理位置具有相同的数值,使得其对外表现出的结果一致。

2.2.2 典型的单一名字空间的分布式文件系统

(1)分布式文件系统的设计模式与系统假设

分布式文件系统的设计和实现会涉及很多方面,限于篇幅以及讨论的层次,这里只对其中一些关键的技术点进行研究。在实际构建分布式文件系统时还会涉及真正的运行环境的复杂性,这里无法一一进行讨论。但是,这里研究的是分布式文件系统最为关键和核心的部分,如果没有这些关键和核心的模块,就不能完成分布式文件系统的建设。在实际的工作中,往往需要围绕这些核心的模块去建设其他模块,这样才能够完成整个分布式文件系统的实现工作,保证系统可以正常运行。

在开始设计分布式文件系统之前,先看一下对系统的假设。这里的单一名字空间的分布式文件系统是基于谷歌文件系统构造的[5]。这是一个非常典型的分布式文件系统,在当前的分布式文件系统的实现中,大部分采用了这个架构[6-7]。在这个分布式文件系统中,假设保存的是大量的大型文件,每一个文件的大小可能有数个TB。针对大文件设计分布式文件系统是非常有意义的,因为小文件分多个节点直接存放即可,每一个文件会被存放在一个节点的内部。如果将大量小文件存放在分布式文件系统中会造成名字空间的负担,以及每一次进行文件访问的时候都需要解析元数据,会造成文件读写的速度很慢。

另外,在进行大文件数据读写时,由于网络数据分析(如搜索引擎)的特点,这些文件的读写模式基本上都是写入一次、读取多次。对应的应用情况是从网络上获取数据并将其存放在分布式文件系统中,之后再从分布式文件系统中读取数据并进行分析。写入数据的过程是数据追加的过程,不会有太多随机写入的问题;读取数据的过程也大多是顺序读取的过程,不会有太多随机读取的问题。这就要求在设计文件系统时要优化这样的读写模式。无论是单机的文件系统还是分布式的文件系统,在设计时不太可能优化所有的读写模式,只能针对具体部署的应用的特点进行有针对性的优化。在优化时,不同读写模式的方法和参数不同,往往不能兼顾,实际构造的时候需要进行取舍。

(2)分布式文件系统的总体设计

下面对单一名字空间的分布式文件系统的总体设计进行分析。值得注意的是,这里假设系统是由数千个节点独立节点组成的集群。集群中的每一个节点独立运行完整的操作系统。因为分布式文件系统也是文件系统,所以在设计时也需要考虑文件系统的元数据(即目录树)以及文件系统的读写设计。在这里,更为关键的是对元数据存放位置的设计,因为这直接关系到后面的文件数据的读写。存放文件系统元数据的方式有很多种,在谷歌文件系统的设计中,使用的是最为简单直接的方式,即将所有文件系统元数据保存在一个节点中。当然,这样的设计是会有性能和可靠性的问题的,这两个问题的解决方法将在第2.3节介绍,现在的首要目标是让分布式文件系统运行起来。

因为所有的元数据被保存在一个节点当中,所以进行文件系统功能设计时就非常方便。与一个具体文件相关的所有元数据也可以被同时保存在相同的节点当中,这些元数据会指出对应的文件数据块所在的物理位置。由于网络大数据的特点,这里设计的文件系统保存的是大量的大文件的数据(例如将大量的网页数据合并成一个大的文件保存在文件系统中)。由于单个节点的容量限制,大文件很有可能不能被单独保存在一个节点内。而出于性能的考虑,也不应当把大的文件保存在单个节点之内,因为这会限制对单个文件进行并发读写的能力。因此,分布式文件系统中的大文件都是通过分块的方式存放数据。与谷歌文件系统一样,我们设计的分布式文件系统在面对大文件时,将数据分割为数个64 MB的数据块。这样,一个文件的元数据的构成为:(文件名字,数据块0信息,数据块1信息,数据块2信息…)。其中,每一个数据块的信息即保存的对应节点的信息。由于在保证性能的同时需要保证可靠性,因此一个数据块会被保存在多个不同的物理位置,也就是说这里的数据块的信息是多个节点的信息,即节点0、节点1、节点2。这里假设每一个数据块都被分配到3个不同的物理节点中,由于节点数目为数千个,因此这样的分配是能够达到的。这样,这里的单一名字空间的分布式文件系统的设计就比较清楚了。

图2-5是单一名字空间的分布式文件系统的总体设计。从图2-5可以看到,系统中的数千个节点被分为两个不同的角色,一个角色用于保存元数据信息,可以称之为元数据节点;另一个角色用于保存文件中的数据块,被称为数据块节点。这样,每一次访问文件数据块时,整个文件系统首先根据元数据节点定位对应的数据块节点。之后,这部分元数据会被返回给客户端,客户端依据返回的信息访问相应的文件的数据。无论是对文件系统进行读取操作,还是对文件系统进行写入操作,都可以通过相同的流程完成。由此可以看到,这样的设计实现了分布式文件系统的两个最大的功能,一个是分布式文件系统的名字空间,另一个是分布式文件系统的数据读写。

图2-5 单一名字空间的分布式文件系统总体设计

上述方式是对整个分布式文件系统的初步设计,虽然比较简陋,但是已经可以帮助我们理解分布式文件系统的设计方式。下面将针对这个初步的分布式文件系统展开讨论,指出其在实际运行中可能出现的问题,并且在此基础上逐步修复,以完成对分布式文件系统的改进。需要注意的是,这里的改进是逐步进行的,不要破坏系统已经达到的指标。此外,在系统出现新的问题时应进行进一步的修复。

下面的分析围绕分布式文件系统的性能、可靠性以及一致性方面。对于任意一个分布式系统来说,性能和可靠性都是首先需要考虑的因素。至于一致性,在大部分情况下都是针对分布式文件系统进行讨论的。在完成分布式文件系统的一致性工作之后,其他分布式系统都可以建立在分布式文件系统之上,并且依赖分布式文件系统来完成一致性的工作。因此,这里针对分布式文件系统的一致性的讨论会成为建立分布式系统的基石。