HDFS课程

HDFS定义

源自于Google的GFS论文
发表于2003年10月
HDFS是GFS的克隆版

Hadoop Distributed File System
易于扩展的分布式文件系统
运行在大量普通廉价机器上,提供容错机制
为大量用户提供性能不错的文件存取服务

HDFS设计目标

非常巨大的分布式文件系统
万个以上的节点,亿份以上文件,10PB的容量以上
1 ZB = 1024 EB
1 EB = 1024 PB
1 PB = 1024 TB
1 TB = 1024 GB
1 GB = 1024 MB

运行于普通硬件上
文件复制多份,避免硬件失败
探测失败和错误恢复

优化批处理
数据暴漏位置,以便计算能够挪到数据附近
提供高聚合的带宽

用户空间可以位于异构的操作系统中

在整个集群中使用单个的命名空间

数据一致性
“写入一次读取多次”的访问模型
客户端只能追加已有的文件

文件被分成各个小块
默认每一块是64MB(实际生产可以调大,一般都是64的整数倍,128是最好的)
每一块复制到不同的DataNode上

智能的客户端
客户端能找到文件块的位置
客户端能直接访问DataNode中的文件位置

程序采用数据就近原则分配节点执行

客户端对文件没有缓存机制(No data caching)

我的H01HDFS

http://192.168.108.101:50070/dfshealth.jsp

我的H01MapReduce

http://192.168.108.101:50030/jobtracker.jsp

HDFS架构——文件

文件切分成块(默认大小64M),以块为单位,每个块有多个副本存储在不同的机器上。副本数可在文件生成时指定(默认3)。

NameNode是主节点,存储文件的元数据:如文件名,文件目录结构,文件属性(生成时间,副本数,文件权限),以及每个文件的块列表、块列表所在的DataNode等等

DataNode在本地文件系统存储文件块数据,以及块数据的校验和。

可以创建、删除、移动或命名文件,当文件创建、写入和关闭之后不能修改文件内容。
这里写图片描述

HDFS架构——NameNode

NameNode是一个中心服务器,单一节点(简化系统的设计与实现),负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。

文件操作,NameNode负责文件元数据的操作,DataNode负责处理文件内容的读写请求,跟文件内容相关的数据流不经过NameNode,只会询问它跟哪个DataNode联系,否则NameNode会成为系统的瓶颈。

副本存放在哪些DataNode上由NameNode来控制。根据全局情况做出块放置决定,读取文件时NameNode尽量让用户先读取最近的副本,降低带宽消耗和读取延时。

NameNode全权管理数据块的复制,它周期性的从集群中的每个DataNode接收心跳信号和块状态报告(Blockreport)。接收心跳信号意味着该DataNode节点工作正常。块状态报告包含了一个该DataNode上所有数据的块列表。

HDFS架构——DataNode

一个数据块在DataNode以文件存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。

DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报告所有的块信息。

心跳是每3秒一下,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器上,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。

集群运行中可以安全加入和退出一些机器。

HDFS架构——NN & SNN

NameNode的两个重要文件
fsimage:元数据镜像文件(保存文件系统的目录树)
edits:元数据操作日志(针对目录树的修改操作)

元数据镜像
内存中保存一份最新的
内存中的镜像=fsimage+edits

定期合并fsimage与edits
Edits文件过大将导致NameNode重启速度慢
SecondaryNameNode负责定期合并它们

这里写图片描述

第一步,SecondaryNameNode通知NameNode切换editlog

第二布,SecondaryNameNode从NameNode获得fsimage和editlog(通过http方式)

第三步,SecondaryNameNode将fsimage载入内存,然后开始合并editlog

第四步,SecondaryNameNode将新的fsimage发回给NameNode

第五步,NameNode用新的fsimage替换旧的fsimage并进行改名

HDFS Shell命令

调用文件系统(FS)Shell命令使用bin/hadoop fs 的形式

所有的FS Shell命令使用URI路径作为参数

URI格式是scheme://authority/path。HDFS的scheme是hdfs;对于本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme。

例如:/parent/child可以表示成
hdfs://namenode:namenodePort/parent/child,或者更简单的/parent/child(假设配置文件是namenode:namenodePort)

