Hadoop-5-HDFS

1、概述

 Hadoop Distributed File System (HDFS™),是一种分布式文件管理系统,用于管理多个机器上的文件

 它主要用于存储文件,通过目录树结构来定位文件的位置。适合一次写入,多次读出的场景,不支持文件的修改,所以用它做数据的分析,而不是当作网盘

2、优缺点

【1】优点

  1. 高容错性。容错性体现在数据保存到多个副本上(DataNode),并且可以通过增加副本的数量(replication),来提高这种特性。并且当一个副本的数据丢失后,它还可以自动恢复
  2. 大数据量。一是处理数据的量级,可以达到TB、PB的级别。二是文件的数量,能够处理百万以上的规模
  3. 流式数据。一次写入,多次写出。只能追加,不能修改。保证数据的一致性
  4. 高可用性。可以将数据节点部署到多个廉价机器上

【2】缺点

  1. 不能实现低延迟的数据访问。无法做到毫秒级的海量数据存储
  2. 无法高效地存储多个小文件。处理大量的小文件的存储、目录结构以及块信息,会占用NameNode的大量内存资源。此外小文件存储时的寻址时间会超过其读取时间,这违反了HDFS设计的初衷
  3. 不能并发写入和随机修改。对于一个文件,在同一时间内只能有一个写入,不允许多个线程同时写入。仅支持文件的追加,不支持文件的修改

3、架构设计

 主要由NameNode,DataNode和SecondaryNameNode组成

 需要注意的是SecondaryNameNode不是NameNode的热备,所以当NameNode节点挂掉时,其并不能立即替换NameNode并提供服务。SecondaryNameNode是一个用于监控HDFS状态的后台辅助程序,它每隔一段时间就会获取NameNode(HDFS元数据)的快照

4、块

 HDFS中的文件在物理上是分块存储(block),块的大小可以通过etc/hadoop/hdfs-site.xml中的dfs.blocksize来设置。apache hadoop 2.9.2默认大小为134217728(128MB)

 HDFS的块的大小比物理磁盘的块的大小要大,这是为了减少寻址的开销。如果块设置得足够大,那么数据传输的时间要明显地久于块寻址的时间

 寻址时间为传输时间的1%时,是最佳状态。计算公式:文件传输时间 = 磁盘寻址时间 / 0.01块的大小 = 文件传输时间 * 磁盘传输速率

 根据公式:假如寻址时间是10s,传输速率是100MB/s,那么块的大小 = 10s / 0.01 * 100MB/s = 100MB

5、命令操作【常用命令】

 所有命令都是通过bin/hadoop fs 命令的方式执行的。注意命令前面都有一个横杠

【1】创建目录

-mkdir -p,选项p表示递归,和Linux命令一样,不带参数仅创建一级目录

【2】查看目录

-ls -R,选项R表示递归,它会一直到目录的最里面

【3】删除目录

-rmdir

【4】上传文件

-copyFromLocal /本地文件 /HDFS目录,复制本地文件到HDFS

-put /本地文件 /HDFS目录,和copyFromLocal命令一样

-moveFromLocal /本地文件 /HDFS目录,移动本地文件到HDFS

【5】下载文件

-copyToLocal /HDFS文件 /本地目录,复制HDFS文件到本地

-get /HDFS文件 /本地目录,和copyToLocal命令一样

-moveToLocal /HDFS文件 /本地目录,移动HDFS文件到本地。

Hadoop 2.9.2,提示:moveToLocal: Option ‘-moveToLocal’ is not implemented yet.

【6】追加文件

-appendToFile /本地文件 /HDFS文件,将本地文件的内容追加到HDFS文件的末端

【7】查看文件

-cat /HDFS文件或目录,查看文件,可以使用*通配符,和Linux命令一样

-tail -f /HDFS文件,查看文件末尾,后41行,可以追加f选项,和Linux命令一样

【8】删除文件

-rm -r /HDFS目录或文件,删除文件或目录,和Linux命令一样

6、Java客户端操作

【1】准备环境

  1. Java
  2. Maven
  3. 和服务端一致的Hadoop,并解压缩到无中文目录
  4. 下载winutils,并将hadoop-2.8.3/bin目录里的winutils.exe复制到解压缩后的hadoop的bin目录当中
  5. 配置环境变量:HADOOP_HOME到解压缩目录
  6. 打开IDE。一定要先配置好环境变量再打开IDE

【2】MAVEN依赖

<properties><!-- 和服务端版本一致 --><hadoop.version>2.9.2</hadoop.version>
</properties><dependency><!-- hadoop-client间接依赖hadoop-common --><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>${hadoop.version}</version>
</dependency>
<dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>${hadoop.version}</version>
</dependency>

【3】获取文件系统

