1、HDFS的设计:
当数据集大小超过一台独立的物理计算机存储能力时,就要对它进行分区并存储到若干台单独的计算机上。管理网络中跨多台计算机存储的文件系统成为分布式文件系统,该系统架构于网络之上。
Hadoop有一个称为HDFS的分布式系统。实际上Hadoop是一个综合性的文件系统抽象,也可以集成其他文件系统(如本地文件系统)。
HDFS以流式数据访问模式来存储超大文件(具有几百MB、GB甚至TB、PB大小的文件),运行于商用硬件集群上。
流式数据访问——HDFS构建思路:一次写入、多次读取是最搞笑的访问模式。数据集通常由数据源生成或从数据源复制而来,接着长时间在此数据集上进行各种分析。每次分析都将涉及该数据集的大部分数据甚至全部。
对于要求低时间延迟数据访问的应用不适合在HDFS上运行,HBase是更好的选择。HDFS是为高数据吞吐量应用优化的。
HDFS中的文件写操作总是将数据添加在文件的末尾,不支持具有多个写入者的操作,也不支持咋文件的任意位置进行修改。
2、HDFS概念:
数据块:类似于磁盘中数据块,HDFS同样也有块的概念,默认为64MB(之所以块头这么大,是为了最小化寻址开销)。HDFS上的文件被划分为块大小的多个分块,作为独立的存储单元。与其他文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块空间。
文件的所有块不需要存储在同一个磁盘上,它们可以利用集群中任意一个磁盘进行存储。块非常适用于数据备份进而提供数据容错能力和提高可用性。将每个块复制到少数几个独立的机器上(默认为3个),可确保咋块、磁盘或机器发生故障后数据不会丢失。
namenode和datanode:HDFS集群分为两类节点,以管理者-工作者模式运行,即一个namenode(管理者)和多个datanode(工作者)。namenode管理文件系统的命名空间。维护着文件系统树及整棵树内所有的文件和目录,这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。客户端(client)代表用户通过与namenode和datanode交互来访问整个文件系统。
datanode是文件系统的工作节点。它们根据需要存储并检索数据块(受客户端或namenode调度),并定期向namenode发送它们所存储的块的列表。
联邦HDFS:namenode在内存中保存文件系统中每个文件和每个数据块的引用关系,这对一个用于大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。在2.x发行版本系列中引入联邦HDFS运行系统通过添加namenode实现扩展,其中每个namenode管理文件系统命名空间中的一部分。
namenode是唯一存储元数据与文件到数据块映射的地方,没有namenode,文件系统将无法使用。
3、命令行接口:
文件系统由URI指定,可使用hdfs URI 来配置HDFS为Hadoop默认的文件系统。
4、Hadoop文件系统:
Hadoop有一个抽象的文件系统概念,HDFS只是其中的一个实现。还包括Local、HFTP、HSDTP、WebHDFS、HAR、hfs(云存储)、FTP、S3(原生)、S3(基于块)、RAID、View等文件系统。Hadoop对文件系统提供了许多接口,一般使用URI方案来选取合适的文件系统实例进行交互。Hadoop是用Java写的,通过Java API可调用所有Hadoop文件系统的交互操作。
5、Java接口:
从Hadoop URL读取数据:
从文件系统中读取文件最简单的方法是使用java.net.URL对象打开数据流,从中读取数据。具体格式为:
从FileSystem API读取数据:
Hadoop文件系统中通过Hadoop Path对象(而非java.io.File对象)来代表文件,可将路径视为一个Hadoop文件系统URI,如hdfs://localhost/user/tom/test.txt。
FileSystem是一个通用的文件系统API,所以第一步是检索需要使用的文件系统实例。获取FileSystem实例有以下几个静态工厂方法:
Configuration对象封装了客户端或服务器的配置,通过设置配置文件读取类路径来实现。第一个方法返回的是默认文件系统(在conf/core-site.xml中指定,如果没有指定,则使用默认的本地文件系统)。第二个方法通过给定的URI方案和权限来确定要使用的文件系统,如果给定的URI中没有指定方案则返回默认文件系统。第三,作为给定用户来访问文件系统。
有了FileSystem 实例之后,调用open()函数来获取文件的输入流。
6、数据流:
剖析文件读取:
客户端及与之交互的HDFS、namenode和datanaode之间的数据流关系如下图所示。
客户端通过调用FileSystem对象的open()方法来打开希望读取的文件,对于HDFS来说,这个对象是分布式文件系统(步骤1)的一个实例。HDFS通过实验RPC来调用namenode,以确定文件起始块的位置(步骤2)。对于每一个块,namenode返回存有该块副本的datanode地址。
剖析文件写入:
下图展示了如何将文件写入HDFS的。目标是新建一个文件,把数据写入该文件,最后关闭该文件。
客户端通过HDFS对象调用create()方法来新建文件(步骤1),HDFS对namenode创建一个RPC调用在文件系统的命名空间中新建一个文件,此时该文件中还没有相应的数据块(步骤2)。Namenode执行各种不同的检查以确保这个文件不存在以及客户端有新建该文件的权限。在客户端写入数据时(步骤3),数据被分成一个个的数据包,并写入内部队列,称为“数据队列”。
7、使用Flume和Sqoop导入数据:
Apache Flume是一个将大规模流数据导入HDFS的工具。典型配置是在每个源机器上(如每个Web服务器)运行一个Flume节点,通过多个层级的聚合节点,最后将数据存入HDFS中。Apache Sqoop是为了将数据从结构化存储设备批量导入HDFS中设计的。Sqoop的应用场景是组织将白天生产的数据库中的数据在晚间导入Hive数据仓库中进行分析。
7、通过distcp并行复制:
据Hadoop有一个有用的distcp分布式复制程序,该程序可以从Hadoop文件系统间复制大量数据,也可以将大量的数据复制到Hadoop中。distcp典型的应用场景是在两个HDFS集群之间传输数据。
8、Hadoop存档
每个文件均按块方式存储,每个块的源数据存储咋namenode的内存中,因此Hadoop存储小文件会非常低效,因为大量的小文件会耗尽namenode中的大部分内存。
Hadoop存档文件或HAR文件是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明地访问。