Hadoop(HDFS)

Hadoop是一个开源的分布式系统架构,旨在解决海量数据的存储和计算问题,Hadoop的核心组件包括Hadoop分布式文件系统(HDFS)、MapReduce编程模型和YARN资源管理器,最近需求需要用到HDFS和YARN。

文章目录

HDFS

HDFS在Hadoop中负责数据的存储,是一个分布式文件系统。HDFS的主要角色包括以下几种:

  • NameNode(nn):负责存储文件的元数据,包括文件名、目录结构、文件属性,此外还记录了每个文件的块列表以及这些块分别存储在哪些DataNode上。
  • DataNode (dn):在本地文件系统中保存文件的实际数据块,客户端通过dn对数据块进行读/写操作,同时还存储这些数据块的校验和,以确保数据的完整性。
  • Secondary NameNode (2nn):定期对NameNode的元数据进行备份操作,以防数据丢失。
  • Client:客户端负责先与NameNode交互获取文件的位置信息后,再与DataNode交互,进行数据的读写操作。

优缺点

优点:

高容错性 :数据会进行多个备份,当其中一个备份丢失时,系统能够自动进行恢复。
处理大规模数据:无论是大规模数据还是大量的文件,都能够有效地进行处理。

缺点:

延迟较高 :不适用于快速响应的场景,例如毫秒级别的数据访问无法实现。
小文件存储效率低下 :当存储大量小文件时,会大量占用NameNode的内存来记录文件目录和块信息,而NameNode的内存资源是有限的,并且小文件的寻址时间可能会超过实际的读取时间。
写入和修改的限制:不支持多个线程同时对同一个文件进行写入操作,且只能对文件进行追加操作,不能对文件内容进行随机修改。

文件块大小

在Hadoop 1.x版本里,默认的文件块大小为64MB,在2.x和3.x版本中为128MB,当寻址时间为传输时间的百分之一是最佳状态,如果单个文件块过小,那么大文件会被切割为很多块,从而增加寻址时间,反之,若文件块过大,那么传输时间会远大于寻址时间。

HDFS的读写原理

(1)文件写入原理

(2) 网络拓扑-节点距离计算

在HDFS进行数据写入时,NameNode会选择与待上传数据距离最近的DataNode来接收并存储这些数据。

节点距离的计算方式:两个节点到达最近的共同祖先的距离总和。

(3)机架感知原理-副本存储节点选择

副本节点选择:

  • 第一个副本在Client所处的节点上;如果客户端在集群外,随机选一个。
  • 第二个副本在另一个机架的随机一个节点。
  • 第三个副本在第二个副本所在机架的随机节点

(4)读文件原理

(5)NN 和 2NN 工作原理

NameNode 中的元数据存放在内存中,当对元数据进行更新或者添加操作时,会修改内存中的元数据并追加到 edits log 中,为了防止edits log过大,导致查询效率低的问题,SecondaryNameNode会定时触发checkpoint操作,将NameNode的edits log和fs image合并,生成一个新的fs image,以减少edits log的大小,并将新的fs image传回给NameNode,以提高元数据的查询效率。

(6)DataNode工作原理

常用命令

(1)查看命令帮助

java 复制代码
hadoop fs -help rm

(2)启动Hadoop集群

java 复制代码
sbin/start-dfs.sh
 
sbin/start-yarn.sh

(3)创建文件夹

java 复制代码
hadoop fs -mkdir /learn

(4)上传文件

  • -put:和copyFromLocal一样,生产环境更多用 put
java 复制代码
vim a.txt
aaa
bbb
hadoop fs -put a.txt /learn

  • -moveFromLocal:从本地移动到 HDFS
java 复制代码
hadoop fs -moveFromLocal b.txt /learn
  • -copyFromLocal:从本地文件拷贝文件到 HDFS
java 复制代码
hadoop fs -copyFromLocal c.txt /learn
  • -appendToFile:追加一个文件到HDFS已经存在的文件末尾
java 复制代码
hadoop fs -appendToFile d.txt /learn/c.txt

(5)下载文件

  • -get:和copyToLocal一样,生产环境更习惯用 get
java 复制代码
hadoop fs -get /learn ./
  • -copyToLocal:从 HDFS 拷贝到本地
java 复制代码
hadoop fs -copyToLocal /data ./

(6)其他操作

  • -mkdir:创建目录
java 复制代码
hadoop fs -mkdir /file
  • -ls: 显示目录信息
java 复制代码
hadoop fs -ls /learn
  • -cat:显示文件内容
  • -chgrp、-chmod、-chown:修改文件所属权限
java 复制代码
hadoop fs -chmod 777 /learn/a.txt
  • -cp:从 HDFS 的一个路径拷贝到 HDFS 的另一个路径
java 复制代码
hadoop fs -cp /learn/a.txt /file
  • -mv:在 HDFS 目录中移动文件
