全面解析HDFS

一、介绍

1.1 什么是HDFS?

HDFS(Hadoop Distributed File System),作为Google File System(GFS)的实现,是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了很多便利。

1.2 特点

  • 优点
    • 存储并管理PB级数据
    • 流式数据访问(一次写入多次读取的访问模式)
    • 所需硬件成本低(不需运行在可靠昂贵的硬件上)
    • 注重数据处理的吞吐量(延迟不敏感)
  • 不适合做
    • 存储小文件(不建议)
    • 大量随机读(不建议)
    • 对文件修改(不支持)
    • 多用户写入(不支持)

1.3 HDFS系统架构

在这里插入图片描述
HDFS由 NameNode(主节点)、DataNode(从结点)、SecondaryNameNode三个组件构成

1.4 NameNode

  • 管理着文件系统命名空间
    • 维护着文件系统树及树中的所有文件和目录
  • 存储元数据
    • NameNode保存元信息的种类有:
      • 文件名目录名及它们之间的层级关系
      • 文件目录的所有者及其权限
      • 每个文件块的名及文件有哪些块组成
  • 元数据保存在内存中
    • NameNode元信息并不包含每个块的位置信息
  • 保存文件,block,datanode之间的映射关系

1.5 DataNode

  • 负责存储数据块,负责为系统客户端提供数据块的读写服务
  • 根据NameNode的指示进行创建、删除和复制等操作
  • 心跳机制,定期报告文件块列表信息
  • DataNode之间进行通信,块的副本处理

1.6SecondaryNameNode(checkpoint节点)

  • 合并NameNode的edit logs到fsimage文件中
  • 不是要取代掉NameNode也不是NameNode的备份

二、数据块

2.1 介绍

  • HDFS默认数据块(block)大小为128M(hadoop 1.0为64M)
  • 磁盘块一般为512B
  • 在hdfs-site.xml配置文件中,增加全局参数dfs.block.size可以修改块大小
  • hdfs fsck / files -blocks 可查看块信息

2.2 为什么HDFS的块这么大

目的是为了最小化寻址开销,降低寻址时间/文件传输时间,如果块足够大,从磁盘传输数据的时间会明显大于定位开始位置所需的时间。
但是这个参数也不应设置得过大,MR中的map任务通常一次只处理一个块的数据,因此若任务数太少(少于集群中的结点数量),作业的运行速度会比较慢

三、元数据持久化

Namenode保留了HDFS的元数据,例如Namespace信息,块信息等。使用时,所有这些信息都存储在主存储器中。但是这些信息也存储在磁盘中以进行持久性存储。
上图显示了NameNode如何在磁盘上存储
fsimage - 它是在NameNode启动时对整个文件系统的快照
edit logs - 它是在NameNode启动后,对文件系统的改动序列

仅在重新启动namenode时,编辑日志才会应用于fsimage以获得文件系统的最新快照。但是,在生产集群中很少重启namenode,这意味着对于namenode长时间运行的集群,编辑日志会变得非常大。在这种情况下,我们将遇到以下问题。

  1. edit logs变得非常大,对其进行管理将具有挑战性
  2. 重新启动Namenode需要很长时间,因为必须合并很多更改
  3. 在崩溃的情况下,由于fsimage很旧,我们将丢失大量的元数据

改进:增加SecondaryNameNode
上图为SecondaryNameNode的工作流程

  • 它定期从namenode获取edit logs,并应用于fsimage
  • 一旦它有了新的fsimage文件,它将其拷贝回NameNode中。
  • NameNode在下次重启时会使用这个新的fsimage文件,从而减少重启的时间

注意:Secondary NameNode所做的不过是在文件系统 中设置一个检查点来帮助NameNode更好的工作。 它不是要取代掉NameNode也不是NameNode的 备份。

四、HA高可用

问题:Hadoop 1.0中NameNode在整个HDFS中只有一个,存在单点故障 风险,一旦NameNode挂掉,整个集群无法使用。
解决方法:HDFS的高可用性将通过在同一个集群中运行两个NameNode ( active NameNode & standby NameNode )来解决。

在这里插入图片描述
Active NameNode: 处理集群中的所有客户端操作。
Standby: 主要用于备用,它主要维持足够的状态,如果必要,可以提供快速的故障恢复。

4.1 工作要点

  • namenode之间需要通过高可用共享存储(JN)实现edit logs的共享。当备用namenode接管工作之后,它将通读共享edit logs直到结尾。
  • datanode需要同时向两个namenode发送数据块处理报告(发送心跳)
  • SecondaryNameNode的角色被备用namenode所包含,备用namenode为活动的name命名空间设置周期检查点(checkpoint)
  • 高可用共享存储(JN)作用是保持数据同步(path——blockid list列表),有两种:
    • NFS——网络文件系统
      • 需要额外的磁盘空间
    • QJM——群体日志管理器:以一组日志节点(journal node)的形式运行,每一次编辑必须写入多数日志节点。
      • 最低法人管理机制(投票)
      • 不需要额外的磁盘空间(只是一个进程)
      • 需要2n+1台机器存储edit log
      • QJM本质是小集群(不需要额外部署)
      • *不需要额外空间
      • *无单点问题(几个机器挂了不会影响投票)
      • *不会因为个别机器延迟,影响整体性能
      • *通过简单的系统配置可以实现
  • 隔离(Fence),即同一时刻仅仅有一个NameNode对外提供服务,防止脑裂(split-brain)
  • 必须保证两个NameNode之间能够ssh无密码登录。