大多数的FS Shell命令的行为和对应的Unix Shell命令相似

[hadoop1@H01 ~]$ hadoop fs -help
hadoop fs is the command to execute fs commands. The full syntax is: 

hadoop fs [-fs <local | file system URI>] [-conf <configuration file>]
    [-D <property=value>] [-ls <path>] [-lsr <path>] [-du <path>]
    [-dus <path>] [-mv <src> <dst>] [-cp <src> <dst>] [-rm [-skipTrash] <src>]
    [-rmr [-skipTrash] <src>] [-put <localsrc> ... <dst>] [-copyFromLocal <localsrc> ... <dst>]
    [-moveFromLocal <localsrc> ... <dst>] [-get [-ignoreCrc] [-crc] <src> <localdst>
    [-getmerge <src> <localdst> [addnl]] [-cat <src>]
    [-copyToLocal [-ignoreCrc] [-crc] <src> <localdst>] [-moveToLocal <src> <localdst>]
    [-mkdir <path>] [-report] [-setrep [-R] [-w] <rep> <path/file>]
    [-touchz <path>] [-test -[ezd] <path>] [-stat [format] <path>]
    [-tail [-f] <path>] [-text <path>]
    [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
    [-chown [-R] [OWNER][:[GROUP]] PATH...]
    [-chgrp [-R] GROUP PATH...]
    [-count[-q] <path>]
    [-help [cmd]]

-fs [local | <file system URI>]:    Specify the file system to use.
        If not specified, the current configuration is used, 
        taken from the following, in increasing precedence: 
            core-default.xml inside the hadoop jar file 
            core-site.xml in $HADOOP_CONF_DIR 
        'local' means use the local file system as your DFS. 
        <file system URI> specifies a particular file system to 
        contact. This argument is optional but if used must appear
        appear first on the command line.  Exactly one additional
        argument must be specified. 

-ls <path>:     List the contents that match the specified file pattern. If
        path is not specified, the contents of /user/<currentUser>
        will be listed. Directory entries are of the form 
            dirName (full path) <dir> 
        and file entries are of the form 
            fileName(full path) <r n> size 
        where n is the number of replicas specified for the file 
        and size is the size of the file, in bytes.

-lsr <path>:    Recursively list the contents that match the specified
        file pattern.  Behaves very similarly to hadoop fs -ls,
        except that the data is shown for all the entries in the
        subtree.

-du <path>:     Show the amount of space, in bytes, used by the files that 
        match the specified file pattern.  Equivalent to the unix
        command "du -sb <path>/*" in case of a directory, 
        and to "du -b <path>" in case of a file.
        The output is in the form 
            name(full path) size (in bytes)

-dus <path>:    Show the amount of space, in bytes, used by the files that 
        match the specified file pattern.  Equivalent to the unix
        command "du -sb"  The output is in the form 
            name(full path) size (in bytes)

-mv <src> <dst>:   Move files that match the specified file pattern <src>
        to a destination <dst>.  When moving multiple files, the 
        destination must be a directory. 

-cp <src> <dst>:   Copy files that match the file pattern <src> to a 
        destination.  When copying multiple files, the destination
        must be a directory. 

-rm [-skipTrash] <src>:     Delete all files that match the specified file pattern.
        Equivalent to the Unix command "rm <src>"
        -skipTrash option bypasses trash, if enabled, and immediately
deletes <src>
-rmr [-skipTrash] <src>:    Remove all directories which match the specified file 
        pattern. Equivalent to the Unix command "rm -rf <src>"
        -skipTrash option bypasses trash, if enabled, and immediately
deletes <src>
-put <localsrc> ... <dst>:  Copy files from the local file system 
        into fs. 

-copyFromLocal <localsrc> ... <dst>: Identical to the -put command.

-moveFromLocal <localsrc> ... <dst>: Same as -put, except that the source is
        deleted after it's copied.

-get [-ignoreCrc] [-crc] <src> <localdst>:  Copy files that match the file pattern <src> 
        to the local name.  <src> is kept.  When copying mutiple, 
        files, the destination must be a directory. 

-getmerge <src> <localdst>:  Get all the files in the directories that 
        match the source file pattern and merge and sort them to only
        one file on local fs. <src> is kept.

-cat <src>:     Fetch all files that match the file pattern <src> 
        and display their content on stdout.

-copyToLocal [-ignoreCrc] [-crc] <src> <localdst>:  Identical to the -get command.

-moveToLocal <src> <localdst>:  Not implemented yet 

-mkdir <path>:  Create a directory in specified location. 

-setrep [-R] [-w] <rep> <path/file>:  Set the replication level of a file. 
        The -R flag requests a recursive change of replication level 
        for an entire tree.

-tail [-f] <file>:  Show the last 1KB of the file. 
        The -f option shows apended data as the file grows. 

-touchz <path>: Write a timestamp in yyyy-MM-dd HH:mm:ss format
        in a file at <path>. An error is returned if the file exists with non-zero length

-test -[ezd] <path>: If file { exists, has zero length, is a directory
        then return 0, else return 1.

-text <src>:    Takes a source file and outputs the file in text format.
        The allowed formats are zip and TextRecordInputStream.

-stat [format] <path>: Print statistics about the file/directory at <path>
        in the specified format. Format accepts filesize in blocks (%b), filename (%n),
        block size (%o), replication (%r), modification date (%y, %Y)

-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...
        Changes permissions of a file.
        This works similar to shell's chmod with a few exceptions.

    -R  modifies the files recursively. This is the only option
        currently supported.

    MODE    Mode is same as mode used for chmod shell command.
        Only letters recognized are 'rwxX'. E.g. a+r,g-w,+rwx,o=r

    OCTALMODE Mode specifed in 3 digits. Unlike shell command,
        this requires all three digits.
        E.g. 754 is same as u=rwx,g=rx,o=r

        If none of 'augo' is specified, 'a' is assumed and unlike
        shell command, no umask is applied.

-chown [-R] [OWNER][:[GROUP]] PATH...
        Changes owner and group of a file.
        This is similar to shell's chown with a few exceptions.

    -R  modifies the files recursively. This is the only option
        currently supported.

        If only owner or group is specified then only owner or
        group is modified.

        The owner and group names may only cosists of digits, alphabet,
        and any of '-_.@/' i.e. [-_.@/a-zA-Z0-9]. The names are case
        sensitive.

        WARNING: Avoid using '.' to separate user name and group though
        Linux allows it. If user names have dots in them and you are
        using local file system, you might see surprising results since
        shell command 'chown' is used for local files.

-chgrp [-R] GROUP PATH...
        This is equivalent to -chown ... :GROUP ...

-count[-q] <path>: Count the number of directories, files and bytes under the paths
        that match the specified file pattern.  The output columns are:
        DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME or
        QUOTA REMAINING_QUATA SPACE_QUOTA REMAINING_SPACE_QUOTA 
              DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME
-help [cmd]:    Displays help for given command or all commands if none
        is specified.

关于FS命令:

[hadoop1@H01 data]$ ls
1.data
[hadoop1@H01 data]$ touch 2.txt
[hadoop1@H01 data]$ ls
1.data  2.txt
[hadoop1@H01 data]$ vim 2.txt 
[hadoop1@H01 data]$ hadoop fs -mkdir /dataa
[hadoop1@H01 data]$ hadoop fs -put 2.txt /dataa
[hadoop1@H01 data]$ hadoop fs -ls /
Found 2 items
-rw-r--r--   1 hadoop1 supergroup         15 2015-10-21 14:13 /data
drwxr-xr-x   - hadoop1 supergroup          0 2015-10-21 14:22 /dataa
[hadoop1@H01 data]$ hadoop fs -ls /dataa
Found 1 items
-rw-r--r--   1 hadoop1 supergroup         11 2015-10-21 14:22 /dataa/2.txt
[hadoop1@H01 data]$ hadoop fs -ls /data
Found 1 items
-rw-r--r--   1 hadoop1 supergroup         15 2015-10-21 14:13 /data
[hadoop1@H01 data]$ hadoop fs -mkdir /data2
[hadoop1@H01 data]$ hadoop fs -mv /data /data2
[hadoop1@H01 data]$ hadoop fs -ls /
Found 2 items
drwxr-xr-x   - hadoop1 supergroup          0 2015-10-21 14:25 /data2
drwxr-xr-x   - hadoop1 supergroup          0 2015-10-21 14:22 /dataa
[hadoop1@H01 data]$ hadoop fs -ls /dataa
Found 1 items
-rw-r--r--   1 hadoop1 supergroup         11 2015-10-21 14:22 /dataa/2.txt
[hadoop1@H01 data]$ hadoop fs -ls /data2

Found 1 items
-rw-r--r--   1 hadoop1 supergroup         15 2015-10-21 14:13 /data2/data
[hadoop1@H01 data]$ 
[hadoop1@H01 data]$ hadoop fs -cat /data2/data
Hello Hadoop !
[hadoop1@H01 data]$ hadoop fs -cat /data2
cat: File does not exist: /data2
[hadoop1@H01 data]$ hadoop fs -cat /data2/data
Hello Hadoop !
[hadoop1@H01 data]$ hadoop fs -cat /dataa/2.txt
wobuzhidao
[hadoop1@H01 data]$ 

HDFS文件读取流程

这里写图片描述

Cleint调用FileSystem.open()方法:

1)FileSystem通过RPC(就是整个HDFS各个进程之间的通信的协议)与NN通信,NN返回该文件的部分或全部block列表(含有block拷贝的DN地址)。

2)选取距离客户端最近的DN建立连接,读取block,返回FSDataInputStream。

Client调用输入流的read()方法

1)当读到block的结尾时,FSDataInputSystem关闭与当前DN的连接,并为读取下一个block寻找最近的DN。

