随着信息技术的高度发展,数据量越来越多,当一个操作系统管辖范围存储不下时,只能将数据分配到更多的磁盘中存储,但是数据分散在多台磁盘上非常不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,因此诞生了分布式文件系统。HDFS(Hadoop Distribute File System)是一种能运行在通用硬件上的分布式文件系统,具有高度容错的特点,适合部署在廉价的机器上。

由于hadoop1和hadoop2版本差异较大,本文以下部分如未标记特殊说明则默认指的是hadoop2版本

HDFS基本概念

1、数据块(block)

   与普通文件系统类似,HDFS也有数据块的概念,默认数据块block大小为64M。不同于普通文件系统的是,在HDFS中,如果一个文件小于数据块的大小,并不占用整个数据块存储空间。

2、元数据节点(namenode)和数据节点(datanode)

   hadoop1版本中只存在一个namnode节点,存在单点故障风险,在hadoop2版本中引入了HDFS联盟的概念,即包含多个HDFS系统,同时也包含多个namenode节点。

   namenode节点的作用:① 接收用户操作请求;② 维护文件系统的目录结构;③ 管理文件与block的关系(哪些block属于哪些文件),block与datanode之间的关系。

   datanode数据节点的作用:①存储文件数据;②存储文件数据block副本(默认存储3份)。

3、HDFS特点

   HDFS允许文件通过网络在多台主机上分享,并让多机器上的多用户分享文件和存储空间,其具有下述两个特性:① 通透性,让实际上是通过网络来访问文件的动作,由程序与用户看来,就像是访问本地的磁盘一般; ② 容错性,即使系统中有某些节点脱机,整体来说系统仍然可以持续运作而不会有数据丢失。

   当HDFS数据块小于一个block大小时,并不占用整个block大小,也即是说文件大小=实际占用空间。这一点与Windows操作系统的文件簇不一样,在Windows操作系统中,一个小于簇大小的文件实际占用空间也是一个簇。HDFS不支持并发写的情况,且不适合小文件。

NameNode元数据解析

1、namenode元数据结构

   在hadoop-2.6.0中,NameNode元数据存储在${hadoop.tmp.dir}/dfs/name/current路径中。可通过dfs.namenode.name.dir配置结构,强烈建议配置多个备份路径,配置格式如:/name1/dfs/name,/name2/dfs/name,/name3/dfs/name等,特别推荐配置一个网络文件系统NFS,最大限度地保证元数据的完整性。hadoop-2.6.0的路径${hadoop.tmp.dir}/dfs/name下,有锁文件in_use.lock和文件夹current,文件夹current下存在以下文件:① VRSION属性文件;② seen_txid文件;③ 大量edits文件;④ 少量fsimage文件。

   其中seen_txid是存放transactionId的一个重要文件,format之后是0,它代表的是namenode里面的edits_*文件的尾数,namenode重启的时候,会按照seen_txid的数字,循序从头跑edits_0000001~到seen_txid的数字。所以当hdfs发生异常重启的时候,一定要比对seen_txid内的数字是不是你edits最后的尾数,否则很可能丢失数据。VERSION文件是Java属性文件,其文件内容和说明如下所示:

#Thu Mar 19 19:52:29 PDT 2015
namespaceID=605992118 #namespaceID是文件系统的唯一标识符,在文件系统首次格式化之后生成的
clusterID=CID-fd97cef9-ffad-48ac-b15b-e715501d73f4 #clusterID是系统生成或手动指定的集群ID,在-clusterid选项中可以使用它
cTime=0 #cTime表示NameNode存储时间的创建时间,由于我的NameNode没有更新过,所以这里的记录值为0,以后对NameNode升级之后,cTime将会记录更新时间戳
storageType=NAME_NODE #storageType说明这个文件存储的是什么进程的数据结构信息(如果是DataNode,storageType=DATA_NODE)
blockpoolID=BP-1535557182-192.168.137.101-1426745680483 #blockpoolID是针对每一个Namespace所对应的blockpool的ID,上面的这个BP-893790215-192.168.24.72-1383809616115就是在我的ns1的namespace下的存储块池的ID,这个ID包括了其对应的NameNode节点的ip地址
layoutVersion=-60 #layoutVersion表示HDFS永久性数据结构的版本信息, 只要数据结构变更,版本号也要递减,此时的HDFS也需要升级,否则磁盘仍旧是使用旧版本的数据结构,这会导致新版本的NameNode无法使用

   在current目录中,我们可以看到大量的edits文件和少量的fsimage文件,他们都是非常重要的元数据文件。fsimage文件是Hadoop文件系统元数据的一个永久性的检查点,保存了整个系统的命名空间、文件块的映射表和文件系统的配置。fsimage包含了所有的HDFS目录和文件idnode的序列化信息,对于文件来说,包含的信息有修改时间、访问时间、块大小和组成一个文件块信息等;而对于目录来说,包含的信息主要有修改时间、访问控制权限等信息。edits文件存放的是Hadoop文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。

   fsimage和edits文件内存储的都是经过序列化的二进制数据,在NameNode启动的时候,进程会将fsimage文件中的内容加载到内存中,然后逐条执行edits文件中的记录,执行完成后,清空edits文件内容。之后客户端所有发起的文件更新操作都会同时记录在内存中的fsimage和磁盘上的edits文件中,也就是说,在任何时候,内存中的fsimage内容=磁盘中的fsimage文件内容+磁盘中的edits文件内容。那么为什么hdfs文件的修改不直接记录在磁盘的fsimage中呢?这是因为随着hdfs文件数目的增多,fsimage文件内容会变得非常巨大,假如每次更新操作都在fsimage中执行,那么执行效率是非常低下的。

2、fsimage和edits文件的合并(hadoop1)

   面对不断增大的edits文件,如果不及时进行处理,那么每次在NameNode启动时会花费大量的时间来合并处理edits文件,导致HDFS集群启动非常慢。为了解决此问题,必须要有一个任务来不断地合并edits和fsimage文件,在hadoop1版本中,是由SecondaryNameNode节点来完成此工作的,而hadoop2是由HA的standby节点上的CheckpointerThread进程来执行的。

   hadoop1中的SecondaryNameNode进程的功能是及时保存NameNode节点元数据信息,并定期将edits和fsimage文件进行合并,从而减少edits文件大小,缩短NameNode下次启动需要消耗的时间。出于性能和数据完整性考虑,通常将SecondaryNameNode配置在与NameNode不同的一台机子上,其合并工作流程如下图所示。

SecondaryNameNode工作流程图

   1) SecondaryNamenode会定期的和NameNode通信,请求其停止使用edits文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;

   这里的“定期”是由配置fs.checkpoint.period(还原点周期检查更新周期,默认3600s)和fs.checkpoint.size(edits文件允许的最大大小,默认64M)来决定的,当还原点周期时间到或者edits文件达到配置的最大大小时,SecondaryNameNode就会执行更新请求和操作。

   2) SecondaryNamenode通过HTTP GET方式从NameNode上获取到fsimage和edits文件,并下载到本地的相应目录下(由fs.checkpoint.dir和fs.checkpoint.edits.dir决定);

   3) SecondaryNamenode将下载下来的fsimage载入到内存,然后一条一条地执行edits文件中的各项更新操作,使得内存中的fsimage保存最新,这个过程就是edits和fsimage文件合并;

   4) SecondaryNamenode执行完合并操作之后,会通过post方式将新的fsimage文件发送到NameNode节点上;

   5) NameNode将从SecondaryNamenode接收到的新的fsimage替换旧的fsimage文件,同时将edit.new替换edits文件,一次合并工作完成。

3、fsimage和edits文件的合并(hadoop2)

   在hadoop2版本中,SecondaryNameNod只存在伪分布模式下,集群模式已经取消了SecondaryNameNode角色。那么集群模式hadoop2的元数据合并工作是由谁完成的呢?

   首先,在hadoop2中引入了NameNode HA的概念,每个HDFS集群中存在多个NameNode(目前版本是2个,以后版本相信会根据需要增加)。任何时候,只有一个NameNode进程是处于active状态的,另一个NameNode进程处于standby状态,而他们之间的元数据是通过奇数个JournalNode节点进行共享的。在standby节点上会运行一个叫做CheckpointerThread的线程,这个线程调用StandbyCheckpointer类的doWork()函数,而doWork函数会每隔一段时间就进行合并工作,相关代码如下:

 try {
Thread.sleep(1000 * checkpointConf.getCheckPeriod());
} catch (InterruptedException ie) {
} public long getCheckPeriod() {
return Math.min(checkpointCheckPeriod, checkpointPeriod);
} checkpointCheckPeriod = conf.getLong(
DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_KEY,
DFS_NAMENODE_CHECKPOINT_CHECK_PERIOD_DEFAULT); checkpointPeriod = conf.getLong(DFS_NAMENODE_CHECKPOINT_PERIOD_KEY,
DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT);

   其中的checkpointCheckPeriod和checkpointPeriod变量是通过获取hdfs-site.xml中的dfs.namenode.checkpoint.period和dfs.namenode.checkpoint.check.period两个属性得到的。执行一次checkpoint的条件如下:

 boolean needCheckpoint = false;
