Hadoop三部曲搞起~

该文章已更新到语雀中,后台回复“语雀”可获取进击吧大数据整个职业生涯持续更新的所有资料(密码每周更新一次)

入门大数据,通常先从Hadoop学习。通过本文可以学习到以下几点:

  1. Hadoop基本特性

  2. HDFS读流程

  3. HDFS写流程

  4. HDFS追加流程

  5. HDFS数据块的一致性保障

一、Hadoop基本特性

   Hadoop是一种分布式系统基础架构,由Apache基金会维护,Hadoop框架最核心的设计就是MapReduce和HDFS。其中一个组件是HDFS(Hadoop Distributed File System)为海量数据提供了存储,具有高容错的特点,而且可以在通过廉价的硬件存储海量的数据。而且也具有高吞吐量的特点。HDFS放宽了POSIX的要求,可以以流的方式来访问数据。而MapReduce则为海量的数据提供了计算。Hadoop具有以下几个优点:

1.高可靠性:Hadoop按位存储和处理数据的能力值得人们信赖。

2.高扩展性:Hadoop将海量数据分配到可用的计算机器之间,而且可以很方便的扩展数千以上的节点来增加数据存储能力和计算能力。

3.高效性:Hadoop能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此处理速度非常快。

4.高容错性:Hadoop能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配 。

5.低成本:与一体机、商用数据仓库以及QlikView、Yonghong Z-Suite等数据集市相比,hadoop是开源的,项目的软件成本因此会大大降低。

本篇文章将围绕着HDFS组件来介绍比较核心的三块流程。

图片

二、HDFS读取流程

图片

整体读取流程如上图所示,接下来详细介绍下具体细节:

  1. 客户端执行读取命令或者通过API调用读取接口,这个时候呢,底层会通过ClientProtocol和NameNode进行通信,NameNode根据读取的条件获取文件起始位置对应的数据块信息。

  2. 客户端拿到获取到的数据块信息之后(这里面也包含了数据块对应的真正存储位置即在哪个机架的哪台机器上),然后选择离客户端最近的一个DataNode节点建立连接,为什么选择最近的呢?因为中间涉及到网络IO,序列化、反序列化等一系列远程操作,这都是比较耗时的。当建立连接后,进行数据块读取操作。

  3. 客户端底层会通过调用DFSInputStream.read()方法以packaet的方式从DataNode节点上获取数据。

  4. 当客户端拿到返回的数据块时候,要先进行校验的,不然取到坏块不就坏事了。当校验值不一样或者是在读取的过程当中DataNode出现了异常,那么会通过ClientProtocol.reportBadBlocks方法向NameNode汇报坏块的信息,然后NameNode收到这个信息后呢,会发出块平衡指令,因为默认块副本是3份,现在少了一份岂不是要重新复制一份了

  5. 这个时候客户端会从副本数据块所在的DataNode节点上进行通信拉取数据,同样也会进行校验操作的。该有的流程一部都不能少。

  6. 当该数据块读取完成之后呢,还没完事,会再次请求NameNode获取下一个数据块对应的DataNode节点信息。

  7. 以此循环1~6步骤,直到所有的数据块都读取完成后,最后关闭输入流。

这里总结一下,大概有这么几个步骤:

  1. 客户端发起打开文件请求

  2. 获取DataNode位置信息

  3. DataNode通信连续获取数据块

  4. 校验数据块,并做异常处理

  5. 关闭输入流,Over!

三、HDFS写流程

图片