2)读取完一个block都会进行checksum验证,如果读取DN时出现错误,客户端会通知NN,然后再从下一个拥有该block拷贝的DN继续读。

3)如果block列表读完后,文件还未结束,FileSystem会继续从NN获取下一批block列表。

关闭FSDataInputSystem

HDFS文件写入流程

这里写图片描述

Client调用FileSystem的create()方法:

1)FileSystem向NN发送请求,在NN的namespace里面创建一个新文件,但是并不关联任何块。

2)NN检查文件是否已存在、操作权限。如果检查通过,NN记录新文件信息,并在某一个DN上创建数据块。

3)返回FSDataOutputStream,将Client引导至该数据块执行写入操作。

Client调用输出流的write()方法:

HDFS默认将每个数据块放置3份。FSDataOutputStream将数据首先写到第一节点,第一节点将数据包传送并写入第二节点,第二节点再到第三节点。

Client调用流的close()方法:flush缓冲区的数据包,block完成复制份数后,NN返回成功消息。

HDFS代码包

HDFS 工具类包

package hadoop.hdfs.utils;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;

/**
 * HDFS 工具类包
 *
 */
public class HDFSUtils {
    public static FileSystem getFileSystem() {

        // 声明 FileSystem
        FileSystem hdfs = null;

        try {
            // 获取配置文件信息
            Configuration conf = new Configuration();

            // 获取文件系统
            hdfs = FileSystem.get(conf);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return hdfs;
    }
}

HDFS API URL 方式操作

package hadoop.hdfs;

import java.io.InputStream;
import java.net.URL;

import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;

/**
 * HDFS API URL 方式操作
 * 
 *
 */

public class HDFSUrlTest {

