我是靠谱客的博主 冷艳大树,最近开发中收集的这篇文章主要介绍HDFS--分布式存储系统,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 

1、定义就是: 分布式文件系统是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户分享文件和存储空间。

分布式文件管理系统很多,HDFS 只是其中一种。适用于一次写入、多次查询的情况,不支持并发写情况,小文件不合适。

 

2、hadoop常用shell命令选项。(前期重点掌握 ls(r)、rm(r)、mkdir、put、get)

Ctrl+R选择命令(kill-9)

-ls -ls <路径> 查看指定路径的当前目录结构

-lsr -lsr <路径> 递归查看指定路径的目录结构

-du -du <路径> 统计目录下个文件大小

-dus -dus <路径> 汇总统计目录下文件(夹)大小

-count -count [-q] <路径> 统计文件(夹)数量

-mv -mv <源路径> <目的路径> 移动

-cp -cp <源路径> <目的路径> 复制

-rm -rm [-skipTrash] <路径> 删除文件/空白文件夹

-rmr -rmr [-skipTrash] <路径> 递归删除

-put -put <多个 linux 上的文件> <hdfs 路径> 上传文件

-copyFromLocal -copyFromLocal <多个 linux 上的文件> <hdfs 路径>  从本地复制

-moveFromLocal -moveFromLocal <多个 linux 上的文件> <hdfs 路径>  从本地移动

-getmerge -getmerge <源路径> <linux 路径> 合并到本地

-cat -cat <hdfs 路径> 查看文件内容

-text -text <hdfs 路径> 查看文件内容

-copyToLocal -copyToLocal [-ignoreCrc][-crc] [hdfs 源路径] [linux 目的路径]  从本地复制

-moveToLocal -moveToLocal [-crc]<hdfs 源路径> <linux目的路径>   从本地移动

-mkdir -mkdir <hdfs 路径> 创建空白文件夹

-setrep -setrep [-R] [-w] <副本数> <路径> 修改副本数量

-touchz -touchz <文件路径> 创建空白文件  > 也可以

-stat -stat [format] <路径> 显示文件统计信息

-tail -tail [-f] <文件> 查看文件尾部信息

-chmod -chmod [-R] <权限模式> [路径] 修改权限

-chown -chown [-R] [属主][:[属组]] 路径 修改属主

-chgrp -chgrp [-R] 属组名称 路径 修改属组

-help -help [命令选项] 帮助

 

3、HDFS体系结构与基本概念

一句话解释:把客户端的大文件存放在很多节点数据块

HDFS的datanode在存储数据时,如果原始文件大小>64MB,按照64MB大小切分;如果<64MB,只有一个block,占用磁盘空间是源文件实际大小。(dfs.block.size)可以在core-site.xml中覆盖。

 

NameNode

NameNode 的作用是管理文件目录结构,是管理数据节点的。名字节点维护两套数据,一套是文件目录与数据块之间的关系, 另一套是数据块与节点之间的关系。前一套数据是静态的,是存放在磁盘上的,通过 fsimage 和 edits 文件来维护;后一套数据是动态的,不持久化到磁盘的,每当集群启动的时候,会自动建立这些信息。

 

配置参见:core-default.xml

 

 

DateNode

DataNode 的作用 是 HDFS 中真正存储数据的。

Block 源码类:org.apache.hadoop.hdfs.protocol.Block 类

block存放的位置:参数dfs.data.dir 的值就是 block 存放在linux 文件系统中的位置。变量 hadoop.tmp.dir的值前面已经介绍了,是/usr/local/hadoop/tmp,那么 dfs.data.dir的完整路径是/usr/local/hadoop/tmp/dfs/data。

 

注意:我们从 linux 磁盘上传一个完整的文件到 hdfs 中,这个文件在linux 是可以看到的,但是上传到 hdfs 后,就不会有一个对应的文件存在,而是被划分成很多的 block 存在的。

 

SecondaryNameNode

SNN 只有一个职责,就是合并 NameNode 中的 edits 到fsimage 中。

  • 执行过程:从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,同时重置NameNode的edits.
  • 默认在安装在NameNode节点上,但这样...不安全!

secondary namenode的工作流程

    1. secondary通知namenode切换editlog
    2. secondary从namenode获得fsimage和editlog(通过http)
    3. secondary将fsimage载入内存,然后开始合并editlog
    4. secondary将新的fsimage发回给namenode
    5. namenode用新的fsimage替换旧的fsimage

4、HDFS的web接口

  • 50070端口,查看NameNode状态
  • 50075端口,查看DataNode的
  • 50090端口,查看SecondaryNameNode的
  •  50030端口,查看JobTracker状态的
  • 50060端口,查看TaskTracker

 

5、搭建Hadoop开发环境

1)通过在本地的 eclipse 中的 java 代码访问远程 linux 中的 hdfs。

要使用宿主机中的 java 代码访问客户机中的 hdfs,需要保证以下几点:

l 确保宿主机与客户机的网络是互通的

l 确保宿主机和客户机的防火墙都关闭,因为很多端口需要通过,为了减少防火墙配置,直接关闭

l 确保宿主机与客户机使用的 jdk 版本一致。如果客户机使用 jdk6,宿主机使用 jdk7,那么代码运行时会报不支持的版本的错误

l 宿主机的登录用户名必须与客户机的用户名一直。比如我们 linux 使用的是 root 用户,那么 windows 也要使用 root 用户,否则会报权限异常

l 在 eclipse 项目中覆盖 hadoop 的 org.apache.hadoop.fs.FileUtil 类的 checkReturnValue 方法,如图 4-661,目的是为了避免权限错误

 

 