通过org.apache.hadoop.fs.FileSystem对象的静态方法来获取

  1. FileSystem get(Configuration conf) throws IOException,需要传递一个org.apache.hadoop.conf.Configuration对象,该配置对象的属性,可以从etc/hadoop/core-site.xml中获取

    Configuration conf = new Configuration();
    // NameNode服务器的IP,9000是默认端口
    conf.set("fs.defaultFS", "hdfs://???.???.???.???:9000");
    FileSystem fileSystem = null;
    try {fileSystem = FileSystem.get(conf);System.out.println(fileSystem);
    } catch (IOException e) {e.printStackTrace();
    } finally {if (null != fileSystem) {try {fileSystem.close();} catch (IOException e) {e.printStackTrace();}}
    }
    
  2. FileSystem get(final URI uri, final Configuration conf, String user) throws IOException, InterruptedException

    URI uri = null;
    try {// NameNode服务器的IP,9000是默认端口uri = new URI("hdfs://???.???.???.???:9000");
    } catch (URISyntaxException e) {e.printStackTrace();return;
    }Configuration conf = new Configuration();
    FileSystem fileSystem = null;
    try {// 操作文件系统的用户名fileSystem = FileSystem.get(uri, conf, "???");System.out.println(fileSystem);
    } catch (IOException | InterruptedException e) {e.printStackTrace();
    } finally {if (null != fileSystem) {try {fileSystem.close();} catch (IOException e) {e.printStackTrace();}}
    }
    
  3. 【推荐】FileSystem get(URI uri, Configuration conf) throws IOException

    URI uri = null;
    try {// NameNode服务器的IP,9000是默认端口uri = new URI("hdfs://???.???.???.???:9000");
    } catch (URISyntaxException e) {e.printStackTrace();return;
    }// 操作文件系统的用户名。这句话也可以配置到vm参数当中-DHADOOP_USER_NAME=???
    System.setProperty("HADOOP_USER_NAME", "???");Configuration conf = new Configuration();
    FileSystem fileSystem = null;
    try {fileSystem = FileSystem.get(uri, conf);System.out.println(fileSystem);
    } catch (IOException e) {e.printStackTrace();
    } finally {if (null != fileSystem) {try {fileSystem.close();} catch (IOException e) {e.printStackTrace();}}
    }
    

【4】参数配置的优先级

 通过org.apache.hadoop.conf.Configuration对象配置参数的优先级是最高的。接着是classpath路径下的配置文件,如core-site.xml等。最后才是默认配置的参数

【5】创建目录

try {boolean mkdirs = fileSystem.mkdirs(new Path("/?/?/?"));System.out.println(mkdirs ? "成功" : "失败");
} catch (IOException e) {e.printStackTrace();
}

【6】查看目录

try {RemoteIterator<LocatedFileStatus> remoteIterator = fileSystem.listFiles(new Path("/"), true); // 第二个参数表示是否递归System.out.println("Permission\tOwner\tGroup\t\tSize\tLast Modified\tPath\t\tReplication");SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM-dd HH:mm");while (remoteIterator.hasNext()) {LocatedFileStatus locatedFileStatus = remoteIterator.next();String permission = locatedFileStatus.getPermission().toString();StringBuilder line = new StringBuilder(permission).append("\t");String owner = locatedFileStatus.getOwner();line.append(owner).append("\t");String group = locatedFileStatus.getGroup();line.append(group).append("\t");long size = locatedFileStatus.getLen();line.append(size).append("\t");long lastModified = locatedFileStatus.getModificationTime();String time = simpleDateFormat.format(new Date(lastModified));line.append(time).append("\t\t");Path path = locatedFileStatus.getPath();String pathStr = path.toString();line.append(pathStr).append("\t\t");short replication = locatedFileStatus.getReplication();line.append(replication);BlockLocation[] blockLocations = locatedFileStatus.getBlockLocations();line.append(Arrays.asList(blockLocations)).append("\t");System.out.println(line);}
} catch (IOException e) {e.printStackTrace();
}

【7】删除目录或文件

try {boolean delete = fileSystem.delete(new Path("/?"), true); // 第二个参数表示是否递归System.out.println(delete ? "成功" : "失败");
} catch (IOException e) {e.printStackTrace();
}

【8】上传文件

// 复制文件
try {fileSystem.copyFromLocalFile(new Path("?:\\???"), new Path("/???/???"));
} catch (IOException e) {e.printStackTrace();
}// 剪切文件
try {fileSystem.moveFromLocalFile(new Path("?:\\???"), new Path("/???/???"));
} catch (IOException e) {e.printStackTrace();
}// 复制文件,流式方式
File file = new File("?:\\???");
try {FileInputStream fis = new FileInputStream(file);FSDataOutputStream fsos = fileSystem.create(new Path("/???/???"));/** 第三个参数,缓冲容器大小* 第四个参数,是否关闭输入流和输入流*/IOUtils.copyBytes(fis, fsos, 4096, true);
} catch (IOException e) {e.printStackTrace();
}

【9】下载文件