    // 让java程序识别HDFS的URL。
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

    // 查看文件内容,与HDFSFsTest的testRead方法功能一样
    @Test
    public void testRead() throws Exception {
        InputStream in = null;

        // 文件路径
        String fileUrl = "hdfs://H01:9000/data2/data";

        try {
            // 获取文件输入流
            in = new URL(fileUrl).openStream();

            // 将文件内容读取出来打印在控制台
            IOUtils.copyBytes(in, System.out, 4096, false);

        } finally {
            IOUtils.closeStream(in);
        }
    }

}

通过FileSystem API 操作HDFS的10个方法

注意:在Shell命令对HDFS上的文件进行操作的时候,要注意写全文件的路径

package hadoop.hdfs;

import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;

import hadoop.hdfs.utils.HDFSUtils;;

/**
 * 通过FileSystem API 操作HDFS
 *
 */
public class HDFSFsTest {

    // 第一个:读取文件内容,就是text,cat方法
    @Test
    public void testRead() throws Exception {
        // 获取文件系统
        FileSystem hdfs = HDFSUtils.getFileSystem();

        // 文件名称
        Path path = new Path("/abc/aaa/touch.data");

        // 打开文件输入流
        FSDataInputStream in = hdfs.open(path);

        // 读取文件内容到控制台显示
        IOUtils.copyBytes(in, System.out, 4096, false);

        // 关闭流
        IOUtils.closeStream(in);

    }