2)使用FileSystem api读写数据

在 hadoop 的 HDFS 操作中,有个非常重要的 api,是 org.apache.hadoop.fs.FileSystem,这是我们用户代码操作 HDFS 的直接入口,该类含有操作 HDFS 的各种方法,类似于 jdbc 中操作数据库的直接入口是 Connection 类。

2.1)那我们怎么获得一个 FileSystem 对象哪?

String uri = "hdfs://192.168.1.240:9000/";

Configuration conf = new Configuration();

FileSystem fs = FileSystem.get(URI.create(uri), configuration);

-------------------------------------------------------------------------------------------------------------------------------

以上代码中,要注意调用的是 FileSystem 的静态方法 get,传递两个值给形式参数,第一个访问的 HDFS 地址,该地址的协议是 hdfs,ip 是 192.168.1.240,端口是 9000.。这个地址的完整信息是在配置文件 core-site.xml 中指定的,读者可以使用自己环境的配置文件中的设置。第二个参数是一个配置对象。

2.2)我们在 HDFS 的根目录下创建文件夹,代码如下

final String pathString = "/d1";

boolean exists = fs.exists(new Path(pathString));

if(!exists){

boolean result = fs.mkdirs(new Path(pathString));

System.out.println(result);

}

以上代码中,决定创建的文件夹完整路径是“/d1” 。第二行代码是使用方法 exitst判断文件夹是否存在;如果不存在,执行创建操作。创建文件夹,调用的是 mkdirs 方法,返回值是布尔值,如果是 true,表示创建成功;如果是 false,表示创建失败。

2.3)

写文件,我向 HDFS 写入文件,代码如下:

final String pathString = "/d1/f1";

final FSDataOutputStream fsDataOutputStream = fs.create(new Path(pathString));

IOUtils.copyBytes(new ByteArrayInputStream("my name is yl".getBytes()),

fsDataOutputStream, configuration, true);

第一行代码表示创建的文件是在刚才创建的 d1 文件夹下的文件 f1;

第二行是调用 create 方法创建一个通向 HDFS 的输出流;

第三行是通过调用 hadoop 的一个工具类 IOUtils 的静态方法 copyBytes 把一个字符串发

送给输出流中。该静态方法有四个参数,第一个参数输入流,第二个参数是输出流,第三个参数是配置对象,第四个参数是布尔值,如果是 true 表示数据传输完毕后关闭流。

2.4)读文件,现在把刚才写入到 HDFS 的文件“/d1/f1”读出来,代码如下:

final String pathString = "/d1/f1";

final FSDataInputStream fsDataInputStream = fs.open(new Path(pathString));

IOUtils.copyBytes(fsDataInputStream, System.out, configuration, true);

第二行表示调用方法 open 打开一个指定的文件,返回值是一个通向该文件的输入流;

第三行还是调用 IOUtils.copyBytes 方法,输出的目的地是控制台。

2.5)查看目录列表和文件详细信息,可以把根目录下的所有文件和目录显示出来,代码如下

final String pathString = "/";

final FileStatus[] listStatus = fs.listStatus(new Path(pathString));

for (FileStatus fileStatus : listStatus) {

final String type = fileStatus.isDir()?"目录":"文件";

final short replication = fileStatus.getReplication();

final String permission = fileStatus.getPermission().toString();

final long len = fileStatus.getLen();

final Path path = fileStatus.getPath();

System.out.println(type+"t"+permission+"t"+replication+"t"+len+"t"+path);

}

调用listStatus方法会得到一个指定路径下的所有文件和文件夹,每一个用FileStatus表示。使用for循环显示每一个FileStatus对象。FileStatus对象表示文件的详细信息,里面含有类型、副本数、权限、长度、路径等很多信息,我们只是显示了一部分。

2.6)删除文件或目录,可以删除某个文件或者路径,代码如下

final String pathString = "/d1/f1";

//fs.delete(new Path("/d1"), true);

fs.deleteOnExit(new Path(pathString));

第三行代码表示删除文件“/d1/f1” ,注释掉的第二行代码表示递归删除目录“/d1”及下面的所有内容。

6、RPC(remote procedure call), RPC是hadoop框架运行的基础。

  不同java进程间的对象方法的调用。一方称作服务端(server),一方称作客户端(client)。server端提供对象,供客户端调用的,被调用的对象的方法的执行发生在server端。

   在服务器端:

构造一个 RPC server.

@param instance 实例中的方法会被客户端调用

 @param bindAddress 绑定的这个地址用于监听连接的到来

@param port 绑定的这个端口用于监听连接的到来

@param conf the configuration to use

 

Server server = RPC.getServer( new MyBiz(), SERVER_ADDRESS, SERVER_PORT, new Configuration());

server.start();

 在客户端:

           /** 构造一个客户端的代理对象。*/

MyBizable proxy = (MyBizable)RPC.waitForProxy(MyBizable.class,

MyBizable.VERSION, new InetSocketAddress(MyServer.SERVER_ADDRESS, MyServer.SERVER_PORT),new Configuration());

String result = proxy.hello("world");

System.out.println("客户端调用结果:"+result);

 

RPC.stopProxy(proxy);

接口需要继承VersionedProtocol,并在其实现类中实现其方法,其返回值为在接口中定义的VERSION

 

读过程:

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

写过程:

  1. 客户端调用create()来创建文件
  2. FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
  3. FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。
  4. DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
  5. DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
  6. 当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。
  7. 如果数据节点在写入的过程中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

最后

以上就是冷艳大树为你收集整理的HDFS--分布式存储系统的全部内容,希望文章能够帮你解决HDFS--分布式存储系统所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部