java 复制代码
hadoop fs -mv /learn/b.txt /file2
  • -tail:显示一个文件的末尾 1kb 的数据
java 复制代码
hadoop fs -tail /learn/a.txt
  • -rm:删除文件或文件夹
java 复制代码
hadoop fs -rm /learn/a.txt
  • -rm -r:递归删除目录及目录里面内容
java 复制代码
hadoop fs -rm -r /learn
  • -du 统计文件夹的大小信息
java 复制代码
hadoop fs -du /file2

7 表示文件大小,21 表示 3个副本的总大小

  • -setrep:设置 HDFS 中文件的副本数量
java 复制代码
hadoop fs -setrep 10 /file2

目前只有3台节点,最多也就3个副本,当节点数增加到10时,副本数才能到10。

HDFS 的 API 操作

(1)创建目录

java 复制代码
public class HdfsLearn {
    @Test
    public void testCreate() throws IOException, URISyntaxException, InterruptedException {
        Configuration configuration = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
        fs.mkdirs(new Path("/learn/file.txt"));
        fs.close();
    }
}

(2)上传文件

java 复制代码
@Test
public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {
    Configuration configuration = new Configuration();
    configuration.set("dfs.replication", "3");
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    fs.copyFromLocalFile(new Path("D:\\hadoop\\learn.txt"), new Path("/test/file4"));
    fs.close();
}

(3)下载文件

java 复制代码
@Test
public void testCopyToLocalFile() throws IOException,
        InterruptedException, URISyntaxException{
    Configuration configuration = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    // boolean delSrc 指是否将原文件删除
    // Path src 指要下载的文件路径
    // Path dst 指将文件下载到的路径
    // boolean useRawLocalFileSystem 是否开启文件校验
    fs.copyToLocalFile(false, new Path("/learn/a.txt"), new Path("D:\\hadoop\\b.txt"), true);
    fs.close();
}

(4)文件移动或者更名

java 复制代码
@Test
public void testRename() throws IOException, InterruptedException, URISyntaxException {
    Configuration configuration = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    fs.rename(new Path("/learn/a.txt"), new Path("/learn/b.txt"));
    fs.close();
}

(5)删除文件

java 复制代码
@Test
public void testDelete() throws IOException, InterruptedException, URISyntaxException{
    Configuration configuration = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    fs.delete(new Path("/file2"), true);
    fs.close();
}

(6)文件详情查看

java 复制代码
@Test
public void testListFiles() throws IOException, InterruptedException, URISyntaxException {
    Configuration configuration = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    // 获取文件详情
    RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
    while (listFiles.hasNext()) {
        LocatedFileStatus fileStatus = listFiles.next();
        System.out.println(fileStatus.getPath());
        System.out.println(fileStatus.getPermission());
        System.out.println(fileStatus.getOwner());
        System.out.println(fileStatus.getGroup());
        System.out.println(fileStatus.getLen());
        System.out.println(fileStatus.getModificationTime());
        System.out.println(fileStatus.getReplication());
        System.out.println(fileStatus.getBlockSize());
        System.out.println(fileStatus.getPath().getName());
        // 获取块信息
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
        System.out.println(Arrays.toString(blockLocations));
    }
    fs.close();
}

(7)文件判断

java 复制代码
@Test
public void testListStatus() throws IOException, InterruptedException, URISyntaxException {
    Configuration configuration = new Configuration();
    FileSystem fs = FileSystem.get(new URI("hdfs://192.168.235.130:8020"), configuration, "liang");
    // 判断是文件还是文件夹
    FileStatus[] listStatus = fs.listStatus(new Path("/"));
    for (FileStatus fileStatus : listStatus) {
        // 如果是文件
        if (fileStatus.isFile()) {
            System.out.println("f:" + fileStatus.getPath().getName());
        } else {
            System.out.println("d:" + fileStatus.getPath().getName());
        }
    }
    fs.close();
}
相关推荐
nrsc3 分钟前
[实用小代码java]-如何将对象存储服务器上的文件下载到客户端
java·服务器·oss·文件下载·octet-stream
南山十一少4 分钟前
当使用key-value方式进行参数传递时,若key对应的是一个对象或数组结构,如何利用API Post工具进行模拟操作。
java·开发语言
激流丶7 分钟前
【缓存策略】你知道 Write Around(缓存绕过写)这个缓存策略吗?
java·分布式·缓存
激流丶10 分钟前
【缓存策略】你知道 Write Through(直写)这个缓存策略吗?
java·分布式·后端·缓存·中间件
BillKu24 分钟前
Linux(CentOS)项目总结(前后端分离)
java·linux·mysql·nginx·centos
生命几十年3万天33 分钟前
故事1111
java
一二小选手37 分钟前
【Java Web】EL表达式
java·servlet·el
编程修仙1 小时前
java的单例设计模式
java·单例模式·设计模式
南城花随雪。1 小时前
Spring框架之模板方法模式 (Template Method Pattern)
java·开发语言·模板方法模式