    // 第二个:查看文件,相当于ls
    @Test
    public void testList() throws Exception {
        FileSystem hdfs = HDFSUtils.getFileSystem();

        // 目录
        Path path = new Path("/");

        FileStatus[] fileStatus = hdfs.listStatus(path);

        for (FileStatus fs : fileStatus) {
            Path p = fs.getPath();
            String info = fs.isDir() ? "目录" : "文件";// 什么意思?

            System.out.println(info + ":" + p);

        }
    }

    // 第三个:创建目录。mkdir
    @Test
    public void testDirectory() throws Exception {
        FileSystem hdfs = HDFSUtils.getFileSystem();

        Path path = new Path("/abc/aaa/bbb/ccc");

        boolean b = hdfs.mkdirs(path);// 相当于mkdir -p ,创建多级目录

        System.out.println(b);
    }

    // 第四个:上传文件,put
    @Test
    public void testPut() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        // 本地文件位置
        Path localPath = new Path("E:/java_workspace/java0623/javaListFile.txt");

        // hdfs文件上传路径
        Path hdfsPath = new Path("/abc/aaa/bbb");

        // 文件上传
        hdfs.copyFromLocalFile(localPath, hdfsPath);

    }

    // 第五个:创建HDFS文件,并写入内容,create
    @Test
    public void testCreate() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        // HDFS文件上传路径
        Path path = new Path("/abc/aaa/bbb/ccc/ddd/d.txt");// 会创建路径中不存在的文件夹目录

        // 创建文件,并获取输出流
        FSDataOutputStream out = hdfs.create(path);

        // 通过输出流的方法写入数据
        out.write("woshiDDD".getBytes());
        // out.writeUTF("你好,hadoop");//这个会出现乱码

        IOUtils.closeStream(out);
    }

    // 第六个:对HDFS 上的文件进行改名,mv
    @Test
    public void testRename() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        // HDFS文件上传路径
        Path path = new Path("/abc/aaa/touch.data");

        Path newPath = new Path("/abc/aaa/rename.data");

        boolean isSuccess = hdfs.rename(path, newPath);

        System.out.println(isSuccess);
    }

    // 第七个:删除HDFS上的文件,rm
    @Test
    public void testDelete() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        Path path = new Path("/abc/aaa/bbb/a.txt");

        boolean isSuccess = hdfs.deleteOnExit(path);

        System.out.println(isSuccess);

    }

    // 第八个:删除HDFS的目录
    @Test
    public void testDelDir() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        Path path = new Path("/abc/aaa/bbb/ccc/ddd");

        boolean isSuccess = hdfs.delete(path, true);

        System.out.println(isSuccess);
    }

    // 第九个:查找某个文件在HDFS集群上的位置
    @Test
    public void testLocation() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        // HDFS文件上传路径
        Path path = new Path("/abc/aaa/bbb/javaListFile.txt");

        FileStatus fs = hdfs.getFileStatus(path);

        BlockLocation[] bl = hdfs.getFileBlockLocations(fs, 0, fs.getLen());

        for (BlockLocation blocklocation : bl) {
            String[] hosts = blocklocation.getHosts();
            for (String host : hosts) {
                System.out.println(host);
            }
        }

    }

    // 第十个:获取HDFS上所有节点的名称信息
    @Test
    public void testCluster() throws Exception {

        FileSystem hdfs = HDFSUtils.getFileSystem();

        DistributedFileSystem dfs = (DistributedFileSystem)hdfs;

        DatanodeInfo[] dataInfo = dfs.getDataNodeStats();

        for(DatanodeInfo dataInfos : dataInfo){
            String hostName = dataInfos.getHostName();
            System.out.println(hostName);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值