zoukankan      html  css  js  c++  java
  • HDFS笔记——技术点汇总

    目录

    · 概况

    · 原理

        · HDFS 架构

        · 

        · NameNode

        · SecondaryNameNode

        · fsimage与edits合并

        · DataNode

        · 数据读写

        · 容错机制

        · 数据完整性

        · NameNode HA

        · NameNode Federation

        · HDFS Snapshots

    · 操作

    · API


     

    概况

    1. 文件系统抽象类FileSystem

        a) 源码

    1 public abstract class FileSystem extends Configured implements Closeable {
    2     // ...
    3 }

        b) 实现类

    文件系统

    URI方案

    Java实现

    定义

    Local

    file

    org.apache.hadoop.fs.LocalFileSystem

    已使用客户端校验的本地文件系统。未使用校验的本地磁盘文件系统由RawLocalFileSystem实现。

    HDFS

    hdfs

    org.apache.hadoop.hdfs.DistributedFileSystem

    Hadoop分布式文件系统

    HFTP

    hftp

    org.apache.hadoop.hdfs.web.HftpFileSystem

    支持通过HTTP方式以只读方式访问HDFS,通常和distcp命令结合使用。

    HSFTP

    hsftp

    org.apache.hadoop.hdfs.web.HsftpFileSystem

    支持通过HTTPS方式以只读方式访问HDFS

    HAR

    har

    org.apache.hadoop.fs.HarFileSystem

    构建在Hadoop文件系统之上,对文件归档。Hadoop归档文件主要用来减少NameNode内存使用。

    FTP

    ftp

    org.apache.hadoop.fs.ftp.FtpFileSystem

    FTP服务器支持的文件系统。

    S3(原生)

    s3n

    org.apache.hadoop.fs.s3native.NativeS3FileSystem

    基于Amazon S3的文件系统。

    S3(基于块)

    s3

    org.apache.hadoop.fs.s3.S3FileSystem

    基于Amazon S3的文件系统,解决S35GB文件大小限制。

    2. HDFS特点

        a) 适合存储超大文件:存储在HDFS的文件大多在GBTB级别,甚至PB级别。

        b) 运行于廉价硬件之上:设计时已考虑集群规模足够大时,节点故障是常态。HDFS无需运行在高可靠且昂贵的服务器,普通的PC服务器即可。

        c) 流式数据访问:HDFS认为一次写入、多次读取时最高效的访问模式。数据集生成后,会长时间在此数据集上进行各种分析,每次分析都将设计该数据集的大部分甚至全部数据。

    3. HDFS缺点

        a) 实时数据访问弱:HDFS针对数据吞吐量做了优化,而牺牲了读取效率,无法做到秒级或毫秒级响应。

        b) 大量小文件:HDFS启动时,NameNode将全部元数据加载到内存,而一般一个HDFS文件、目录和数据块的存储信息约150字节,因此文件个数受限于NameNode节点内存。过多小文件很快达到上限。

        c) 多用户写入,任意修改文件:HDFS文件同时只能有一个写入者,且写操作总在文件末。

    原理

    HDFS 架构

    1. 架构图

    2. 守护进程

    名称

    集群中数目

    作用

    NameNode

    1(默认)

    存储文件系统元数据,存储文件与数据块映射,并提供文件系统全景图

    SecondaryNameNode

    1

    备份NameNode数据,并负责镜像与NameNode日志数据合并

    DataNode

    多个(至少1个)

    存储块数据

    1. 文件系统块:块大小是磁盘块大小的整数倍,如ext34KBNTFS4KB

    2. HDFS

        a) HDFS文件:被划分为块大小的多个分块。

        b) 默认大小:64MB

        c) 较大原因:最小化寻址开销(块足够大,从磁盘传输数据块的时间明显大于定位块开始位置所需的时间)。

        d) 配置:hdfs-site.xml的参数“dfs.block.size”。

    3. 副本

        a) 含义:每个HDFS块在集群中保存的份数,默认为3

        b) 效果:值越高,冗余性越好,占用存储越多。

        c) 配置:hdfs-site.xml的参数“dfs.replication”。

    4. 块分布示例

        a) 环境:文件大小150MB,块大小64MB,副本数2

        b) 分布:第164MB,第264MB,第322MB

    5. 块布局策略

        a) 第1个副本:如果HDFS客户端在集群内,默认布局在客户端所在节点;否则随机选择一个节点,但会尽量避免存储太满或太忙的节点。

        b) 第2个副本:与第1个副本不同且随机另外机架中的节点。

        c) 第3个副本:与第2个副本相同机架且随机选择另外一个节点。

        d) 其他副本(副本数>3):集群随机选择节点,但会尽量避免在相同机架上布局太多副本。

        e) 由NameNode选择节点。

        f) 示意图:副本数为3

     

    NameNode

    1. 职责:HDFS主从(Master/Slave)架构的主角色。

    2. NameNode存储的文件

        a) fsimageHDFS元数据的完整快照,每次NameNode启动时,默认加载最新的fsimage

        b) editsfsimage的编辑日志。

    SecondaryNameNode

    1. 职责:定期合并fsimageedits的辅助守护进程。

    2. 部署:生产环境一般单独部署在一台服务器。

    fsimage与edits合并

    1. 不直接更新fsimage的原因:fsimage是一个大型文件,如果频繁执行写操作,会使系统运行极慢。

    2. 定期合并的原因

        a) 随时间推移,edits越来越大,一旦发生故障,回滚时间非常长。

        b) 如果由NameNode合并,则NameNode可能无法提供足够资源为集群服务,所以由SecondaryNameNode合并。

    3. 定期合并的过程

     

        a) SecondaryNameNode通知NameNode准备提交edits文件,此时NameNode产生edits.new

        b) SecondaryNameNode通过HTTP GET方式获取NameNodefsimageedits文件(在SecondaryNameNodecurrent同级目录下可见 temp.check-point或者previous-checkpoint目录,这些目录中存储着从NameNode拷贝来的镜像文件);

        c) SecondaryNameNode开始合并获取的上述两个文件,产生一个新的fsimage文件fsimage.ckpt

        d) SecondaryNameNodeHTTP POST方式发送fsimage.ckptNameNode

        e) NameNodefsimage.ckptedits.new文件分别重命名为fsimageedits,然后更新fstime,整个checkpoint过程结束。

    4. 定期合并的默认时机

        a) 每小时一次;

        b) 或当NameNode edits文件达到默认的64MB时。

    DataNode

    1. 职责:HDFS主从(Master/Slave)架构的从角色。

    2. 块文件:每个块都是一个文件,默认位于参数“dfs.data.dir”目录的current目录下,文件名blk_blkID

    3. 上报:DataNode启动时,向NameNode上报块信息(Block Report)。

    数据读写

    1. 文件读取过程

     

        a) HDFS对客户端身份验证,两种方式:通过信任的客户端,由其指定用户名;诸如Kerberos等强制验证机制。

        b) 客户端告知NameNode要读取的文件。当文件存在且用户有访问权限时,NameNode告知客户端该文件第1个块的标号以及保存该块的DataNode列表(按DataNode与客户端距离排序)。

        c) 客户端直接访问最适合的DataNode读取块,该过程一直重复直到文件所有块读取完成或客户端主动关闭文件流。

        d) 特殊情况,客户端是DataNode时,将从本地DataNode读取数据。

    2. 文件写入过程

        a) 客户端发送请求,打开一个要写入的文件。如果客户端有写入权限,则请求被送达NameNode,并建立该文件的元数据,但该文件元数据未和任何数据库关联。

        b) 客户端收到“打开文件成功”响应后开始将数据写入流,数据被自动拆分成数据包,并将数据包保存在内存队列。

        c) 客户端一个独立线程从队列读取数据包,并向NameNode请求一组DataNode列表,以便写入下一个块的多个副本。客户端直接连接到列表中第1DataNode,而该DataNode又连接到第2DataNode,第2个又连接到第3各,如此建立块的复制管道。各DataNode都会确认收到的数据包成功写入磁盘。客户端维护着一个列表,记录由尚未收到确认信息的数据包。

        d) 当块被写入一组DataNode后,客户端重新向NameNode申请下一组DataNode

        e) 最终,全部数据包写入,关闭数据管道并通知NameNode写操作完成。

    容错机制

    1. 心跳机制:当NameNode未收到DataNode心跳包时,NameNode认为该DataNode上的数据无效。新的IO操作将不会派发给该DataNode;如果块副本数小于hdfs-site.xml的参数“dfs.replication.min”,则开始自动复制新副本到其他DataNode节点。

    2. 块完整性校验:HDFS记录文件所有块的校验和,当确认校验和不一致时,会从其他DataNode节点获取块的副本。

    3. 集群负载均衡:节点失效或增加可能导致数据分布不均,当某个DataNode空闲空间大于临界值时,HDFS自动从其他DataNode迁移数据保持平衡。

    4. fsimageedits:如果NameNode单点部署,fsimageedits文件损坏时,可手工从SecondaryNameNode定期备份手工恢复。

    5. 文件删除:删除并未从NameNode移除,而是存放在/trash目录可随时恢复,直到超过hdfs-site.xml的参数“fs.trash.interval”的值(秒)。

    数据完整性

    1. 写入时校验:客户端将数据及其校验和发送到一组DataNode组成复制管道,管道最后一个DataNode负责验证校验和,如果错误,客户端便收到ChecksumException

    2. 读取时校验:客户端对比读取数据与DataNode存储的校验和,验证成功后告知DataNodeDataNode记录到验证校验和日志(包括每个块的最后验证时间)。

    3. 后台定期校验:每个DataNode后台有一个DataBlockScanner线程,定期验证Data上所有数据块。

    4. 块修复:NameNode将块标记为已损坏,之后安排该块的一个副本复制到另一DataNode以达到预设副本数,最后删除已损坏的块。

    NameNode HA

    1. 场景

        a) NameNode的热备(SecondaryNameNodeNameNode的冷备)。

        b) 生产环境必备功能。

    2. NameNode HA架构

        a) 一个NameNode处于主状态(Active),处理客户端和DataNode请求,并把edits写入本地和共享编辑日志(NFSQJM等)。

        b) 另一个NameNode处于从状态(StandBy),启动时加载fsimage文件,然后周期性从共享编辑日志获取edits,保持与主NameNode同步。

        c) 为实现主节点宕机后从节点迅速提供服务,DataNode需同时向两个NameNode汇报(Block Report)。

    NameNode Federation

    1. 解决问题:解决NameNode伸缩性、隔离性,以及单NameNode性能方面的问题。

    2. 场景:集群规模在1000台以下时,几乎无需NameNode Federation

     

    HDFS Snapshots

    1. 原理:HDFS Snapshots是一个只读的基于时间点的文件系统副本,快照可以时整个文件系统也可以是其中一部分。

    2. 场景:常用来作为数据备份,防止用户误操作和容灾。

    操作

    1. HDFS文件系统命令

    命令

    功能

    举例

    hadoop dfs -ls <path>

    列出文件或目录内容

    hadoop dfs -ls /

    hadoop dfs -lsr <path>

    递归列出目录内容

    hadoop dfs -lsr /

    hadoop dfs -df <path>

    查看目录使用情况

    hadoop dfs -df /

    hadoop dfs -du <path>

    显示目录中所有文件及目录的大小

    hadoop dfs -du /

    hadoop dfs -dus <path>

    显示目录总大小

    hadoop dfs -dus /

    hadoop dfs -count [-q] <path>

    显示目录下目录数及文件数,格式为“目录数 文件数 大小 文件名”,-q指查看文件索引

    hadoop dfs -count /

    hadoop dfs -mv <src> <dst>

    HDFS文件移动到目标目录

    hadoop dfs -mv /user/hadoop/a.txt /user/test

    hadoop dfs -rm [-skipTrash] <path>

    HDFS文件移动到回收站,-skipTrash指直接删除

    hadoop dfs -rm /text.txt

    hadoop dfs -rmr [-skipTrash] <path>

    HDFS目录移动到回收站,-skipTrash指直接删除

    hadoop dfs -rmr /text

    hadoop dfs -expunge

    清空回收站

    hadoop dfs -expunge

    hadoop dfs -put <localsrc> ... <dst>

    将本地文件上传到HDFS目录

    hadoop dfs -put /home/hadoop/test.txt /user/hadoop

    hadoop dfs -copyFromLocal <localsrc> ... <dst>

    类似-put

    hadoop dfs -copyFromLocal /home/hadoop/test.txt /user/hadoop

    hadoop dfs -moveFromLocal <localsrc> ... <dst>

    将本地文件移动到HDFS目录

    hadoop dfs -moveFromLocal /home/hadoop/test.txt /user/hadoop

    hadoop dfs -get [-ignoreCrc] [-crc] <src> <localdst>

    HDFS文件下载到本地目录,-ignoreCrc指忽略CRC校验失败,-crc指下载文件及CRC信息

    hadoop dfs -get /user/hadoop/a.txt /home/hadoop

    hadoop dfs -getmerge <src> <localdst> [addnl]

    HDFS目录下所有文件按文件名排序合并成一个文件下载到本地目录,addnl指每个文件结尾添加一个换行符

    hadoop dfs -getmerge /user/test /home/hadoop/o

    hadoop dfs -cat <src>

    浏览HDFS文件内容

    hadoop dfs -cat /user/hadoop/test.txt

    hadoop dfs -text <src>

    以文本方式浏览HDFS文件

    hadoop dfs -text /user/test.txt

    hadoop dfs -copyToLocal [-ignoreCrc] [-crc] <src> <localdst>

    类似-get

    hadoop dfs -copyToLocal /user/hadoop/a.txt /home/hadoop

    hadoop dfs -moveToLocal [-crc] <src> <localdst>

    HDFS文件移动到本地目录

    hadoop dfs -moveToLocal /user/hadoop/a.txt /home/hadoop

    hadoop dfs -mkdir <path>

    创建HDFS目录

    hadoop dfs -mkdir /user/test

    hadoop dfs -setrep [-R] [-w] <rep> <path/file>

    设置文件副本数,-R指递归执行

    hadoop dfs -setrep 5 -R /user/test

    hadoop dfs -touchz <path>

    创建0字节的HDFS空文件

    hadoop dfs -touchz /user/hadoop/test

    hadoop dfs -test -[ezd] <path>

    检查HDFS文件,-e指检查存在(存在返回0),-z指检查0字节(是返回0),-d指检查目录(是返回1,否返回0

    hadoop dfs -test -e /user/test.txt

    hadoop dfs -stat [format] <path>

    显示HDFS文件或目录统计信息

    hadoop dfs -stat /user/test

    hadoop dfs -tail [-f] <file>

    浏览HDFS文件最后1KB内容,-f指随文件内容更新而更新

    hadoop dfs -tail -f /user/test.txt

    hadoop dfs -chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...

    修改HDFS文件权限,-R指递归执行

    hadoop dfs -chmod -R +r /user/test

    hadoop dfs -chown [-R] [OWNER][:[GROUP]] PATH...

    修改HDFS文件所属用户,-R指递归执行

    hadoop dfs -chown -R hadoop:hadoop /user/test

    hadoop dfs -chgrp [-R] GROUP PATH...

    修改HDFS文件所属组别,-R指递归执行

    hadoop dfs -chgrp -R hadoop /user/test

    hadoop dfs -help

    显示所有dfs命令帮助

    hadoop dfs -help

    2. HDFS其他命令参考官方文档

    API

    1. HDFS客户端要求:

        a) 配置文件hdfs-site.xml

        b) Maven依赖

    1 <dependency>
    2     <groupId>org.apache.hadoop</groupId>
    3     <artifactId>hadoop-client</artifactId>
    4     <version>2.6.5</version>
    5 </dependency>

    2. 示例执行方法

    hadoop jar hdfs-test.jar hdfs.ReadFile

    3. 读取文件

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 import java.io.InputStream;
     5 
     6 import org.apache.hadoop.conf.Configuration;
     7 import org.apache.hadoop.fs.FileSystem;
     8 import org.apache.hadoop.fs.Path;
     9 import org.apache.hadoop.io.IOUtils;
    10 
    11 public class ReadFile {
    12 
    13     public static void main(String[] args) throws IOException {
    14         String uri = "hdfs://centos1:9000/test/README.txt";
    15         Configuration conf = new Configuration();
    16         
    17         FileSystem fs = null;
    18         InputStream in = null;
    19         try {
    20             fs = FileSystem.get(conf);
    21             in = fs.open(new Path(uri));
    22             IOUtils.copyBytes(in, System.out, 4096, false);
    23         } finally {
    24             IOUtils.closeStream(in);
    25             if (fs != null) {
    26                 fs.close();
    27             }
    28         }
    29     }
    30 
    31 }

    4. 写入文件

     1 package hdfs;
     2 
     3 import java.io.BufferedInputStream;
     4 import java.io.FileInputStream;
     5 import java.io.IOException;
     6 import java.io.InputStream;
     7 import java.io.OutputStream;
     8 
     9 import org.apache.hadoop.conf.Configuration;
    10 import org.apache.hadoop.fs.FileSystem;
    11 import org.apache.hadoop.fs.Path;
    12 import org.apache.hadoop.io.IOUtils;
    13 
    14 public class WriteFile {
    15 
    16     public static void main(String[] args) throws IOException {
    17         String source = "/opt/app/hadoop-2.6.5/NOTICE.txt";
    18         String destination = "hdfs://centos1:9000/test/NOTICE.txt";
    19         Configuration conf = new Configuration();
    20         
    21         InputStream in = null;
    22         FileSystem fs = null;
    23         OutputStream out = null;
    24         try {
    25             in = new BufferedInputStream(new FileInputStream(source));
    26             fs = FileSystem.get(conf);
    27             out = fs.create(new Path(destination));
    28             IOUtils.copyBytes(in, out, 4096, true);
    29         } finally {
    30             IOUtils.closeStream(out);
    31             if (fs != null) {
    32                 fs.close();
    33             }
    34             IOUtils.closeStream(in);
    35         }
    36     }
    37 
    38 }

    5. 创建目录

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.hadoop.conf.Configuration;
     6 import org.apache.hadoop.fs.FileSystem;
     7 import org.apache.hadoop.fs.Path;
     8 
     9 public class CreateDirectory {
    10 
    11     public static void main(String[] args) throws IOException {
    12         String uri = "hdfs://centos1:9000/test/testdir";
    13         Configuration conf = new Configuration();
    14         
    15         FileSystem fs = null;
    16         try {
    17             fs = FileSystem.get(conf);
    18             Path dir = new Path(uri);
    19             fs.mkdirs(dir);
    20         } finally {
    21             if (fs != null) {
    22                 fs.close();
    23             }
    24         }
    25     }
    26 
    27 }

    6. 删除目录

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.hadoop.conf.Configuration;
     6 import org.apache.hadoop.fs.FileSystem;
     7 import org.apache.hadoop.fs.Path;
     8 
     9 public class RemoveDirectory {
    10 
    11     public static void main(String[] args) throws IOException {
    12         String uri = "hdfs://centos1:9000/test/testdir";
    13         Configuration conf = new Configuration();
    14         
    15         FileSystem fs = null;
    16         try {
    17             fs = FileSystem.get(conf);
    18             Path dir = new Path(uri);
    19             boolean deleted = fs.delete(dir, true);    // 递归删除,也可删除文件
    20             System.out.println(deleted);
    21         } finally {
    22             if (fs != null) {
    23                 fs.close();
    24             }
    25         }
    26     }
    27 
    28 }

    7. 检查文件存在

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.hadoop.conf.Configuration;
     6 import org.apache.hadoop.fs.FileSystem;
     7 import org.apache.hadoop.fs.Path;
     8 
     9 public class CheckFileExistence {
    10 
    11     public static void main(String[] args) throws IOException {
    12         String uri = "hdfs://centos1:9000/test/NOTICE.txt";
    13         Configuration conf = new Configuration();
    14         
    15         FileSystem fs = null;
    16         try {
    17             fs = FileSystem.get(conf);
    18             Path file = new Path(uri);
    19             boolean exists = fs.exists(file);
    20             System.out.println(exists);
    21         } finally {
    22             if (fs != null) {
    23                 fs.close();
    24             }
    25         }
    26     }
    27 
    28 }

    8. 列出子目录和文件

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.hadoop.conf.Configuration;
     6 import org.apache.hadoop.fs.FileStatus;
     7 import org.apache.hadoop.fs.FileSystem;
     8 import org.apache.hadoop.fs.Path;
     9 
    10 public class ListFiles {
    11 
    12     public static void main(String[] args) throws IOException {
    13         String uri = "hdfs://centos1:9000/test";
    14         Configuration conf = new Configuration();
    15         
    16         FileSystem fs = null;
    17         try {
    18             fs = FileSystem.get(conf);
    19             Path dir = new Path(uri);
    20             FileStatus[] files = fs.listStatus(dir);
    21             for (FileStatus file : files) {
    22                 System.out.println(file.getPath());
    23             }
    24         } finally {
    25             if (fs != null) {
    26                 fs.close();
    27             }
    28         }
    29     }
    30 
    31 }

    9. 获取块位置信息

     1 package hdfs;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.commons.lang.StringUtils;
     6 import org.apache.hadoop.conf.Configuration;
     7 import org.apache.hadoop.fs.BlockLocation;
     8 import org.apache.hadoop.fs.FileStatus;
     9 import org.apache.hadoop.fs.FileSystem;
    10 import org.apache.hadoop.fs.Path;
    11 
    12 public class ObtainFileInfo {
    13 
    14     public static void main(String[] args) throws IOException {
    15         String uri = "hdfs://centos1:9000/test/NOTICE.txt";
    16         Configuration conf = new Configuration();
    17         
    18         FileSystem fs = null;
    19         try {
    20             fs = FileSystem.get(conf);
    21             Path file = new Path(uri);
    22             FileStatus fileStatus = fs.getFileStatus(file);
    23             BlockLocation[] blockLocations = fs.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());
    24             for (int index = 0, length = blockLocations.length; index < length; index++) {
    25                 System.out.println("block" + index + " " + StringUtils.join(blockLocations[index].getHosts(), ","));
    26             }
    27         } finally {
    28             if (fs != null) {
    29                 fs.close();
    30             }
    31         }
    32     }
    33 
    34 }

    作者:netoxi
    出处:http://www.cnblogs.com/netoxi
    本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。

  • 相关阅读:
    接口测试—-工具篇,实现接口自动化
    接口自动化测试,完整入门篇
    接口测试系列汇总
    Java教程
    补充三:国际化
    补充二:会话控制——Cookie
    补充一:EL简介
    ES6——JavaScript 的下一个版本标准
    hibernate---session查询
    缓存技术--页面缓存
  • 原文地址:https://www.cnblogs.com/netoxi/p/7223085.html
Copyright © 2011-2022 走看看