2014-11-09---Hadoop的基础学习(二)----HDFS的特性和JavaAPI源码分析
2014-11-09---Hadoop的基础学习(二)----HDFS的特性和JavaAPI源码分析
查封炉台 发表于3年前
2014-11-09---Hadoop的基础学习(二)----HDFS的特性和JavaAPI源码分析
  • 发表于 3年前
  • 阅读 1107
  • 收藏 60
  • 点赞 3
  • 评论 6

新睿云服务器60天免费使用,快来体验!>>>   

摘要: Hadoop Distributed File System (HDFS) — Apache Hadoop 项目的一个子项目 — 是一个高度容错的分布式文件系统,设计用于在低成本硬件上运行。HDFS 提供高吞吐量应用程序数据访问功能,适合带有大型数据集的应用程序。本文探索 HDFS 的主要特性,并深入其API源码,简单查看实现的流程.

1.HDFS概览

HDFS 是一个 Apache Software Foundation 项目,是 Apache Hadoop 项目的一个子项目。Hadoop 非常适于存储大型数据(比如 terabytes和petabytes),并使用 HDFS 作为其存储系统。HDFS 允许您连接多个集群中包含的节点 (普通个人计算机),那些集群上分布着一些数据文件。然后您可以将那些数据文件作为一个无缝文件系统来进行访问和存储。对数据文件的访问通过一种流线型(streaming) 方式进行处理,这意味着应用程序或命令通过 MapReduce 处理模型直接执行(参见 参考资料)。HDFS 是容错的,且提供对大数据集的高吞吐量访问。

HDFS 与其他分布式文件系统有许多相似点,但也有几个不同点。一个明显的区别是 HDFS 的 “一次写入、多次读取(write-once-read-many)” 模型,该模型降低了并发性控制要求,简化了数据聚合性,支持高吞吐量访问。

HDFS 的另一个独特的特性是下面这个观点:将处理逻辑放置到数据附近通常比将数据移向应用程序空间更好。

HDFS 将数据写入严格限制为一次一个写入程序。字节总是被附加到一个流的末尾,字节流总是以写入顺序存储。

HDFS 有许多目标,下面是一些最明显的目标:

  • 通过检测故障和应用快速、自动的恢复实现容错性

  • 通过 MapReduce 流进行数据访问

  • 简单可靠的聚合模型

  • 处理逻辑接近数据,而不是数据接近处理逻辑

  • 跨异构普通硬件和操作系统的可移植性

  • 可靠存储和处理大量数据的可伸缩性

  • 通过跨多个普通个人计算机集群分布数据和处理来节约成本

  • 通过分布数据和逻辑到数据所在的多个节点上进行平行处理来提高效率

  • 通过自动维护多个数据副本和在故障发生时自动重新部署处理逻辑来实现可靠性

HDFS应用程序接口(API)

您可以以多种不同的方法访问 HDFS。HDFS 提供了一个原生 Java™ 应用程序编程接口(API重点介绍)和一个针对这个 Java API 的原生 C 语言封装器。另外,您可以使用一个 web 浏览器来浏览 HDFS 文件.例外还有以下可以来访问HDFS:

2.HDFS的SHELL操作

既然HDFS 是存取数据的分布式文件系统,那么对HDFS 的操作,就是文件系统的基本操作,比如文件的创建、修改、删除、修改权限等,文件夹的创建、删除、重命名等。对HDFS 的操作命令类似于lLinux 的shell 对文件的操作,如ls、mkdir、rm 等。我们执行以下操作的时候,一定要确定hadoop 是正常运行的,使用jps 命令确保看到各个hadoop 进程。SHELL操作较多,简介见文档Hadoop-Shell.pdf还有该链接http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html,就不一个一个介绍啦。

3.HDFS的体系结构和基本概念

我们通过hadoop shell 上传的文件是存放在DataNode 的block 中,通过linux shell 是看不到文件的,只能看到block。可以一句话描述HDFS:把客户端的大文件存放在很多节点的数据块中。在这里,出现了三个关键词:文件、节点、数据块。HDFS 就是围绕着这三个关键词设计的,我们在学习的时候也要紧抓住这三个关键词来学习。