if (uncheckpointed >= checkpointConf.getTxnCount()) {
LOG.info("Triggering checkpoint because there have been " +
uncheckpointed + " txns since the last checkpoint, which " +
"exceeds the configured threshold " +
checkpointConf.getTxnCount());
needCheckpoint = true;
} else if (secsSinceLast >= checkpointConf.getPeriod()) {
LOG.info("Triggering checkpoint because it has been " +
secsSinceLast + " seconds since the last checkpoint, which " +
"exceeds the configured interval " + checkpointConf.getPeriod());
needCheckpoint = true;
}

   当上述needCheckpoint被设置成true的时候,StandbyCheckpointer类的doWork()函数将会调用doCheckpoint()函数正式处理checkpoint。当fsimage和edits的合并完成之后,它将会把合并后的fsimage上传到Active NameNode节点上,Active NameNode节点下载完合并后的fsimage,再将本节点上旧的fsimage删掉,同时清除旧的edits文件。

   合并步骤大概如下:

   1) 配置好HA后,客户端所有的更新操作将会写到JournalNodes节点的共享目录中(通过dfs.namenode.shared.edits.dir和dfs.journalnode.edits.dir配置);

   2) Active Namenode和Standby NameNode从JournalNodes的edits共享目录中同步edits到自己edits目录中;

   3) Standby NameNode中的StandbyCheckpointer类会定期的检查合并的条件是否成立,如果成立会合并fsimage和edits文件,然后将合并之后的fsimage上传到Active NameNode相应目录中;

   4) Active NameNode接到最新的fsimage文件之后,将旧的fsimage和edits文件清理掉,一个数据合并工作完成。

HDFS操作命令

   HDFS操作基本格式:“hadoop fs -命令”或“hdfs dfs -命令”,其中hdfs dfs是hadoop2版本推出的命令,此处只列举了一些常用命令,详细介绍及操作命令见《HDFS操作手册》。

1、查看文件,关键字ls

   hadoop fs -ls /   --查看HDFS根目录下的文件

   hadoop fs -ls hdfs://hadoop:9000/  --hadoop fs -ls /的完整版写法,这里符号 / 为HDFS文件路径,默认表示hdfs://hadoop:9000/,是因为core-site.xml中配置了fs.default.name的值为hdfs://hadoop:9000/

   hadoop fs -ls -R / --递归显示根目录下所有文件

   hadoop fs -ls -h /   --显示根目录下的文件,文件大小自动转化成合适的单位(M、K等)

  显示的文件信息格式如下所示:

drwx------  -  root supergroup   0  2014-07-23 03:48  /usr/local/hadoop/tmp/mapred/system
-rw------- 1 root supergroup 4 2014-07-23 03:48 /usr/local/hadoop/tmp  

  格式说明:① 第一列:drwx------,与linux的文件说明一致;② 第二列:目录为-,文件为数字,表示文件的副本数;③ 第三列:root,表示文件的创建者;④ 第四列:supergroup,表示文件所在组;⑤ 第五列:0,表示文件大小(单位byte),目录大小为0;⑥ 第六列:2014-07-23 03:48,表示最后修改时间;⑦ 第七列:/usr/local/hadoop/tmp/mapred/system,表示文件路径。

2、创建文件夹,关键字mkdir

   hadoop fs -mkdir /hans   --在根目录下创建文件夹hans

   hadoop fs -mkdir hans   --在当前用户路径(/user/用户名)下创建文件夹hans,使用root登录时,创建文件目录为/user/root/hans

在HDFS操作中,若文件夹或文件路径不带/,则默认表示为用户路径,即/user/用户名/...

3、上传文件,关键字put

   格式:hadoop fs -put <linux source> <hdfs destination>

   hadoop fs -put /root/install.log /hans   --将本地文件/root/install.log上传到HDFS的目录/hans中,若/hans文件夹不存在,则默认表示将install.log文件重命名为hans,非文件夹