4.2 部署问题

  • NN和JN通常不在一个机器上(数据同步到NN,需要额外的机器做部署)
  • FC和NN在一台机器上(FC监控NN)
  • RM和NN在同一台机器上(RM是yarn的主,NN是hdfs的主,通常部署在一台机器上)
  • zk需要单独维护一套独立的集群

五、HDFS读操作

在这里插入图片描述

  1. 客户端通过调用FileSystem对象的open()方法来打开要读取的文件,这个对象是DistributedFileSystem的一个实例。
  2. DistributedFileSystem通过使用远程调用(RPC)来调用namenode,以确定文件起始块的位置。对于每一个块,namenode返回存有该块副本的datanode地址。
  3. 响应于该元数据请求,具有该块的副本的数据节点的地址被返回。
  4. DistributedFileSystem类返回一个FSDataInputStream对象(一个支持文件定位的输入流)给客户端以便读取数据。FSDataInputStream类转而封装DFSInputStream对象,该对象管理着datanode和namenode的I/O,然后,客户端对这个输入流调用read()方法。
  5. 存储文件起始几个块的datanode地址的DFSInputStream随即连接距离最近的文件中第一个块所在的datanode。对数据流反复调用read()方法,将数据从datanode传输到客户端。
  6. 到达块的末端时,DFSInputStream关闭与该datanode的连接,然后寻找下一个块的最佳datanode。
    7.客户端完成读取后,对FSDataInputStream调用close()方法。

六、HDFS写操作

在这里插入图片描述

  1. 客户端通过对DistributedFileSystem对象调用create()来新建文件。
  2. DistributedFileSystem对象使用RPC调用连接到NameNode并启动新文件创建。但是,此文件创建操作不会将任何块与该文件关联
    NameNode负责验证文件(正在创建)尚不存在,并且客户端具有创建新文件的正确权限。如果文件已经存在或客户端没有足够的权限来创建新文件,则 IOException将 被抛出给客户端。否则,操作将成功,并且NameNode将创建该文件的新记录。
  3. DistributedFileSystem向客户端返回一个FSDataOutputStream对象,客户端开始写入数据。
  4. FSDataOutputStream封装一个DFSOutputstream对象,该对象负责处理datanode和namenode之间的通信。在客户端继续写入数据的同时,DFSOutputStream继续使用此数据创建数据包。这些数据包入队到称为DataQueue的队列中 。
  5. DataStream处理数据队列,它负责挑选出合适存储数据复本的一组Datanode,并据此来要求namenode分配新的数据块。
  6. 现在,复制过程开始于使用DataNodes创建管道。这一组Datanode构成一个管线——假设复本数为3,所以管线中有3个节点。
  7. DataStreamer将数据包流式传输到管线中第一个datanode。
  8. 第一个datanode存储数据包后将它发送到管线中的第2个datanode,同样,第二个datanode存储数据包后发送到管线中的第3个(最后一个)datanode。
  9. DFSOutputStream维护着一个叫"确认队列"(Ack Queue)的内部数据包队列,存储等待数据节点确认的数据包。
  10. 一旦从管道中的所有DataNode接收到队列中数据包的确认,便将其从"确认队列"中删除。
    注意:
    如果任何 datanode 在数据写入期间发生故障, 则执行以下操作(对写入数据的客户端是透明的)。首先关闭管线,确认把队列中的所有数据包都添加回数据队列的最前端, 以确保故障节点下游的 datanode 不会漏掉任何一个数据包。为存储在另一正常 datanode 的当前数据块指定一个新的标识, 并将该标识传送给 namenode, 以便故障 datanode 在恢复后可以删除存储的部分数据块。从管线中删除故障datanode, 基于两个正常 datanode 构建一条新管线。余下的数据块写入管线中正
    常的 datanode。namenode 注意到块复本量不足时, 会在另一个节点上创建一个新的复本。后续的数据块继续正常接受处理。
  11. 客户端完成数据的写入后,对数据流调用close(),将剩余的所有数据写入datanode管线 中。
  12. 收到最终确认后,将与NameNode联系以告知其文件写入操作已完成。

七、Block副本放置策略

在这里插入图片描述

  • 第一个副本,在客户端相同的节点(如果客户端是集群外的一台机器,就随机算节点,但是系统会避免挑选太满或者太忙的节点)
  • 第二个副本,放在不同机架(随机选择)的节点
  • 第三个副本,放在与第二个副本同机架但是不同节点上。

在这里插入图片描述

  • distance(/D1/R1/H1,/D1/R1/H1)=0 相同的datanode
  • distance(/D1/R1/H1,/D1/R1/H3)=2 同一rack下的不同datanode
  • distance(/D1/R1/H1,/D1/R2/H5)=4 同一IDC下的不同datanode
  • distance(/D1/R1/H1,/D2/R3/H9)=6 不同IDC下的datanode
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值