写HDFS的具体流程如下:

  1. 当客户端发起写请求的时候,会先让NameNode创建一个空的文件,然后把这个操作记录到editLog中,这个时候呢会返回一个DFSOutputStream输出流对象,这样可以进入后续的写了。

  2. 当客户端拿到输出流对象后,会向NameNode申请数据块,不然客户端怎么知道往哪写呢?当客户端拿到对应的DataNode位置信息后,就开始通信建立管道,这样就可以用来传输数据了。

  3. 客户端这个时候开始发送数据,但不可能一下子全发出去,而且会将这些数据切分成Packet发送到DataNode节点上,然后DataNode开始进行确认,没问题就返回给输出流一个ack消息。

  4. 上文也提到HDFS具有高容错的特点,所以数据写到一个节点上,万一节点挂了数据岂不是丢失了?所以在数据写到该节点的时候呢,会和其他节点进行通信以Pipeline的方式传输数据,这样数据就会保留多份。具体要保留几份,结合你实际的存储资源和数据重要性。

  5. 当所有的DataNode节点都确认了把数据写入成功后,输出流就会从缓存队列中删掉这个数据包(这个缓存队列是来放未确认的packet),当DataNode成功接收到一个数据块之后呢,会向NameNode大管家进行汇报,那么NameNode就会更新内存中的元数据信息(也就是这个块在哪些节点上存储的,块涉及到的数据范围是怎么样的)。

  6. 当客户端把一个块写满之后呢,会再次向NameNode申请新的数据块,然后循环执行1~5步骤。(以前一个块的大小是64MB,现在更改为128MB,在实际生产中可能会设置为256MB)。

  7. 当客户端把文件中的所有数据都写完之后,就会关闭输出流,然后通知NameNode提交所有的数据块。

总结一下:

  1. 创建空文件

  2. 建立流管道

  3. 开始写数据、副本复制

  4. 关闭管道、提交文件

四、HDFS追加写流程

图片

除了写流程之后,通常还会有一些追加写的场景,内部具体流程如下:

  1. 客户端发起一个往已经存在的文件写的请求,这个时候NameNode会返回该文件最后一个块的位置信息,并实例化一个DFSOutputStream输出流,同时呢会拿到一个租约(租约问题就不展开来说了,可以理解为是一个门票是有有效期的)。

  2. 如果最后一个块已经被写满了之后会返回Null,并向NameNode申请新的数据块,否则的话就开始建立管道并写数据。

  3. 客户端开始发送数据,这些数据会被切分成Packet发送到DataNode节点,然后DataNode之间进行复制,然后DataNode进行确认,返回给输出流一个ack消息。

  4. 当所有的DataNode节点都确认了数据写入成功之后,输出流就会从缓存队列中删除这个数据包,和普通写的流程是一样的。

  5. 当客户端写满一个数据块之后,会申请新的数据块,循环执行1~5步骤。

  6. 当客户端把文件所有的数据都写完之后,就会关闭输出流,通知NameNode提交所有的数据块。

以上就是HDFS核心的三部曲了,这里再对写流程展开来思考一下,如果在写的过程中出现了异常会不会造成数据丢失呢?hadoop是怎么保障集群中的所有节点的数据块是一致准确的呢?

五、数据容错一致性保障

我们先来了解下在写的过程中是如何保障不丢的?

首先在输出流的设计中,上文也提及到一个缓存队列的东西,这个是用来存储未被确认的数据包的,如果在写的过程中节点出现了异常或者网络通信出现了故障,那么就会把未确认的数据包重新加入到发送队列中,所以这么一来就不会出现某一个块的丢失,因为所有的块都必须要进行确认的。

还有一个问题就是集群是如何保障数据块在所有的节点上是一致准确的?

这里其实是有一个时间戳的机制,也就是说在写入数据块的时候会申请一个时间戳,然后会用这个时间戳来建立一个管道。这里举两种情况:

一个是DataNode假死的情况:当往一个DataNode节点上写数据的时候,比如突然说DataNode负载很高,没有向NameNode发送心跳,那么就会误认为这个挂掉了,这个时候客户端会向NameNode汇报,并重新申请时间戳建立新的管道,当该节点恢复后会出现故障前的时间戳和NameNode保存的时间戳不一样,那么DataNode就会把失效的块进行删除,这样就保障了所有的数据块都是一致的。

一个是DataNode真的挂了的情况:这种情况下客户端会向新的DataNode进行通信,申请新的时间戳建立通道,同时这个节点上还没有存储这个新的数据块,因此会先通过其他的DataNode节点把数据块复制到该节点上,这样就保障了数据块不会丢失的。

猜你喜欢

转载自blog.csdn.net/qq_28680977/article/details/122149413