hdfs读写流程_深度探索Hadoop分布式文件系统(HDFS)数据读取流程

一、开篇

Hadoop分布式文件系统(HDFS)是Hadoop大数据生态最底层的数据存储设施。因其具备了海量数据分布式存储能力,针对不同批处理业务的大吞吐数据计算承载力,使其综合复杂度要远远高于其他数据存储系统。

因此对Hadoop分布式文件系统(HDFS)的深入研究,了解其架构特征、读写流程、分区模式、高可用思想、数据存储规划等知识,对学习大数据技术大有裨益,尤其是面临开发生产环境时,能做到胸中有数。

本文重点从客户端读取HDFS数据的角度切入,通过Hadoop源代码跟踪手段,层层拨开,渐渐深入Hadoop机制内部,使其读取流程逐渐明朗化。

二、HDFS数据读取整体架构流程

9dce0d3f4f3c2c36c23aceed8bb51c71.png

如上图所示:描绘了客户端访问HDFS数据的简化后整体架构流程。
  • 客户端向hdfs namenode节点发送Path文件路径的数据访问的请求

  • Namenode会根据文件路径收集所有数据块(block)的位置信息,并根据数据块在文件中的先后顺序,按次序组成数据块定位集合(located blocks),回应给客户端

  • 客户端拿到数据块定位集合后,创建HDFS输入流,定位第一个数据块所在的位置,并读取datanode的数据流。之后根据读取偏移量定位下一个datanode并创建新的数据块读取数据流,以此类推,完成对HDFS文件的整个读取。

三、Hadoop源代码分析经过上述简单描述,我们对客户端读取HDFS文件数据有了一个整体上概念,那么这一节,我们开始从源代码跟踪的方向,深度去分析一下HDFS的数据访问内部机制。(一)  namenode代理类生成的源代码探索为什么我们要先从namenode代理生成说起呢?原因就是先了解清楚客户端与namenode之间的来龙去脉,再看之后的数据获取过程就有头绪了。

1. 首先我们先从一个hdfs-site.xml配置看起

    dfs.client.failover.proxy.provider.fszx

    org.apache.hadoop.hdfs.server.namenode.ha.

    ConfiguredFailoverProxyProvider

配置中定义了namenode代理的提供者为ConfiguredFailoverProxyProvider。什么叫namenode代理?其实本质上就是连接namenode服务的客户端网络通讯对象,用于客户端和namenode服务端的交流。

2. 分析ConfiguredFailoverProxyProvider

f92bc2af39664abb59b7eaf56b0b81b1.png上图是ConfiguredFailoverProxyProvider的继承关系,顶端接口是FailoverProxyProvider,它包含了一段代码:

  /**

   * Get the proxy object which should be used until the next failover event

   * occurs.

   * @return the proxy object to invoke methods upon

   */

  public ProxyInfo getProxy();

这个方法返回的ProxyInfo就是namenode代理对象,当然客户端获取的ProxyInfo整个过程非常复杂,甚至还用到了动态代理,但本质上就是通过此接口拿到了namenode代理。

3. 此时类关系演化成如下图所示:

3f740ab8461429e23afa6af704c318ff.png上图ProxyInfo就是namenode的代理类,继承的子类NNProxyInfo就是具体指定是高可用代理类。

4. 那么费了这么大劲搞清楚的namenode代理,它的作用在哪里呢?

这就需要关注一个极为重要的对象DFSClient了,它是所有客户端向HDFS发起输入输出流的起点,如下图所示:9203e83f5e2596aa5ac96523c8c15970.png上图实线代表了真实的调用过程,虚线代表了对象之间的间接关系。我们可以看到DFSClient是一个关键角色,它由分布式文件系统对象(DistributeFileSystem)初始化,并在初始化中调用NameNodeProxiesClient等一系列操作,实现了高可用NNproxyInfo对象创建,也就是namenode代理,并最终作为DFSClient对象的一个成员,在创建数据流等过程中使用。(二)  读取文件流的深入源代码探索

1. 首先方法一样,先找一个切入口。建立从HDFS下载文件到本地的一个简单场景,以下是代码片段

……

//打开HDFS文件输入流

input = fileSystem.open(new Path(hdfs_file_path));

//创建本地文件输出流

output = new FileOutputStream(local_file_path);

//通过IOUtils工具实现数据流字节循环复制

IOUtils.copyBytes(input, output, 4096, true);

……

咱们再看看IOUtils的一段文件流读写的方法代码。

