分布式系统基本原理
分布式系统被设计成可以存储和管理大数据量的信息的系统,并为这些数据提供对外的访问功能(通过网络)。现在已经有许多的分布式系统用各种不同的方法解决了这个问题。
NFS, the Network File System, 是目前最普遍的分布式系统。它也是还在使用的最老的分布式系统之一。它的设计是非常易懂的,但它也有许多的局限性。NFS 为存储在一台机器上的一个逻辑卷提供远程访问。一个NFS能够让它的本地文件系统的一部分对其他的客户端可见。然后,客户端 会把这个远程系统 加进 它们自己的 Linux 文件系统,然后就像 远程系统在本地硬盘上一样 去使用它。
这个模型的一个主要的优点就是它的透明性。客户端压根儿不用知道它们是否在使用远程系统。标准库中的方法,例如 open(),close(),fread(),等等,会帮助我们使用在NFS上的文件。
但是作为一个分布式系统,它的功能并不是很强大。NFS 中的文件始终都只是存储在一台机器上。这就意味着,存储的容量不可能超过那台机器的容量,并且 NFS 也不提供可靠性上的保证(比如 数据备份)。最后,因为 所有的数据都被存储在一台机器上,那所有的客户端都得跑到这台机器上来取数据。当很多客户端同时跑过来的时候,服务器可能会超负荷。而且,客户端在每次处 理数据之前,都必须跑到服务器上去取数据。
HDFS的设计能够解决一些其他的分布式系统,例如 NFS,所无能为力的问题。尤其是在以下一些方面:
HDFS的可扩展性,高性能也决定了它对应用程序的不同于其他分布式系统的苛刻要求。为了达到设计者的目的,设计者做了一些额外的限制设计和折中方案。主要有:
HDFS的设计是基于google的分布式系统GFS的,这里是google发表的相关论文 。
HDFS 是一个块结构的文件系统;每个文件都被分割成固定大小的文件块。这些块根据数据存储策略被分别存储在一台或者多台机器上。集群中的机器,我们 叫,DataNode。一个文件能够被分割成几个文件块,这些文件块并不一定会被存储在同一台机器上,哪个块存在哪个机器上是随机的。由此,想要访问一个 文件,或许得要几台机器一起合作才行。但是却因此而获得了存储大文件的能力,显而易见,文件能够要求比单个硬盘更大的空间来存储它。
如果一个文件的使用,需要多台机器的配合,那么一台机器的故障将会导致该文件的不可用。HDFS通过为文件的每一个块都做备份的方式来解决这个问题(通常,有3个备份)。
图 2.1: DataNodes 存储着文件的文件块 ,备份的数量是2 。NameNode 结点负责将文件名映射到文件块的ID上。
多数块结构的文件系统使用4k或者8k 数量级别的块大小。相比之下,HDFS的块大小默认下是64MB---一个大很多的数量级别。这个设计减少了HDFS持有的文件块的数量(文件块的容量大 的时候,块的数量就会相应的减少了)。这样做更有利于流式读取方式。显而易见,HDFS 非常喜欢 特大的文件,并且更喜欢流式地读取它们。不像NTFS 或EXT这样的文件系统,它们通常保存很多的小文件,HDFS更希望存储适中数量的特大文件,几百M的、几百G的。毕竟,一个100M的文件也才不过两个 文件块而已。在我们平常的计算机中,文件通常是被随机访问的,应用程序可能会读取一个文件的不同的几个部分,这些部分通常不是连续的存储在硬盘上的。相比 之下,HDFS期望程序一次读完整个文件。这种做法刚好非常适合MapReduce编程的风格。也就是说,像平常使用一般分布式系统那样去使用HDFS, 不是一个明智的选择。
HDFS将文件分成块,并存储在几台机器上,这些文件不可能被当成正常文件系统的一部分了。在一台跑Hadoop的机器上使用ls命令,返回的结果是 linux系统的内容,而并不会包括任何存储在HDFS系统里面的文件。HDFS是一个建立在本地文件系统之上的应用。HDFS的文件(更确切的说,组成 文件的那些文件块) 被存储在 DataNode 结点的一个特定的目录下,但这些文件块只有id。所以,你根本就没有办法使用linux 文件系统的一些工具(ls,cp,mv等等)去操作这些文件。不用操心,HDFS 自带了文件管理功能,操作起来跟(ls,cp,mv)等命令一样地简单。
数据的可靠性是相当重要的。HDFS的数据被设计成只允许一次写入和多次读取操作,当大量的客户端同时需要对文件目录进行修改的时候,同步工作就显得异常 重要了。所以,对文件目录的维护由单独的一台机器来完成,这台机器我们称之为NameNode。NameNode将会存储 文件系统的文件目录和文件名称。因为,每个文件需要记录的东西是很少的(例如,文件名、权限、文件块的位置等),所以,所有的数据都可以被存储在一台机器 上,并提供快速的访问功能。
假设,客户端要访问文件A。客户端从NameNode中取得组成文件A的文件块的位置列表。这个列表知道文件块被存储在哪台机器上。然后客户端 直接 从DataNode上读取文件数据。NameNode是不参与文件的传输的,我们要保证NameNode的消耗尽可能的小。
当然,我们还有预防NameNode机器崩溃的情况。我们使用冗余来保证文件系统的数据不会丢失,即使是在NameNode忽然崩溃的情况下。显 然,NameNode的崩溃要比集群里面的任何一台DataNode的崩溃要严重得多了。当一台DataNode故障的时候,整个集群还可以继续运行,但 当NameNode故障的时候,集群就无法运行了,这时候,我们得手动的采取措施修复故障。当然,NameNode的工作量是相当的小的,它发生故障的概 率要比其他机器发生故障的概率小得多了。
关于HDFS的设计与实现,下面的这篇文章阐述的更加详细。document