菜单

Administrator
发布于 2026-05-18 / 1 阅读
0
0

深入理解HDFS

深入理解HDFS

本文详细介绍了HDFS中的许多概念,对于理解Hadoop分布式文件系统很有帮助。

1. 介绍

在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统。而一旦在系统中引入网络,就不可避免地引入了所有网络编程的复杂性,例如挑战之一是如果保证在节点不可用的时候数据不丢失。

传统的网络文件系统(NFS)虽然也称为分布式文件系统,但是其存在一些限制。由于NFS中,文件是存储在单机上,因此无法提供可靠性保证,当很多客户端同时访问NFS Server时,很容易造成服务器压力,造成性能瓶颈。

HDFS,是Hadoop Distributed File System的简称,是Hadoop抽象文件系统的一种实现。Hadoop抽象文件系统可以与本地系统、Amazon S3等集成,甚至可以通过Web协议(webhsfs)来操作。HDFS的文件分布在集群机器上,同时提供副本进行容错及可靠性保证。

2. HDFS设计原则

2.1 设计目标

  • 存储非常大的文件:这里非常大指的是几百M、G、或者TB级别。实际应用中已有很多集群存储的数据达到PB级别。
  • 采用流式的数据访问方式:最有效的数据处理模式是一次写入、多次读取。数据集经常从数据源生成或者拷贝一次,然后在其上做很多分析工作。
  • 运行于商业硬件上:Hadoop不需要特别贵的、reliable的机器,可运行于普通商用机器。商用机器不代表低端机器,在集群中节点失败率是比较高的,HDFS的目标是确保集群在节点失败的时候不会让用户感觉到明显的中断。

2.2 HDFS不适合的应用类型

  1. 低延时的数据访问:对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时。HBase更适合低延时的数据访问。
  2. 大量小文件:文件的元数据保存在NameNode的内存中,整个文件系统的文件数量会受限于NameNode的内存大小。一个文件/目录/文件块一般占有150字节的元数据内存空间。
  3. 多方读写,需要任意的文件修改:HDFS采用追加(append-only)的方式写入数据。不支持文件任意offset的修改,不支持多个写入器(writer)。

3. HDFS核心概念

3.1 Blocks

HDFS的Block块比一般单机文件系统大得多,默认为128M。HDFS的文件被拆分成block-sized的chunk,chunk作为独立单元存储。比Block小的文件不会占用整个Block,只会占据实际大小。

HDFS的Block为什么这么大? 是为了最小化查找(seek)时间,控制定位文件与传输文件所用的时间比例。假设定位到Block所需的时间为10ms,磁盘传输速度为100M/s。如果要将定位到Block所用时间占传输时间的比例控制1%,则Block大小需要约100M。

Block抽象的好处:

  • block的拆分使得单个文件大小可以大于整个磁盘的容量
  • Block的抽象也简化了存储系统
  • Block作为容错和高可用机制中的副本单元

3.2 Namenode & Datanode

整个HDFS集群由Namenode和Datanode构成master-worker(主从)模式。Namenode负责构建命名空间,管理文件的元数据等,而Datanode负责实际存储数据,负责读写工作。

Namenode 存放文件系统树及所有文件、目录的元数据。元数据持久化为2种形式:namespace image 和 edit log。

Datanode 负责存储和提取Block,读写请求可能来自namenode,也可能直接来自客户端。数据节点周期性向Namenode汇报自己节点上所存储的Block相关信息。

3.3 HDFS Federation

我们知道NameNode的内存会制约文件数量,HDFS Federation提供了一种横向扩展NameNode的方式。在Federation模式中,每个NameNode管理命名空间的一部分。

每个NameNode管理一个namespace volumn,所有volumn构成文件系统的元数据。各NameNode之间是独立的,一个节点的失败不会导致其他节点管理的文件不可用。

3.4 HDFS HA

在HDFS集群中,NameNode是单点故障(SPOF)。HA方案中配置两个NameNode,分别处于Active和Standby状态。

HA主要实现逻辑:

  1. 主备需共享edit log存储:QJM(quorum journal manager)是专门为HDFS的HA实现而设计的,用来提供高可用的edit log
  2. DataNode需要同时往主备发送Block Report
  3. 客户端需要配置failover模式(对用户透明)
  4. Standby替代Secondary NameNode

4. 命令行接口

HDFS提供了各种交互方式,例如通过Java API、HTTP、shell命令行。

hadoop fs -copyFromLocal  # 从本地复制文件到HDFS
hadoop fs mkdir           # 创建目录
hadoop fs -ls             # 列出文件列表

Hadoop中,文件和目录的权限类似于POSIX模型,包括读、写、执行3种权限。

5. Hadoop文件系统

Hadoop的文件系统概念是抽象的,HDFS只是其中的一种实现。其他实现包括:

  • Local:对本地文件系统的抽象
  • har:Hadoop体系下的压缩文件
  • viewfs:在客户端屏蔽多个Namenode的底层细节
  • WebHDFS/SWebHDFS:通过HTTP提供文件操作接口
  • s3a/azure:云服务平台实现

6. Java接口

6.1 读操作

使用FileSystem API读取数据:

// 获取FileSystem实例
public static FileSystem get(Configuration conf) throws IOException
public static FileSystem get(URI uri, Configuration conf) throws IOException

// 调用FileSystem的open方法获取输入流
public FSDataInputStream open(Path f) throws IOException

// 使用FSDataInputStream进行数据操作

6.2 写数据

String localSrc = args[0];
String dst = args[1];
InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(dst), conf);
OutputStream out = fs.create(new Path(dst), new Progressable() {
    public void progress() {
        System.out.print(".");
    }
});
IOUtils.copyBytes(in, out, 4096, true);

6.3 目录操作

使用mkdirs()方法会自动创建没有的上级目录。HDFS中元数据封装在FileStatus类中,包括长度、block size、replications等。

6.4 删除数据

public boolean delete(Path f, boolean recursive) throws IOException;

7. 数据流(读写流程)

7.1 读文件

  1. 客户端传递一个文件Path给FileSystem的open方法
  2. DFS采用RPC远程获取文件最开始的几个block的datanode地址
  3. 客户端使用FSDataInputStream对象读取数据
  4. DFSInputStream连接持有第一个block的、最近的节点读取数据
  5. 第一个block读取完毕后,寻找下一个block的最佳datanode
  6. 数据读取完毕,客户端调用close方法关闭流对象

7.2 写文件

  1. 客户端调用DistributedFileSystem的create方法
  2. DistributedFileSystem远程RPC调用Namenode创建一个新文件
  3. DFSOutputStream分解为packets,写入数据队列
  4. DataStreamer请求Namenode分配新的block存放的数据节点
  5. DFSOutputStream维护ack queue队列,等待datanode确认
  6. 数据写入完毕,客户端close输出流

7.3 副本存放策略

  • 第一个副本放在客户端相同的机器上
  • 第二个副本随机放在不同于第一个副本的机架上
  • 第三个副本放在跟第二个副本同一机架上,但是不同的节点上

评论