/**

   * Copies from one stream to another.

   * 

   * @param in InputStrem to read from

   * @param out OutputStream to write to

   * @param buffSize the size of the buffer 

   */

  public static void copyBytes(InputStream in, OutputStream out, int buffSize) 

    throws IOException {

      PrintStream ps = out instanceof PrintStream ?

       (PrintStream)out : null;

      byte buf[] = new byte[buffSize];

      int bytesRead = in.read(buf);

      while (bytesRead >= 0) {

      out.write(buf, 0, bytesRead);

      if ((ps != null) && ps.checkError()) {

          throw new IOException("

          Unable to write to output stream.");

      }

      bytesRead = in.read(buf);

    }

  }

这段代码是个标准的循环读取HDFS InputStream数据流,然后向本地文件OutputStream输出流写数据的过程。我们的目标是深入到HDFS InputStream数据流的创建和使用过程。

2. 接下来我们开始分析InputStream的产生过程,如下图所示:

5abcfc8e80c01a7f5ce90c4112361d1b.png上图实线代表了真实的调用过程,虚线代表了对象之间的间接关系。其代码内部结构极为复杂,我用此图用最简化的方式让我们能快速的理解清楚他的原理。我来简单讲解一下这个过程:
  • 第一步 

是DistributeFileSystem通过调用DFSClient对象的open方法,实现对DFSInputStream对象的创建,DFSInputStream对象是真正读取数据块(LocationBlock)以及与datanode交互的实现逻辑,是真正的核心类。
  • 第二步 

DFSClient在创建DFSInputStream的过程中,需要为其传入调用namenode代理而返回的数据块集合(LocationBlocks)。
  • 第三步

DFSClient创建一个装饰器类HDFSDataInputStream,封装了DFSInputStream,由装饰器的父类FSDataInputStream最终返回给DistributeFileSystem,由客户端开发者使用。

3. 最后我们再深入到数据块读取机制的源代码上看看,如下图所示:

35d849bea66a77f08fb9c33a89cce0ba.png上图实线代表了真实的调用过程,虚线代表了对象之间的间接关系。实际的代码逻辑比较复杂,此图也是尽量简化展现,方便我们理解。一样的,我来简单讲解一下这个过程:
  • 第一步 

FSDataInputStream装饰器接受客户端的读取调用对DFSInputStream对象进行read(...)方法调用。
  • 第二步 

DFSInputStream会调用自身的blockSeekTo(long offset)方法,一方面根据offset数据偏移量,定位当前是否要读取新的数据块(LocationBlock),另一方面新的数据块从数据块集合(LocationBlocks)中找到后,寻找最佳的数据节点,也就是Hadoop所谓的就近原则,先看看本机数据节点有没有副本,再次根据网络距离着就近获取副本。
  • 第三步 

通过FSDataInputStream副本上数据块(LocationBlock)构建BlockReader对象,它就是真正读取数据块的对象。BlockReader对象它有不同的实现,由BlockReaderFactory.build根据条件最优选择具体实现,BlockReaderLocal和BlockReaderLocalLegacy(based on HDFS-2246)是优选方案,也是short-circuit block readers方案,相当于直接从本地文件系统读数据了,若short-circuit因为安全等因素不可用,就会尝试UNIX domain sockets的优化方案,再不行才考虑BlockReaderRemote建立TCP sockets的连接方案了。BlockReader的细节原理也非常值得深入一探究竟,下次我专门写一篇针对BlockReader原理机制文章。四、结束非常感觉您能看完。下一篇我会对“Hadoop分布式文件系统(HDFS)数据写入流程”做一篇深度探索分析。期盼您的关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python可视化分析网易云音乐评论_Python数据可视化:网易云音乐歌单

网易云音乐2018年度听歌报告—遇见你,真好。相信有不少人在上周,应该已经看过自己网易云音乐的年度报告了。小F也是去凑凑热闹,瞅了一波自己的年度听歌报告。那么你在云村又听了多少首歌,听到最多的歌词又是什么呢?2018年你的年度…

mysql隔离级别验证_MySQL事务隔离级别以及验证

查询初始数据开启A事务  并做更新操作再另一端 B开始另一个事务查询 事务级别设置为读未提查询到事务未提交的数据 a的count修改为3 但是没有提交2 第二个级别 读已提交 避免脏读问题 但是有不可重复读问题回滚数据 修改隔离级别 确保都是 读已提交级别客户端A客户端B验证 脏…

登录样式:log4j 2,上下文,自动清除…全部不附加任何字符串!

日志记录-保持操作的时间跟踪-对于任何关键任务系统,无论大小,都至关重要。 我们的Project-X框架也是如此 ,这就是为什么我们希望从一开始就正确地做到这一点。 基于我们在传奇的UltraESB上的登录经验, 上下文日志记录&#xff0…

python37安装失败_Linux 安装Python37

1、下载python3.7.0https://www.python.org/downloads/release/python-370/2、创建Linux的python37目录mkdir /usr/local/python373、解压python3.7.0源码tar zxvf python3.7.0.tar.zg4、配置编译参数./configure --prefix/usr/local/python375、make6、make install注意&#…

python string模块template_Python标准库笔记(1) — string模块

String模块包含大量实用常量和类,以及一些过时的遗留功能,并还可用作字符串操作。1. 常用方法常用方法描述str.capitalize()把字符串的首字母大写str.center(width)将原字符串用空格填充成一个长度为width的字符串,原字符串内容居中str.count…

注意力机制可视化_目标跟踪中的(STAM)时空注意力机制

目标跟踪分为单目标跟踪和多目标跟踪,单目标跟踪较为简单,这里我们只讨论多目标跟踪。多目标跟踪的遮挡问题多目标跟踪时特别容易发生目标间的相互遮挡,从而导致严重的预测偏移问题,如下图所示:红色框的行人在和蓝色框…

byteman_使用Byteman和JUnit进行故障注入

byteman我们的应用程序独立存在的时间已经很久了。 如今,应用程序是一种非常复杂的野兽,它们使用无数的API和协议相互通信,将数据存储在传统或NoSQL数据库中,通过网络发送消息和事件……例如,您多久考虑一次例如数据库…

java动态扩展_java栈内存动态扩展要怎么理解?要如何实现?

小伙伴们知道如何在java栈中内存动态扩展吗?这是虚拟机中的一个概念,下面让我们一起来看看该如何实现吧。一、内存概念在java中,我们一般会简单把java内存区域划为两种:堆内存与栈内存。其实这种划分是比较粗粒度的。其中栈内存就是指的是虚…

python 爬虫热搜_Python网络爬虫之爬取微博热搜

微博热搜的爬取较为简单,我只是用了lxml和requests两个库1.分析网页的源代码:右键--查看网页源代码.从网页代码中可以获取到信息(1)热搜的名字都在的子节点里(2)热搜的排名都在的里(注意置顶微博是没有排名的!)(3)热搜的访问量都在的子节点里…

优盘复制进来为空_为何电脑上的文件夹一复制到U盘里就变成空文件夹了?

(格式化后的卡在恢复前千万不要往里面存东西,因为这样会覆盖你想恢复的内容,如果你不小心存东西了也不要放弃,只不过恢复的机率会变小),下面开始:::在百度里输入Easy recover 软件找到后下载安装到电脑上,然后将内存卡与电脑连接,打开Easy recover 软件,首次打开时软件会分析系…

Spring Cloud教程–使用Spring Cloud Bus自动刷新配置更改

问题 在上一篇文章Spring Cloud Config Server简介 ( http://sivalabs.in/2017/08/spring-cloud-tutorials-introduction-to-spring-cloud-config-server/ )中,我们已经了解了如何使用Spring Cloud配置服务器。 但是,问题是要重新…

js给标签添加属性和值_jquery节点属性

一.节点操作1.DOM内容节点操作:​ ①innerHTML属性:设置或获取文本的内容(普通文本和标签)。​ ②innerText属性:设置或获取文本的内容(普通文本),存在兼容性问题。2.jQuery内容节点…

sci translate好用吗_228个学科分类对应12000+本SCI和SSCI期刊,总有你要的那款!

最近有很多小伙伴询问选刊的问题,而且都是非常具体的学科方向,我们的小编虽然非常热心且礼貌的回答“近期安排”,但其实我们也感觉到鸭梨山大:根据WOS最新一期(2020/9/21)名单公布,WOS目前总共收录了12266本…

java 反射 属性顺序_java反射得到的方法数组的顺序

展开全部看了下你好像需要set和get方法,如果你知道属性的名字的话不需要遍历可以这样获取,这个是我以前的demo的一个32313133353236313431303231363533e58685e5aeb931333332633561片段:Class clazzClass.forName("com.demo.reflectdemo.Student&quo…

arrays.sort(._Arrays.sort与Arrays.parallelSort

arrays.sort(.我们都使用Arrays.sort对对象和原始数组进行排序。 此API在下面使用合并排序或Tim排序对内容进行排序,如下所示: public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sor…

python冒泡排序函数_python冒泡排序-Python,冒泡排序

arr[7,4,3,67,34,1,8].defbubble_sort:最近在学习Python,下面是我的一些笔记冒泡排序实现思路: 使用双重for循环,内层变量为i, 外层为j,在内层循环中不断的比较相邻的两个值(i, i1)的大小,如果i1的值大于i的…

适用于Idea的面向现代TDD的Java 8 JUnit测试模板(带有Mockito和AssertJ)

使用类似BDD的语法,Java 8和Mockito-AssertJ二重奏为Idea调整JUnit测试类模板。 本文涵盖的主题似乎很简单。 但是,根据我的培训师经验,我知道(不幸的是)这不是常见的做法。 因此,我决定写这篇简短的博客文…

python编程的基本方法有哪些_Python编程中常用的基础知识有哪些?

今天小编要跟大家分享的文章是关于Python编程中常用的基础知识有哪些?正在从事Python相关工作的小伙伴们,来和小编一起看一看本篇文章,希望本篇文章能够对大家有所帮助。1、正则表达式替换目标: 将字符串 line 中的 overview.gif 替换成其他字符串>&…

java取网页源码_Java获取任意http网页源代码的方法

本文实例讲述了JAVA获取任意http网页源代码。分享给大家供大家参考,具体如下:JAVA获取任意http网页源代码可实现如下功能:1. 获取任意http网页的代码2. 获取任意http网页去掉HTML标签的代码Webpage类:/*** 网页操作相关类*/packag…

python数据结构算法优势_Python数据结构与算法(一)----- 算法效率

一.引入先来看一道题:如果abc1000, 且a2b2c^2(a,b,c为自然数),如何求出所有a,b,c可能的组合?(1) 枚举法import timestart_time time.time()for a in range(0,1001):for b in range(0,1001):for c in range(1,1001):if abc1000 and a**2b**2 …