注:①同名文件不允许上传;②若保存的HDFS文件夹不存在,则表示将上传的文件重命名为文件夹名;③当目的路径不带/时,默认表示用户路径/user/当前用户

4、下载文件,关键字get

   格式:hadoop fs -get <hdfs source> <linux destination>

   hadoop fs -get /hans/install.log    --将HDFS文件/hans/install.log下载到linux当前目录下

5、在线查看文件,关键字text、cat或tail

   hadoop fs -text /hans/install.log   --在线查看文件/hans/install.log

   hadoop fs -cat /hans/install.log   --在线查看文件/hans/install.log

   hadoop fs -tail /hans/install.log   --在线查看文件的最后1000个字节

6、删除文件,关键字rm

   hadoop fs -rm /hans/install.log   --删除HDFS文件/hans/install.log

   hadoop fs -rm -r /hans   --递归删除HDFS文件夹/hans及/hans下的所有文件

   hadoop fs -rm -r hdfs://hadoop:9000/*   --递归删除HDFS根目录下所有文件,其中hadoop为主机名

7、查看帮助文档,关键字help

   hadoop fs -help   --查看hadoop fs所有帮助命令

   hadoop fs -help ls   --查看ls的命令帮助

8、合并MR输出文件,关键字getmerge

   格式:hadoop dfs -getmerge <hdfs souce> <linux destination>

   hadoop dfs -getmerge /out /root/Download/output   --将mapreduce的输出HDFS文件/out合并并复制到本地文件系统/root/Download/output中

HDFS运行配置

1、默认配置文件路径

   hdfs-default.xml:hadoop-2.6.0-src\hadoop-hdfs-project\hadoop-hdfs\src\main\resources\

2、常用配置(hadoop2.6.0)

   ▶ dfs.namenode.name.dir(hadoop1对应配置是:dfs.name.dir),配置NameNode元数据的存储路径,可通过“,”间隔配置多个路径,如:/name1/dfs/name,/name2/dfs/name,/name3/dfs/name。此外,为确保元数据不丢失,建议配置一个NFS路径。

   ▶ fs.trash.interval,配置HDFS回收站功能,值为回收站自动清空的时间(分钟)。当用户通过HDFS命令删除数据后,首先会移动到Trash回收站中,默认路径:/user/{用户}/.Trash;

通过Java操作HDFS

   在Java中操作HDFS都是通过org.apache.hadoop.fs.FileSystem类来实现的,修改HDFS服务端文件是否需要关闭权限验证,即在hdfs-site.xml中配置dfs.permissions.enabled(hadoop1对应为:dfs.permissions)为false。

   示例代码如下(完整代码点此下载):

 package com.hicoor.hadoop.hdfs;

 import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Before;
import org.junit.Test; public class HDFSDemo { FileSystem fileSystem = null; @Before
public void init() throws IOException, URISyntaxException {
fileSystem = FileSystem.get(new URI("hdfs://hadoop0:9000/"),new Configuration());
System.setProperty("hadoop.home.dir", "D:/hadoop-2.6.0");
} @Test
public void uploadFile() throws IOException,
FileNotFoundException {
FSDataOutputStream out = fileSystem.create(new Path("/hadoop2.6(x64)V0.2.zip"));
FileInputStream in = new FileInputStream("D:\\desktop\\hadoop2.6(x64)V0.2.zip");
IOUtils.copyBytes(in, out, 4096, true);
} @Test
public void downloadFile() throws IOException,
FileNotFoundException {
FSDataInputStream in = fileSystem.open(new Path("/jdk7"));
OutputStream out = new FileOutputStream("D:\\desktop\\jdk1.7");
IOUtils.copyBytes(in, out, 4096, true);
} @Test
public void deleteFile() throws IllegalArgumentException, IOException {
fileSystem.delete(new Path("/cata"), true);
} @Test
public void makeDir() throws IllegalArgumentException, IOException {
fileSystem.mkdirs(new Path("/cata"));
} }

   更多资料等待进一步研究....