HDFS 由一些互联的节点集群组成,文件和目录驻留在那些节点上。一个 HDFS 集群包含一个节点,称为 NameNode,该节点管理文件系统名称空间并规范客户端对文件的访问。另外, Data node (DataNodes)将数据作为块存储在文件中。HDFS的架构图如下:

由上图可知:在 HDFS 中,一个给定的NameNode是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表两套数据,Namenode还将数据块映射到Data node,处理来自 HDFS 客户端的读写请求。 Data node 还根据 Name node 的指令创建、删除和复制数据块。

3.1 NameNode

  其中的文件放在指定目录(有配置文件core-site.xml的dfs.name.dir属性决定).在该目录下包括:

  • fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。在内存...

  • edits:操作日志文件。

  • fstime:保存最近一次checkpoint的时间

   这些的文件保存在linux系统下的文件系统下.HDFS的客户端所有的操作必须经过NameNode

3.2 DataNode

     提供真实文件的存储服务.

  • 文件块(Block):最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是128MB(可配置),以一个256MB文件,共有256/128=2个Block.block 本质上是一个逻辑概念,意味着block 里面不会真正的存储数据,只是划分文件的.不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间.

       在每台主机Linux文件系统中都能找到:

      

  • 副本(replication):多副本,默认是三个.可配置:hdfs-site.xml中dfs.replication的属性.机柜意识:

通常,大型 HDFS 集群跨多个安装点(机柜)排列。一个安装中的不同节点之间的网络流量通常比跨安装点的网络流量更高效。一个 Name node 尽量将一个块的多个副本放置到多个安装上以提高容错能力。但是,HDFS 允许管理员决定一个节点属于哪个安装点。因此,每个节点都知道它的机柜 ID,也就是说,它具有机柜意识。

3.3 NameNode元数据的存储信息

     见下图:就不做解释啦.

3.4 NameNode和DataNode之间的通信机制

Data node 持续循环,询问 Name node 的指令。 Name node 不能直接连接到 Data node ,它只是从 Data node 调用的函数返回值。每个 Data node 都维护一个开放的服务器套接字,以便客户端代码或其他 Data node 能够读写数据。 Name node 知道这个服务器的主机或端口,将信息提供给有关客户端或其他 Data node 。所有 HDFS 通信协议都构建于 TCP/IP 协议之上。HDFS 客户端连接到 Name node 上打开的一个 Transmission Control Protocol (TCP) 端口,然后使用一个基于 Remote Procedure Call (RPC) 的专有协议与 Name node 通信。 Data node 使用一个基于块的专有协议与 Name node 通信。Hadoop整个生态系统都是基于RPC协议之上的。关于RPC的通信原理将例外写一篇博客.链接。。。

3.5 HDFS非纯HA的一个解决方案Secondary Name node

实际上,为了提高整个集群的可靠性和可维护性,各大公司和社区都提出来很多改进HDFS的方案,在这里,我就暂时介绍HDFS其中的一种,以后博客会详细描述HDFS HA的解决方案,并且进行总结.

Secondary NameNode通过定期下载NameNode的元数据和日志文件,并进行合并更新,来对NameNode进行备份。当NameNode故障时,可以通过Secondary NameNode进行恢复,但是不足之处在于Secondary NameNode的备份知识NameNode的Checkpoint,并没有与NameNode实时同步,恢复后的数据存在一定的元信息丢失,由于在恢复过程中存在一段系统不可用的时间,该方案只能是一种备份方案,并不是真正意义上的HA方案.该流程图如下:

  NameNode的执行:

Namenode始终在内存中保存metedata,用于处理“读请求”.
等到有“写请求”到来时,namenode会首先写editlog到磁盘,即向edits文件中写日志,成功返回后,才会修改内存,并且向客户端返回。
Hadoop会维护一个fsimage文件,也就是namenode中metedata的镜像,但是fsimage不会随时与namenode内存中的metedata保持一致,而是每隔一段时间通过合并edits文件来更新内容。有谁来合并呢??---->Secondary namenode就是用来合并fsimage和edits文件来更新NameNode的metedata的。

   Secondary namendoe的工作流程:

1.secondary通知namenode切换edits文件(这时NameNode会生成newedits文件)
2.secondary从namenode获得fsimage和edits(通过http)
3.secondary将fsimage载入内存,然后开始合并(以一定的算法)edits
4.secondary将新的fsimage发回给namenode
5.namenode用新的fsimage替换旧的fsimage

4.HDFS中Java应用程序接口访问

直接上代码:

HadoopUtil.java
package com.codewatching.hadoop.service;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
/**
 * Hadoop简单工具类
 * @author LISAI
 */
public class HadoopUtil {
	public static FileSystem getFileSystem(){
		try {
			Configuration conf = new Configuration();
			URI uri = new URI("hdfs://yun10-0:9000/");
			FileSystem fileSystem = FileSystem.get(uri, conf, "lisai");
			return fileSystem;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

HadoopBasicAPIService.java
package com.codewatching.hadoop.service;
import java.io.FileOutputStream;
import java.io.OutputStream;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
/**
 * Hadoop API的操作
 * @author LISAI
 */
public class HadoopBasicAPIService {
	private FileSystem fileSystem = HadoopUtil.getFileSystem();
	/**
	 * 传统方式---下载
	 */
	@Deprecated
	public void downLoadTraditional(String uri,String dest) throws Exception{
		FSDataInputStream dataInputStream = fileSystem.open(new Path(uri));
		OutputStream outputStream = new FileOutputStream(dest);
		IOUtils.copyBytes(dataInputStream, outputStream, fileSystem.getConf());
	}
	/**
	 * 常用方式---下载(windows环境下注意事项)
	 */
	public void downLoadSimple(String src,String dest) throws Exception{
		fileSystem.copyToLocalFile(new Path(src), new Path(dest));
	}
	/**
	 * 上传 
	 * @param src
	 * @param dest
	 * @throws Exception
	 */
	public void upload(String src,String dest) throws Exception{
		fileSystem.copyFromLocalFile(new Path(src),new Path(dest));
	}
	/**
	 * 创建文件夹
	 * @param makeDir
	 * @throws Exception
	 */
	public void mkdir(String makeDir) throws Exception{
		fileSystem.mkdirs(new Path(makeDir));
	}
	/**
	 * 删除文件夹
	 */
	public void deldir(String delDir) throws Exception{
		fileSystem.delete(new Path(delDir),true);
	}
}

5.HDFS中'读'文件源码分析

1.初始化FileSystem,然后客户端(client)用FileSystem的open()函数打开文件
2.FileSystem用RPC调用元数据节点,得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。
3.FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。
4.DFSInputStream连接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端(client)
5.当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
6.当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
7.在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
8.失败的数据节点将被记录,以后不再连接。


  

 

以下几步,就是如何获取创建和代理对象的过程..只有拿到客户端的代理对象,我们才能对HDFS进行相关操作。RPC过程的原理,以后的博客会有大幅边幅谈论.


dfs===========DFSClient[clientName=DFSClient_NONMAPREDUCE_1386880610_1, ugi=lisai (auth:SIMPLE)]

fs===========DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_1386880610_1, ugi=lisai (auth:SIMPLE)]]

初始化完毕。。。。。。


中间省略几个方法调用..........

这下就拿到了FSDataInputStream流到客户端。接下来的步骤就是COPY的事啦。。。

参考文章:http://www.ibm.com/developerworks/cn/web/wa-introhdfs/

              http://www.ibm.com/developerworks/cn/linux/1406_jiangtao_camphadoop/

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 49
博文 56
码字总数 138491
评论 (6)
敲代码猥琐男
我觉得,还可以在理理,hadoop能讲的东西太多啦,写个系列就更好啦
查封炉台

引用来自“四少”的评论

我觉得,还可以在理理,hadoop能讲的东西太多啦,写个系列就更好啦
恩,确实.刚开始学习Hadoop.一边学习,一边总结吧.
寻梦2012
不错
facesea
希望保持住13
lgscofield
块默认64m
查封炉台

引用来自“lgscofield”的评论

块默认64m

Hadoop版本的不同,块默认大小也是不同!在hadoop2.x里是128M.hadoop1.x里是64M.
×
查封炉台
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: