每个磁盘都有默认的数据块大小,这是磁盘进行数据读写的最小单位。构建于单个磁盘上的文件系统通过磁盘块来管理该文件系统中的块,该文件系统块的大小可以是磁盘块的数倍。文件系统一般为几千字节,而磁盘块一般为512字节。
HDFS同样也有块的概念,但是它大得多,默认为64MB。与单一磁盘上的文件系统相似,HDFS的文件也被划分为块大小的多个分块(chunk),作为独立的存储单元。但是HDFS中小于一个块大小的文件不会占据整个块的空间。
HDFS的块比磁盘块大,它的目的是为了最小化寻址开销。如果块设置的足够大,那么从磁盘传输数据的时间可以明显大于定位这个块开始位置所需的时间。这样,传输一个由多个块组成的文件的时间取决于磁盘传输速率。随着新一代磁盘驱动器传输速率的提升,块的大小将会被设置的更大。但是该参数也不会设置的过大,MapReduce中的map任务通常一次处理一个块中的数据,因此如果任务数太少(少于集群中的节点数量),作业的运行速度就会比较慢。
对分布式文件系统中的块进行抽象会带来很多好处,如下:
(1)一个文件的大小可以大于网络中任意一个磁盘的容量。文件的所有块并不需要存储在同一个磁盘上,因此它们可以利用集群上的任意一个磁盘进行存储。事实上,尽管不常见,但是对于整个HDFS集群而言,也可以仅存储一个文件,该文件中的块占满集群中所有的磁盘。
(2)使用块抽象而不是整个文件作为存储单元,大大简化了存储子系统的设计。简化是所有系统的目标,但是这对于故障种类繁多的分布式系统来说尤其重要。将存储子系统控制单元设置为块,可以简化存储管理,由于块的大小是固定的,因此计算单个磁盘能存储多少个块就相对容易。同时也消除了对元数据的顾虑,因为块只是存储数据的一部分,而文件的元数据,比如全县信息,并不需要与块一同存储,这样一来,其他系统就可以单独地管理这些元数据。
而且块非常适合用于数据备份进而提供数据容错能力和可用性。将每个块复制到少数几个独立的机器上(默认为3个),可以确保在发生块、磁盘或者机器故障后数据不丢失。如果发现一个块不可用,系统会从其他地方读取另一个复本,而这个过程对用户是透明的。一个因为损坏或者机器故障而丢失的块可以从其他候选地点复制到另一台可以正常运行的机器上,以保证复本的数量回到正常水平。
我们可以使用HDFS中的fsck指令来显示块信息,比如hadoop fsck / -files -blocks
HDFS集群有两类节点,并且以管理者-工作者模式运行,即一个namenode(管理者)和多个datanode(工作者).而namenode管理文件系统中的命名空间,它维护者文件系统树以及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。namenode也记录着每个文件中各个块所在的数据节点信息,但是它并不永久保存块的位置信息,因为这些信息会在启动时由数据节点创建。
客户端代表用户通过与namenode和datanode交互来访问整个文件系统,客户端提供一个类似于POSIX(可移植操作系统界面)的文件系统接口,因此用户在编程时无需知道namenode和datanode也可以实现其功能。
datanode是文件系统的工作节点,它们根据需要存储并且检索数据块(受客户端或者namenode调度),并且定期向namenode发送它们所存储的块的列表。
没有namenode,文件系统将无法使用。事实上,如果运行namenode服务的机器毁坏,文件系统上所有的文件将会丢失,因为我们不知道如何根据datanode的块来重建文件。
对namenode的容错非常重要,Hadoop为此提供了两种机制:
(1)第一种机制是备份那些组成文件系统元数据持久状态的文件。Hadoop可以通过配置使得namenode在多个文件系统上保存元数据的持久状态。这些写操作是实时同步的,是原子操作。一般的配置是,我们将持久状态写入本地磁盘的同时,写入一个远程挂载的网络文件系统(NFS).
(2)另一种可行的方法是运行一个辅助namenode,但是它不能被用作namenode。这个辅助namenode的重要作用是定期通过编辑日志合并并且命名空间镜像,以防止编辑日志过大。这个辅助namenode一般在另一台单独的物理计算机上运行,因为它需要占用大量的CPU时间与namenode相同容量的内存来执行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode发生故障时启用。但是辅助namenode保存的状态总是滞后于主节点,所以在主节点全部失效后,难免会丢失部分数据。这种情况下,一般把存储在NFS上的namenode元数据复制到辅助namenode并作为新的主namenode运行。