Hadoop学习(2)-- HDFS的更多相关文章

  1. hadoop学习(五)----HDFS的java操作

    前面我们基本学习了HDFS的原理,hadoop环境的搭建,下面开始正式的实践,语言以java为主.这一节来看一下HDFS的java操作. 1 环境准备 上一篇说了windows下搭建hadoop环境, ...

  2. Hadoop学习笔记-HDFS命令

    进入 $HADOOP/bin 一.文件操作 文件操作 类似于正常的linux操作前面加上“hdfs dfs -” 前缀也可以写成hadoop而不用hdfs,但终端中显示 Use of this scr ...

  3. Hadoop学习笔记---HDFS

    Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统.HDFS是一个高度容错性的系统,适合部署在廉价的机器上.HDFS能提供高吞吐 ...

  4. Hadoop学习笔记—HDFS

    目录 搭建安装 三个核心组件 安装 配置环境变量 配置各上述三组件守护进程的相关属性 启停 监控和性能 Hadoop Rack Awareness yarn的NodeManagers监控 命令 hdf ...

  5. hadoop学习(二)----HDFS简介及原理

    前面简单介绍了hadoop生态圈,大致了解hadoop是什么.能做什么.带着这些目的我们深入的去学习他.今天一起看一下hadoop的基石--文件存储.因为hadoop是运行与集群之上,处于分布式环境之 ...

  6. 【Hadoop学习】HDFS中的集中化缓存管理

    Hadoop版本:2.6.0 本文系从官方文档翻译而来,转载请尊重译者的工作,注明以下链接: http://www.cnblogs.com/zhangningbo/p/4146398.html 概述 ...

  7. 【Hadoop学习】HDFS 短路本地读

    Hadoop版本:2.6.0 本文系从官方文档翻译而来,转载请尊重译者的工作,注明以下链接: http://www.cnblogs.com/zhangningbo/p/4146296.html 背景 ...

  8. hadoop学习之hdfs文件系统

    一.hdfs的概念 Hadoop 实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS. Hadoop是Apache Lucene创始人Doug Cu ...

  9. Hadoop 学习之——HDFS

    HDFS是HADOOP中的核心技术之一——分布式文件存储系统.Hadoop的作者Doug Cutting 和Mike 是根据Google发布关于GFS 的研究报告所设计出的分布式文件存储系统. 一.H ...

  10. hadoop学习记录--hdfs文件上传过程源码解析

    本节并不大算为大家讲接什么是hadoop,或者hadoop的基础知识因为这些知识在网上有很多详细的介绍,在这里想说的是关于hdfs的相关内容.或许大家都知道hdfs是hadoop底层存储模块,专门用于 ...

随机推荐

  1. json解析json字符串时候,数组必须对应jsonObjectArray,不能对应JsonObject。否则会解析错误。

    json第三方解析json字符串时候,json数组必须对应jsonObjectArray,不能对应JsonObject.->只要是[]开头的都是json数组字符串,就要用jsonArray解析 ...

  2. Rails--render partial时传递参数

    1. example如下: <%=render :partial => "networks/primary_agent", :locals => {:id =&g ...

  3. Latex公式换行、对齐

    http://blog.sina.com.cn/s/blog_64827e4c0100vnqu.html 换行后等式对齐 \begin{equation}\begin{aligned}R(S_2)&a ...

  4. windows系统中ubuntu虚拟机安装及web项目到服务上(三)

    项目在ubuntu虚拟机下的部署 一:将war从本地通过Xftp 4 传到虚拟机tomcat目录下的webapps目录下 2:修改tomcat下的server.xml  <Host name=& ...

  5. 深入了解Windows句柄到底是什么

    深入了解Windows句柄到底是什么 http://blog.csdn.net/wenzhou1219/article/details/17659485 总是有新入门的Windows程序员问我Wind ...

  6. CSS的display属性,显示或隐藏元素

    <html> <head> <script type="text/javascript"> function removeElement() { ...

  7. GCD的简单介绍

    一)GCD 的使用方式 dispatch_async(dispatch_queue_t queue, dispatch_block_t block); async表明运行方式 queue则是你把任务交 ...

  8. QTextCodec::makeDecoder函数,plugins需要是动态链接库

    QT中的QString内容使用Unicode作为文本编码.但是实际系统中通常采用的是其他编码,例如GBK,utf8等.为了便于兼容这些格式,QT中还设置了两个字符串类型: QCString类: C类型 ...

  9. Let's Encrypt这个免费的证书签发服务

    使用的是Let's Encrypt这个免费的证书签发服务,按照这里的教程一步步照着来,很快就完成了. 迁移过程总体来说比较顺利,只是遇到了两个不大不小的坑.一个是域名的跳转问题,迁移完成以后对于所有h ...

  10. 阅读javaScript 的原型笔记

    下面我们先看一个例子已经一张图. function Foo() { } Object.prototype.name = 'My Object'; Foo.prototype.name = 'Bar'; ...