try {/** 第一个参数,是否删除源文件。true: 剪切,false: 复制* 最后一个参数,是否将RawLocalFileSystem作为本地文件系统。推荐使用*/fileSystem.copyToLocalFile(false, new Path("?:\\???"), new Path("/???/???"), true);
} catch (IOException e) {e.printStackTrace();
}// 下载文件,流式方式
try {FSDataInputStream fsis = fileSystem.open(new Path("/???/???");File file = new File("?:\\???");FileOutputStream fos = new FileOutputStream(file);/** 第三个参数,缓冲容器大小* 第四个参数,是否关闭输入流和输入流*/IOUtils.copyBytes(fsis, fos, 4096, true);
} catch (IOException e) {e.printStackTrace();
}// 下载2块文件
try {FSDataInputStream fsis = fileSystem.open(new Path("/???/jdk-8u212-linux-x64.tar.gz"));File part1 = new File("?:\\part1");FileOutputStream fos1 = new FileOutputStream(part1);int bufferSize = 4096; // 缓冲大小byte[] buffer = new byte[bufferSize];long blockSize = 128 * 1024 * 1024; // 128MB -- 块大小for (int offset = 0; offset < blockSize; offset += bufferSize) {int read = fsis.read(buffer, 0, bufferSize);fos1.write(buffer, 0, read);}IOUtils.closeStream(fos1); // 关闭输出流File part2 = new File("?:\\part2");FileOutputStream fos2 = new FileOutputStream(part2);fsis.seek(blockSize);IOUtils.copyBytes(fsis, fos2, bufferSize, true); // 复制块1,并关闭输入流和输出流
} catch (IOException e) {e.printStackTrace();
}

【10】重命名目录或文件(移动操作)

try {boolean rename = fileSystem.rename(new Path("/?/?"), new Path("/?/?"));System.out.println(rename ? "成功" : "失败");
} catch (IOException e) {e.printStackTrace();
}

【11】判断是否是文件还是目录

try {Path path = new Path("/?/?");boolean file = fileSystem.isFile(path);boolean directory = fileSystem.isDirectory(path);System.out.println(file ? "是文件" : "不是文件!");System.out.println(directory ? "是目录" : "不是目录!");
} catch (IOException e) {e.printStackTrace();
}

注意:如果目录或文件不存在时,这2种判断都会返回false

7、机架感知(Rack Awareness)

 Hadoop具有机架感知的功能。 将一个块的分片复制品放在不同的机架上,通过这种块放置的方式,外加使用机架感知来实现容错。 这可以在群集发生网络切换故障或分区时,提供数据的可用性

 就默认分片数为3而言:如果本机DataNode需要存储数据,则Hadoop会将DataNode的副本放到本机上,否则就随机放到其他DataNode上。同时会在另外一机架上的节点放置副本。最后一副本放到同一机架上的不同节点

 这样做可以减少机架间的写入流量,从而提高写入效率。因为机架故障的可能性远小于节点故障的可能性,所以这种策略不会影响数据的可靠性和可用性。此外也减少了读取数据时使用的聚合网络带宽,因为块放到了2个唯一的机架上,而不是3个。三分之一的副本存放到一个节点上,三分之二的副本存放到一个机架上。这种策略可以提高写入性能,而不会影响数据的可靠性或可读性

8、文件上传和文件下载的工作流程

【1】文件上传

  1. 客户端请求NameNode,是否可以进行文件的上传
  2. 当客户端收到可以上传的响应后,依次顺序上传block0(0 ~ 128MB),block1(128MB ~ 256MB)到DataNode
  3. 获取所有需要上传的DataNode的节点信息,依次请求建立传输通道
  4. 收到DataNode响应,传输通道建立完毕,开始传输数据

【2】文件下载

  1. 客户端请求NameNode,获取block信息
  2. 收到NameNode返回的元数据信息,请求对应的DataNode,获取所需的block数据
  3. 合并所有的block数据为一个完整的数据,最终得到完整数据

9、NameNode和SecondaryNameNode工作机制

【1】NameNode启动时的工作机制

  1. NameNode将镜像文件(FsImage)加载到内存中
  2. NameNode将编辑日志(EditLog)加载到内存中
  3. 保存检查点位置(checkpoint)
  4. 进入安全模式(Safe mode)

这一过程,可以通过NameNode的管理页面来查看,在Startup Progress选项卡页面当中

Elapsed Time: ??? sec, Percent Complete: 100%

Phase Completion Elapsed Time
Loading fsimage /???/dfs/name/current/fsimage_??? ??? KB 100% ??? sec
 inodes (???/???) 100%
 delegation tokens (???/???) 100%
 cache pools (???/???) 100%
Loading edits 100% ??? sec
 /???/dfs/name/current/edits_???-??? ??? MB (???/???) 100%
Saving checkpoint 100% ??? sec
 inodes /???/dfs/name/current/fsimage.ckpt_??? (???/???) 100%
 delegation tokens /???/dfs/name/current/fsimage.ckpt_??? (???/???) 100%
 cache pools /???/dfs/name/current/fsimage.ckpt_??? (???/???) 100%
Safe mode 100% ??? sec
 awaiting reported blocks (???/???) 100%

每一个block占元数据的大小为150字节,由于NameNode在启动时,会将这些都加载到内存当中,而内存是有上限的。所以这就是Hadoop不宜存储过多小文件的原因,它会占用大量的内存空间

【2】SecondaryNameNode运行时的工作机制

  1. 请求NameNode是否需要检查点(Checkpoint)
  2. 如果需要Checkpoint,则执行
  3. 复制NameNode的编辑日志(edits),包括已经执行完毕的(例如:edits_0000000000000000001-0000000000000000002)以及正在执行的(例如:edits_inprogress_0000000000000010453)
  4. 加载到内存中,合并生成新的镜像文件(fsimage.checkpoint)
  5. 复制镜像文件(fsimage.checkpoint)到NameNode

 将编辑日志(EditLog)中的所有事务保存到镜像文件(FsImage)里,并加载到内存中,然后结转旧的编辑日志(EditLog),这个过程称为检查点(checkpoint)

 触发SecondaryNameNode请求NameNode查看是否需要执行检查点(checkpoint),是由2个参数配置来决定的,在etc/hadoop/hdfs-site.xml

<!-- 执行检查点的周期,单位:秒。默认为1小时 -->
<property><name>dfs.namenode.checkpoint.period</name><value>3600</value>
</property>
<!-- 执行编辑日志的事务次数。默认为一百万次 -->
<property><name>dfs.namenode.checkpoint.txns</name><value>1000000</value>
</property>

 可以通过前端管理页面来查看SecondaryNameNode的概览,链接是:http://SecondaryNameNode服务主机的IP:50090

 包括了:Hadoop的版本(Version),NameNode的服务地址(NameNode Address),启动时间(Started),上次检查点时间(Last Checkpoint)以及检查点周期(Checkpoint Period)和HDFS事务执行次数上限(Checkpoint Transactions)

 注意:hadoop-2.9.2版本的SecondaryNameNode管理页面JS有一个名为moment的function未定义,所以在加载页面时不会展示数据。解决办法是打开浏览器的开发者工具里的Sources选项卡,修改moment函数

'date_tostring' : function (v) {// return moment(Number(v)).format('ddd MMM DD HH:mm:ss ZZ YYYY');return new Date(v); // 直接新建时间对象并返回即可
},

 在dfs-dust.js:61处打断点,修改并保存JS,放开断点即可

【3】NameNode运行时的工作机制

 接收SecondaryNameNode发来的镜像文件(fsimage.checkpoint),并重命名为fsimage

10、编辑日志和镜像文件

【1】概念

 EditLog文件位于??/dfs/name/current/目录里,以edits_开头。它保存了HDFS的所有更新操作的记录的序列化信息

 seen_txid文件保存了正在执行过程中的EditLog文件(edits_inprogress_???)的事务ID

 FsImage文件位于??/dfs/name/current/目录里,以fsimage_开头。它保存了HDFS的所有目录和文件的idnode的序列化信息,是HDFS元数据的检查点(checkpoint)的持久化形态

 VERSION文件,保存了NameNode的唯一标识(namespaceID),全局唯一的集群ID(clusterID),以及存储形态(storageType=NAME_NODE)

 SecondaryNameNode和NameNode相比,其???/dfs/namesecondary/current/目录里,仅仅少了正在执行过程中的EditLog文件(edits_inprogress_???)和seen_txid文件。这样设计是为了方便当NameNode节点故障时,并且没有及时备份数据,可以通过SecondaryNameNode来恢复NameNode

【2】反序列化EditLog和FsImage

 可以反序列化编辑日志,使用命令:bin/hdfs oev -p 反序列化的文件类型 -i 编辑日志路径 -o 反序列化后的文件路径

 可选的反序列化的文件类型有:binary (native binary format that Hadoop uses), xml (default, XML format), stats (prints statistics about edits file)。可以看到默认是XML类型

 反序列化镜像文件,使用命令:bin/hdfs oiv -p 反序列化的文件类型 -i 镜像文件路径 -o 反序列化后的文件路径

 可选的反序列化的文件类型有:(XML|FileDistribution|ReverseXML|Web|Delimited) The default is Web。可以看到默认是Web类型。推荐使用XML

【3】反序列化后的EditLog

<?xml version="1.0" encoding="UTF-8"?>
<EDITS><!-- EditLog版本号 --><EDITS_VERSION>-63</EDITS_VERSION><RECORD><!-- 操作类型:开始记录EditLog --><OPCODE>OP_START_LOG_SEGMENT</OPCODE><DATA><!-- 事务ID --><TXID>1</TXID></DATA></RECORD><RECORD><!-- 操作类型:结束记录EditLog --><OPCODE>OP_END_LOG_SEGMENT</OPCODE><DATA><TXID>2</TXID></DATA></RECORD>
<!-- 另外一个EditLog --><RECORD><!-- 操作类型:创建目录 --><OPCODE>OP_MKDIR</OPCODE><DATA><TXID>4</TXID><!-- 文件大小:0,目录 --><LENGTH>0</LENGTH><!-- inodeID --><INODEID>16386</INODEID><!-- 路径 --><PATH>/tmp</PATH><!-- 创建时间戳 --><TIMESTAMP>1565635741266</TIMESTAMP><!-- 权限 --><PERMISSION_STATUS><!-- 所有者 --><USERNAME>hadoop</USERNAME><!-- 所属组 --><GROUPNAME>supergroup</GROUPNAME><MODE>504</MODE></PERMISSION_STATUS></DATA></RECORD><RECORD><!-- 操作类型:新建文件 --><OPCODE>OP_ADD</OPCODE><DATA><TXID>10315</TXID><LENGTH>0</LENGTH><INODEID>18322</INODEID><PATH>/???/_temporary/???/_temporary/attempt_1565637203418_0001_r_000000_0/part-r-00000</PATH><!-- 分片数 --><REPLICATION>4</REPLICATION><MTIME>1565637361625</MTIME><ATIME>1565637361625</ATIME><!-- 块大小:128MB --><BLOCKSIZE>134217728</BLOCKSIZE>    <!-- 客户端名称 --><CLIENT_NAME>DFSClient_attempt_1565637203418_0001_r_000000_0_950599497_1</CLIENT_NAME><!-- 客户端IP --><CLIENT_MACHINE>???.???.???.???</CLIENT_MACHINE><OVERWRITE>false</OVERWRITE><PERMISSION_STATUS><USERNAME>hadoop</USERNAME><GROUPNAME>supergroup</GROUPNAME><MODE>420</MODE></PERMISSION_STATUS><RPC_CLIENTID>fb6e1e9c-f8a4-4428-a6f0-12304607e6c1</RPC_CLIENTID><RPC_CALLID>4</RPC_CALLID></DATA></RECORD><RECORD><!-- 操作类型:分配块ID --><OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE><DATA><TXID>10316</TXID><BLOCK_ID>1073743480</BLOCK_ID></DATA></RECORD><RECORD><!-- 操作类型:添加块 --><OPCODE>OP_ADD_BLOCK</OPCODE><DATA><TXID>10318</TXID><PATH>/???/_temporary/???/_temporary/attempt_1565637203418_0001_r_000000_0/part-r-00000</PATH><BLOCK><BLOCK_ID>1073743480</BLOCK_ID><NUM_BYTES>0</NUM_BYTES><GENSTAMP>2656</GENSTAMP></BLOCK><RPC_CLIENTID></RPC_CLIENTID><RPC_CALLID>-2</RPC_CALLID></DATA></RECORD><RECORD><!-- 操作类型:删除临时目录 --><OPCODE>OP_DELETE</OPCODE><DATA><TXID>10324</TXID><LENGTH>0</LENGTH><PATH>/???/_temporary</PATH><TIMESTAMP>1565637361871</TIMESTAMP><RPC_CLIENTID>4e4b34de-f566-4b67-a350-e014ebc27e39</RPC_CLIENTID><RPC_CALLID>39</RPC_CALLID></DATA></RECORD></RECORD><RECORD><!-- 操作类型:重命名(执行MapReduce任务) --><OPCODE>OP_RENAME</OPCODE><DATA><TXID>10354</TXID><LENGTH>0</LENGTH><SRC>/tmp/hadoop-yarn/staging/history/done_intermediate/hadoop/job_1565637203418_0001_conf.xml</SRC><DST>/tmp/hadoop-yarn/staging/history/done/2019/08/13/000000/job_1565637203418_0001_conf.xml</DST><TIMESTAMP>1565637363513</TIMESTAMP><OPTIONS>TO_TRASH</OPTIONS><RPC_CLIENTID>696288b7-d3ff-4bf2-a17b-5dc108925fc9</RPC_CLIENTID><RPC_CALLID>20</RPC_CALLID></DATA></RECORD>
<!-- 另外一个EditLog --><RECORD><!-- 操作类型:重命名(上传文件) --><OPCODE>OP_RENAME_OLD</OPCODE><DATA><TXID>25</TXID><LENGTH>0</LENGTH><SRC>/???/???._COPYING_</SRC><DST>/???/???</DST><TIMESTAMP>1566211667239</TIMESTAMP><RPC_CLIENTID>a3bffd43-b49b-4c0b-b4d1-394feb9fd9a2</RPC_CLIENTID><RPC_CALLID>8</RPC_CALLID></DATA></RECORD>
</EDITS>

【4】反序列化后的FsImage

<?xml version="1.0"?>
<fsimage><!-- 版本信息 --><version><layoutVersion>-63</layoutVersion><onDiskVersion>1</onDiskVersion><oivRevision>826afbeae31ca687bc2f8471dc841b66ed2c6704</oivRevision></version><!-- NameNode信息 --><NameSection><!-- 对应VERSION文件里的namespaceID --><namespaceId>598335362</namespaceId><genstampV1>1000</genstampV1><genstampV2>2670</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073743492</lastAllocatedBlockId><txid>10455</txid></NameSection><!-- 目录和文件信息 --><INodeSection><!-- 最后一个InodeId --><lastInodeId>18346</lastInodeId><numInodes>42</numInodes><inode><id>16385</id><!-- 这是个目录 --><type>DIRECTORY</type><!-- /:根路径 --><name/><mtime>1566131716332</mtime><!-- 权限,所有者:所属组:0权限信息 --><permission>hadoop:supergroup:0755</permission><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode><inode><id>16386</id><type>DIRECTORY</type><!-- 目录名称 --><name>tmp</name><mtime>1565636758639</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode><inode><id>18346</id><!-- 这是个文件 --><type>FILE</type><!-- 文件名称 --><name>jdk-8u212-linux-x64.tar.gz</name><!-- 分片数量 --><replication>4</replication><mtime>1566132732553</mtime><atime>1566132726115</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073743491</id><genstamp>2669</genstamp><numBytes>134217728</numBytes></block><block><id>1073743492</id><genstamp>2670</genstamp><numBytes>60795424</numBytes></block></blocks><storagePolicyId>0</storagePolicyId></inode></INodeSection><INodeReferenceSection/><!-- 快照信息 --><SnapshotSection><snapshotCounter>0</snapshotCounter><numSnapshots>0</numSnapshots></SnapshotSection><!-- 目录的父子关系 --><INodeDirectorySection><directory><parent>16385</parent><child>18340</child><child>16392</child><child>16386</child></directory><directory><parent>16386</parent><child>16387</child><child>18243</child></directory></INodeDirectorySection><FileUnderConstructionSection/><SecretManagerSection><currentId>0</currentId><tokenSequenceNumber>0</tokenSequenceNumber><numDelegationKeys>0</numDelegationKeys><numTokens>0</numTokens></SecretManagerSection><CacheManagerSection><nextDirectiveId>1</nextDirectiveId><numDirectives>0</numDirectives><numPools>0</numPools></CacheManagerSection>
</fsimage>

11、滚动编辑日志

 使用命令bin/hdfs dfsadmin -rollEdits,这样会结转当前正在执行中的EditLog(edits_???-???),并生成一个新的正在执行过程中的EditLog(edits_inprogress_???

Successfully rolled edit logs.
New segment starts at txid ???

12、通过SecondaryNameNode来恢复NameNode

【1】手动方式

  1. 模拟NameNode故障,jps查看NameNode的进程号,通过命令kill -9 NameNode的进程ID强制停止NameNode
  2. 首先删除???/dfs/name目录里的所有文件
  3. 使用scp复制SecondaryNameNode的???/dfs/namesecondary目录里的所有文件到NameNode的???/dfs/name目录里,并删除复制后的name目录里的in_use.lock文件
  4. 启动NameNode,sbin/hadoop-daemon.sh start namenode
  5. 查看是否可以访问NameNode的前端管理页面,并测试HDFS的文件上传和文件下载

【2】命令方式

  1. 模拟NameNode故障,jps查看NameNode的进程号,通过命令kill -9 NameNode的进程ID强制停止NameNode

  2. 修改NameNode节点的etc/hadoop/hdfs-site.xml文件

    <!-- 修改执行检查点的周期为2分钟,这是为了保证能够及时同步SecondaryNameNode的数据。默认为1小时 -->
    <property><name>dfs.namenode.checkpoint.period</name><value>120</value>
    </property>
    <!-- 指定NameNode的name目录的路径。默认为file://${hadoop.tmp.dir}/dfs/name -->
    <property><name>dfs.namenode.name.dir</name><value>/???/dfs/name</value>
    </property>
    
  3. 使用scp复制SecondaryNameNode的???/dfs/namesecondary目录到NameNode的???/dfs目录下,和???/dfs/name平级即可。并删除复制后的namesecondary目录里的in_use.lock文件

  4. 删除???/dfs/name目录里的所有文件

  5. 执行导入检查点数据命令,bin/hdfs namenode -importCheckpoint

    执行命令后,会发现NameNode被启动起来。命令执行过程较长,如果此时访问NameNode的前端管理页面,会发现提示信息:Upgrade in progress. Not yet finalized.

    当看到process的信息后,就可以Ctrl + C停止命令了

  6. 启动NameNode,sbin/hadoop-daemon.sh start namenode

  7. 查看是否可以访问NameNode的前端管理页面,并测试HDFS的文件上传和文件下载

13、安全模式(Safemode)

【1】概念

 当NameNode在刚启动时,会进入安全模式,此时HDFS对于客户端来说是只读的

 在系统正常运行期间,NameNode会在内存中保存所有的块位置的映射信息。而在安全模式下,每个DataNode会向NameNode发送最新的块列表信息。NameNode了解的块位置信息越多,它可越高效地运行文件系统

一旦满足最小副本条件,NameNode会在30秒后退出安全模式。最小副本条件是指,在整个文件系统当中,99.9%的块满足最小副本级别,最小副本级别可以通过etc/hadoop/hdfs-site.xmldfs.replication.min参数来配置,默认值为1

 启动一个刚格式化的HDFS集群时,不会进入安全模式,是因为此时还没有任何块信息

【2】相关命令

  • 查看当前是否在安全模式当中

    bin/hdfs dfsadmin -safemode get

  • 进入安全模式

    bin/hdfs dfsadmin -safemode enter

  • 退出安全模式

    bin/hdfs dfsadmin -safemode leave

  • 等待安全模式退出

    bin/hdfs dfsadmin -safemode wait

#!/bin/bash
bin/hdfs dfsadmin -safemode wait
echo "退出安全模式!"
# 执行HDFS文件操作
# bin/hadoop fs -???

14、NameNode多目录配置

 在etc/hadoop/hdfs-site.xml中配置

<!-- 指定NameNode的name目录的路径,多个目录之间用逗号隔开。默认为file://${hadoop.tmp.dir}/dfs/name -->
<property><name>dfs.namenode.name.dir</name><value>file://${hadoop.tmp.dir}/dfs/name1,file://${hadoop.tmp.dir}/dfs/name2</value>
</property>

注意:配置此项后,再次启动集群时需要格式化NameNode

15、DataNode工作机制

  1. DataNode启动后,向NameNode发起注册
  2. 注册成功后,每隔1个小时上传一次所有块的位置信息
  3. NameNode每隔3秒钟(可配置),执行一次心跳检测,DataNode接收到心跳检测并返回给NameNode发来的命令信息
  4. 如果超过10分钟(可配置)[外加30秒],NameNode没有收到DataNode传来的心跳检测信息,则认为该节点不可用

 DataNode不同于NameNode,其无需进行格式化,在初始化过程中,创建好数据目录

 DataNode保存了数据,数据长度(文件大小),校验和(CRC),以及时间戳等信息。这些位于???/dfs/data/current目录当中

 DataNode校验和使用CRC算法(循环冗余校验)。对原始数据进行CRC的校验计算,然后和传输过来的CRC校验位进行对比,查看结果是否一致

 心跳检测周期和心跳超时时间,可以在etc/hadoop/hdfs-site.xml中来配置

<!-- 心跳检测DataNode的超时时间,单位:毫秒。默认为300秒(5分钟) -->
<property><name>dfs.namenode.heartbeat.recheck-interval</name><value>300000</value>
</property>
<!-- DataNode的心跳检测间隔,单位:秒。默认为3秒 -->
<property><name>dfs.heartbeat.interval</name><value>3</value>
</property>

心跳超时时间 = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval

 所以默认心跳超时时间是10分钟

 一旦NameNode将最近没有发送heartbeat消息的DataNode标记为已死亡,就不会再将新的IO请求转发给它,并且对于HDFS来说,它是不可用的。这就有可能降低某些block的分片数量(replication factor)

16、DataNode多目录配置

 在etc/hadoop/hdfs-site.xml中配置

<!-- 指定NameNode的name目录的路径,多个目录之间用逗号隔开。默认为file://${hadoop.tmp.dir}/dfs/data -->
<property><name>dfs.datanode.data.dir</name><value>file://${hadoop.tmp.dir}/dfs/data1,file://${hadoop.tmp.dir}/dfs/data2</value>
</property>

注意:配置此项后,再次启动集群时需要格式化NameNode

17、集群节点的动态增加和动态移除

【1】动态新增节点

  1. 准备好新的机器,配置好静态IP,host和防火墙,以及Java运行环境和环境变量,并新建执行Hadoop的用户

  2. 使用scp命令复制NameNode服务节点的Hadoop目录到新的机器上

  3. 配置好其他节点的host

  4. 使用命令ssh-copy-id 用户名@新机器host,为NameNode节点和ResourceManager节点,创建新的机器的免密登录

  5. ① 在所有节点的etc/hadoop目录下,创建名为dfs.hosts的文件,并添加所有节点的IP到文件中。每个IP占一行,不允许有空格

    ② 在所有节点的etc/hadoop/hdfs-site.xml中,修改配置

    <!-- 修改 -->
    <property><!-- 配置副本数 --><name>dfs.replication</name><value>增加机器后的DataNode的数量</value>
    </property>
    <!-- 新增 -->
    <property><!-- 指定可以连接到NameNode的主机列表。如果该值为空,则允许所有主机。默认为空 --><name>dfs.hosts</name><value>/???/可以连接到NameNode的主机列表文件</value>
    </property>
    

    ③ 在所有节点的etc/hadoop/slaves中,将新机器的IP添加到里面

  6. 在NameNode节点机器上,执行命令bin/hdfs dfsadmin -refreshNodes,刷新DataNode

  7. 在ResourceManager节点机器上,执行命令bin/yarn rmadmin -refreshNodes,刷新NodeManager

  8. 在NameNode节点机器上,执行命令sbin/start-balancer.sh,实现集群数据的平衡(Blocks)

  9. 此时查看NameNode的前端管理页面,在Datanodes选项页面里,应该新增了一个DataNode节点,其Admin State为Dead

  10. 到新机器上,分别执行命令sbin/hadoop-daemon.sh start datanode启动DataNode,和命令sbin/yarn-daemon.sh start nodemanager启动NodeManager

  11. 再回到NameNode的前端管理页面,刷新可以看到,新节点的Admin State为In Service

  12. 上传文件和下载文件,进行测试

【2】动态移除节点

  1. ① 在所有节点的etc/hadoop目录下,创建名为dfs.hosts.exclude的文件,并添加要移除的节点的IP到文件中。每个IP占一行,不允许有空格

    ② 在所有节点的etc/hadoop/hdfs-site.xml中,修改配置

    <!-- 修改 -->
    <property><!-- 配置副本数 --><name>dfs.replication</name><value>移除机器后的DataNode的数量</value>
    </property>
    <!-- 新增 -->
    <property><!-- 指定不允许连接到NameNode的主机列表。如果该值为空,则不排除任何主机。默认为空 --><name>dfs.hosts.exclude</name><value>/???/不允许连接到NameNode的主机列表文件</value>
    </property>
    

    ③ 在所有节点的etc/hadoop/slaves中,将准备移除的机器的IP删除

  2. 在NameNode节点机器上,执行命令bin/hdfs dfsadmin -refreshNodes,刷新DataNode

  3. 在ResourceManager节点机器上,执行命令bin/yarn rmadmin -refreshNodes,刷新NodeManager

  4. 在NameNode节点机器上,执行命令sbin/start-balancer.sh,实现集群数据的平衡(Blocks)

  5. 此时查看NameNode的前端管理页面,在Datanodes选项页面里,那些准备移除的节点机器的Admin State应该为Decommission In Progress。等待数据传输给其他的DataNode完毕,状态变为Decommission

  6. 在准备退役的机器上,分别执行命令sbin/yarn-daemon.sh stop nodemanager停止NodeManager,和命令sbin/hadoop-daemon.sh stop datanode停止DataNode

  7. 如果在etc/hadoop/hdfs-site.xml中配置了dfs.hosts,则还应删掉对应的退役机器的IP,并执行命令重新刷新DataNode和NodeManager

18、集群间的数据拷贝

 使用命令,bin/hadoop distcp hdfs://源服务机器IP:9000/?/? hdfs://目标服务机器IP:9000/?/?

 注意:数据拷贝的时候,会执行一个MapReduce任务,所以必须确保2个集群的相关资源(YARN等)都在正常运行中

19、数据的归档

 由于NameNode启动时会加载所有的元数据到内存当中,所以过多的小文件,会占用大量的内存资源。我们可以把这些小文件归档(压缩)起来,这样就能节省很多的内存空间

 数据归档本质上是一个MapReduce程序(确保YARN相关资源已启动)

 相关命令:

  1. 创建归档文件,bin/hadoop archive -archiveName 归档文件名.har -p 要归档的目录 归档文件输出目录

  2. 查看归档文件,bin/hadoop fs -ls -R har:///???/???.har

  3. 提取归档文件,其实就是复制归档文件里的内容,bin/hadoop fs -cp har:///???/归档文件名.har/归档文件 /目标路径

    注意:只能复制归档文件的内容,不能移动(mv),否则会报错:mv: `har:///???/???.har/???': Does not match target filesystem

20、快照

 快照相当于是对目录进行一个备份,它并不会立即复制所有的文件,而是先创建一个索引文件指向目标文件。当有新的文件写入时,它才会产生新的文件

 相关命令:

  1. 开启指定目录的快照功能,bin/hdfs dfsadmin -allowSnapshot /指定目录

  2. 创建指定目录的快照,bin/hdfs dfs -createSnapshot /指定目录 快照文件名称

    快照文件名称可以省略,默认的名称为/指定目录/.snapshot/s日期-时间.毫秒

  3. 重命名快照,bin/hdfs dfs -renameSnapshot /快照目录 旧名称 新名称

    注意:系统默认创建的快照名称是无法重命名的,会报错:renameSnapshot: Modification on a read-only snapshot is disallowed

  4. 展示当前用户下的所有的已开启快照功能的目录,bin/hdfs lsSnapshottableDir

  5. 比较两个快照目录的不同,bin/hdfs snapshotDiff /开启快照功能的目录 快照名称1 快照名称2

    快照名称可以使用.来代替,表示当前开启了快照功能的目录

    注意:比较结果是用右边的快照和左边的快照相比较

  6. 删除快照,bin/hdfs dfs -deleteSnapshot /开启快照功能的快照目录 快照名称

    注意快照目录和快照名称之间的空格

  7. 禁用指定目录的快照功能,bin/hdfs dfsadmin -disallowSnapshot /指定目录

    注意:禁用快照功能前,需要先删除当前目录的所有快照,否则报错:disallowSnapshot: The directory /???/??? has snapshot(s). Please redo the operation after removing all the snapshots.

 使用快照进行恢复,则使用bin/hadoop fs -cp /快照目录里的文件 /指定目录。注意不能使用移动(mv)命令,因为快照文件是只读的

21、回收站

 回收站功能默认是关闭的,需要在etc/hadoop/core-site.xml配置文件中,设置2个参数来开启它

<!-- 回收站内的文件的有效期,单位:分钟。默认为0,表示禁用回收站功能 -->
<property><name>fs.trash.interval</name><value>0</value>
</property>
<!--
检查回收站的周期,单位:分钟。该值要小于等于fs.trash.interval。如果为0,则设置为fs.trash.interval的值。
每当回收站运行的时候,它都会创建一个新的检查点,用于删除超过fs.trash.interval时间(文件有效期)之后的文件
-->
<property><name>fs.trash.checkpoint.interval</name><value>0</value>
</property>

 同时还要注意:默认拥有查看回收站的权限的用户名是dr.who,需要修改它为操作Hadoop集群的用户。否则访问NameNode的前端管理页面时会报错:Permission denied: user=dr.who, access=READ_EXECUTE, inode="/user":???:supergroup:drwx------

 在etc/hadoop/core-site.xml

<!-- 拥有查看HDFS Web页面(NameNode前端管理页面)的权限的用户名 -->
<property><name>hadoop.http.staticuser.user</name><value>dr.who</value>
</property>

 删除的文件目录,位于回收站的目录/user/执行Hadoop的用户名/.Trash/Current/???

 恢复回收站里的文件的方法是,将回收站里的文件移动出来,使用命令bin/hadoop fs -mv /回收站目录 /恢复目录。注意,如果移动文件夹,可能因为权限问题而无法查看

 删除回收站目录,可以使用命令bin/hadoop fs -rm -r -skipTrash /user/???。加上-skipTrash选项

Hadoop-5-HDFS相关推荐

  1. 安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法

    安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法 参考文章: (1)安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法 (2)https:// ...

  2. Hadoop基础-HDFS集群中大数据开发常用的命令总结

    Hadoop基础-HDFS集群中大数据开发常用的命令总结 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本盘博客仅仅列出了我们在实际生成环境中常用的hdfs命令,如果想要了解更多, ...

  3. Hadoop之HDFS面试知识复习

    Hadoop之HDFS面试知识复习 目录 HDFS的存储机制 secondary namenode工作机制 NameNode与SecondaryNameNode 的区别与联系? hdfs整体架构介绍 ...

  4. Hadoop之HDFS读写数据流程

    Hadoop之HDFS读写数据流程 目录 HDFS写数据流程 HDFS读数据流程 网络拓扑概念 机架感知 1. HDFS写数据流程 HDFS写数据流程,如下图 客户端通过Distributed Fil ...

  5. Hadoop之HDFS常用Shell命令

    Hadoop之HDFS常用Shell命令 启动Hadoop集群 sbin/start-dfs.shsbin/start-yarn.sh -help:输出这个命令参数 hadoop fs -help r ...

  6. Hadoop之HDFS概述

    Hadoop之HDFS概述 目录 HDFS产生背景 HDFS概念 HDFS优缺点 HDFS组成架构 1. HDFS产生背景 随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操 ...

  7. Hadoop之HDFS文件操作

    摘要:Hadoop之HDFS文件操作常有两种方式,命令行方式和JavaAPI方式.本文介绍如何利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件    命令行     Java API HD ...

  8. Spring boot项目整合Hadoop的HDFS

    由于最近需要使用Spring boot整合Hadoop的HDFS,但是在整合的过程遇到了很多问题,网上也没有现成教程,都是自己摸索出来的,配置了很久都没能把项目搭建出来,希望对大家有帮助. 使用Spr ...

  9. Hadoop点滴-HDFS命令行接口

    1.-help[cmd] 显示命令的帮助信息 ./hdfs dfs -help ls1 2.-ls(r) 显示当前目录下的所有文件 -R层层循出文件夹 ./hdfs dfs -ls /log/map ...

  10. Hadoop基础-Hdfs各个组件的运行原理介绍

    Hadoop基础-Hdfs各个组件的运行原理介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode工作原理(默认端口号:50070) 1>.什么是NameN ...

最新文章

  1. Python多阶段框架实现虚拟试衣间,超逼真!
  2. 主题模型(topic models)总结
  3. big endian and little endian
  4. Leetcode-5846.周赛 找到数组的中间位置
  5. JavaScript原生对象属性和方法详解——String对象
  6. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1091:求阶乘的和
  7. 图像处理之添加图像水印
  8. Android插件化开发之动态加载的类型
  9. 单片机与gsm通信c语言,gsm模块如何与单片机通信?
  10. Redis常见问题及其一些重点知识总结
  11. linux挂载磁盘阵列
  12. REVERSE-PRACTICE-BUUCTF-11
  13. linux同时安装python2和python3_linux-Centos7安装python3并与python2共存
  14. python—os模块、时间模块
  15. 有没有五金产品展开计算机软件,拆单软件功能介绍
  16. 方差分析的SPSS实现
  17. 一场无名的宿醉,失措了一夜的安然。
  18. 腾讯QQ空间穿越时光轴3D特效
  19. 〖Python接口自动化测试实战篇⑥〗- 接口抓包工具 Chrome 的使用
  20. 百胜图Barsetto智能胶囊咖啡机测评 始于颜值忠于便捷

热门文章

  1. 取消耳机孔的 4 年后,苹果居然把耳机卖到了四千块
  2. 用最速下降法求最优解
  3. python爬取凤凰新闻网_python爬取凤凰网站的新闻,及其链接地址,来源,时间和内容,用selenium自动化和requests处理数据...
  4. 【强化学习】竞争深度Q网络(Dueling DQN)求解倒立摆问题 + Pytorch代码实战
  5. mysql查询带序列号
  6. 阿米洛键盘使用手册2021-02-22
  7. 从端到云——工业物联网项目全栈快速开发
  8. 如何通过企业微信便捷访问华为云、阿里云?
  9. 微信小程序Day2学习笔记
  10. localtime和localtime_r