Hadoop-5-HDFS
Hadoop-5-HDFS
1、概述
Hadoop Distributed File System (HDFS™),是一种分布式文件管理系统,用于管理多个机器上的文件
它主要用于存储文件,通过目录树结构来定位文件的位置。适合一次写入,多次读出的场景,不支持文件的修改,所以用它做数据的分析,而不是当作网盘
2、优缺点
【1】优点
- 高容错性。容错性体现在数据保存到多个副本上(DataNode),并且可以通过增加副本的数量(replication),来提高这种特性。并且当一个副本的数据丢失后,它还可以自动恢复
- 大数据量。一是处理数据的量级,可以达到TB、PB的级别。二是文件的数量,能够处理百万以上的规模
- 流式数据。一次写入,多次写出。只能追加,不能修改。保证数据的一致性
- 高可用性。可以将数据节点部署到多个廉价机器上
【2】缺点
- 不能实现低延迟的数据访问。无法做到毫秒级的海量数据存储
- 无法高效地存储多个小文件。处理大量的小文件的存储、目录结构以及块信息,会占用NameNode的大量内存资源。此外小文件存储时的寻址时间会超过其读取时间,这违反了HDFS设计的初衷
- 不能并发写入和随机修改。对于一个文件,在同一时间内只能有一个写入,不允许多个线程同时写入。仅支持文件的追加,不支持文件的修改
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】准备环境
- Java
- Maven
- 和服务端一致的Hadoop,并解压缩到无中文目录
- 下载winutils,并将hadoop-2.8.3/bin目录里的
winutils.exe
复制到解压缩后的hadoop的bin目录当中 - 配置环境变量:
HADOOP_HOME
到解压缩目录 - 打开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
对象的静态方法来获取
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();}} }
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();}} }
【推荐】
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】文件上传
- 客户端请求NameNode,是否可以进行文件的上传
- 当客户端收到可以上传的响应后,依次顺序上传block0(0 ~ 128MB),block1(128MB ~ 256MB)到DataNode
- 获取所有需要上传的DataNode的节点信息,依次请求建立传输通道
- 收到DataNode响应,传输通道建立完毕,开始传输数据
【2】文件下载
- 客户端请求NameNode,获取block信息
- 收到NameNode返回的元数据信息,请求对应的DataNode,获取所需的block数据
- 合并所有的block数据为一个完整的数据,最终得到完整数据
9、NameNode和SecondaryNameNode工作机制
【1】NameNode启动时的工作机制
- NameNode将镜像文件(FsImage)加载到内存中
- NameNode将编辑日志(EditLog)加载到内存中
- 保存检查点位置(checkpoint)
- 进入安全模式(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运行时的工作机制
- 请求NameNode是否需要检查点(Checkpoint)
- 如果需要Checkpoint,则执行
- 复制NameNode的编辑日志(edits),包括已经执行完毕的(例如:edits_0000000000000000001-0000000000000000002)以及正在执行的(例如:edits_inprogress_0000000000000010453)
- 加载到内存中,合并生成新的镜像文件(fsimage.checkpoint)
- 复制镜像文件(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】手动方式
- 模拟NameNode故障,
jps
查看NameNode的进程号,通过命令kill -9 NameNode的进程ID
强制停止NameNode - 首先删除
???/dfs/name
目录里的所有文件 - 使用
scp
复制SecondaryNameNode的???/dfs/namesecondary
目录里的所有文件到NameNode的???/dfs/name
目录里,并删除复制后的name目录里的in_use.lock
文件 - 启动NameNode,
sbin/hadoop-daemon.sh start namenode
- 查看是否可以访问NameNode的前端管理页面,并测试HDFS的文件上传和文件下载
【2】命令方式
模拟NameNode故障,
jps
查看NameNode的进程号,通过命令kill -9 NameNode的进程ID
强制停止NameNode修改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>
使用
scp
复制SecondaryNameNode的???/dfs/namesecondary
目录到NameNode的???/dfs
目录下,和???/dfs/name
平级即可。并删除复制后的namesecondary目录里的in_use.lock
文件删除
???/dfs/name
目录里的所有文件执行导入检查点数据命令,
bin/hdfs namenode -importCheckpoint
执行命令后,会发现NameNode被启动起来。命令执行过程较长,如果此时访问NameNode的前端管理页面,会发现提示信息:
Upgrade in progress. Not yet finalized.
当看到process的信息后,就可以Ctrl + C停止命令了
启动NameNode,
sbin/hadoop-daemon.sh start namenode
查看是否可以访问NameNode的前端管理页面,并测试HDFS的文件上传和文件下载
13、安全模式(Safemode)
【1】概念
当NameNode在刚启动时,会进入安全模式,此时HDFS对于客户端来说是只读的
在系统正常运行期间,NameNode会在内存中保存所有的块位置的映射信息。而在安全模式下,每个DataNode会向NameNode发送最新的块列表信息。NameNode了解的块位置信息越多,它可越高效地运行文件系统
一旦满足最小副本条件,NameNode会在30秒后退出安全模式。最小副本条件是指,在整个文件系统当中,99.9%的块满足最小副本级别,最小副本级别可以通过etc/hadoop/hdfs-site.xml
的dfs.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工作机制
- DataNode启动后,向NameNode发起注册
- 注册成功后,每隔1个小时上传一次所有块的位置信息
- NameNode每隔3秒钟(可配置),执行一次心跳检测,DataNode接收到心跳检测并返回给NameNode发来的命令信息
- 如果超过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】动态新增节点
准备好新的机器,配置好静态IP,host和防火墙,以及Java运行环境和环境变量,并新建执行Hadoop的用户
使用
scp
命令复制NameNode服务节点的Hadoop目录到新的机器上配置好其他节点的host
使用命令
ssh-copy-id 用户名@新机器host
,为NameNode节点和ResourceManager节点,创建新的机器的免密登录① 在所有节点的
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添加到里面在NameNode节点机器上,执行命令
bin/hdfs dfsadmin -refreshNodes
,刷新DataNode在ResourceManager节点机器上,执行命令
bin/yarn rmadmin -refreshNodes
,刷新NodeManager在NameNode节点机器上,执行命令
sbin/start-balancer.sh
,实现集群数据的平衡(Blocks)此时查看NameNode的前端管理页面,在Datanodes选项页面里,应该新增了一个DataNode节点,其Admin State为Dead
到新机器上,分别执行命令
sbin/hadoop-daemon.sh start datanode
启动DataNode,和命令sbin/yarn-daemon.sh start nodemanager
启动NodeManager再回到NameNode的前端管理页面,刷新可以看到,新节点的Admin State为In Service
上传文件和下载文件,进行测试
【2】动态移除节点
① 在所有节点的
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删除在NameNode节点机器上,执行命令
bin/hdfs dfsadmin -refreshNodes
,刷新DataNode在ResourceManager节点机器上,执行命令
bin/yarn rmadmin -refreshNodes
,刷新NodeManager在NameNode节点机器上,执行命令
sbin/start-balancer.sh
,实现集群数据的平衡(Blocks)此时查看NameNode的前端管理页面,在Datanodes选项页面里,那些准备移除的节点机器的Admin State应该为Decommission In Progress。等待数据传输给其他的DataNode完毕,状态变为Decommission
在准备退役的机器上,分别执行命令
sbin/yarn-daemon.sh stop nodemanager
停止NodeManager,和命令sbin/hadoop-daemon.sh stop datanode
停止DataNode如果在
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相关资源已启动)
相关命令:
创建归档文件,
bin/hadoop archive -archiveName 归档文件名.har -p 要归档的目录 归档文件输出目录
查看归档文件,
bin/hadoop fs -ls -R har:///???/???.har
提取归档文件,其实就是复制归档文件里的内容,
bin/hadoop fs -cp har:///???/归档文件名.har/归档文件 /目标路径
注意:只能复制归档文件的内容,不能移动(mv),否则会报错:
mv: `har:///???/???.har/???': Does not match target filesystem
20、快照
快照相当于是对目录进行一个备份,它并不会立即复制所有的文件,而是先创建一个索引文件指向目标文件。当有新的文件写入时,它才会产生新的文件
相关命令:
开启指定目录的快照功能,
bin/hdfs dfsadmin -allowSnapshot /指定目录
创建指定目录的快照,
bin/hdfs dfs -createSnapshot /指定目录 快照文件名称
快照文件名称可以省略,默认的名称为
/指定目录/.snapshot/s日期-时间.毫秒
重命名快照,
bin/hdfs dfs -renameSnapshot /快照目录 旧名称 新名称
注意:系统默认创建的快照名称是无法重命名的,会报错:
renameSnapshot: Modification on a read-only snapshot is disallowed
展示当前用户下的所有的已开启快照功能的目录,
bin/hdfs lsSnapshottableDir
比较两个快照目录的不同,
bin/hdfs snapshotDiff /开启快照功能的目录 快照名称1 快照名称2
快照名称可以使用
.
来代替,表示当前开启了快照功能的目录注意:比较结果是用右边的快照和左边的快照相比较
删除快照,
bin/hdfs dfs -deleteSnapshot /开启快照功能的快照目录 快照名称
注意快照目录和快照名称之间的空格
禁用指定目录的快照功能,
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相关推荐
- 安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法
安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法 参考文章: (1)安装完Hadoop之后,命令行输入hadoop或hdfs却找不到命令的解决方法 (2)https:// ...
- Hadoop基础-HDFS集群中大数据开发常用的命令总结
Hadoop基础-HDFS集群中大数据开发常用的命令总结 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本盘博客仅仅列出了我们在实际生成环境中常用的hdfs命令,如果想要了解更多, ...
- Hadoop之HDFS面试知识复习
Hadoop之HDFS面试知识复习 目录 HDFS的存储机制 secondary namenode工作机制 NameNode与SecondaryNameNode 的区别与联系? hdfs整体架构介绍 ...
- Hadoop之HDFS读写数据流程
Hadoop之HDFS读写数据流程 目录 HDFS写数据流程 HDFS读数据流程 网络拓扑概念 机架感知 1. HDFS写数据流程 HDFS写数据流程,如下图 客户端通过Distributed Fil ...
- Hadoop之HDFS常用Shell命令
Hadoop之HDFS常用Shell命令 启动Hadoop集群 sbin/start-dfs.shsbin/start-yarn.sh -help:输出这个命令参数 hadoop fs -help r ...
- Hadoop之HDFS概述
Hadoop之HDFS概述 目录 HDFS产生背景 HDFS概念 HDFS优缺点 HDFS组成架构 1. HDFS产生背景 随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操 ...
- Hadoop之HDFS文件操作
摘要:Hadoop之HDFS文件操作常有两种方式,命令行方式和JavaAPI方式.本文介绍如何利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件 命令行 Java API HD ...
- Spring boot项目整合Hadoop的HDFS
由于最近需要使用Spring boot整合Hadoop的HDFS,但是在整合的过程遇到了很多问题,网上也没有现成教程,都是自己摸索出来的,配置了很久都没能把项目搭建出来,希望对大家有帮助. 使用Spr ...
- Hadoop点滴-HDFS命令行接口
1.-help[cmd] 显示命令的帮助信息 ./hdfs dfs -help ls1 2.-ls(r) 显示当前目录下的所有文件 -R层层循出文件夹 ./hdfs dfs -ls /log/map ...
- Hadoop基础-Hdfs各个组件的运行原理介绍
Hadoop基础-Hdfs各个组件的运行原理介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode工作原理(默认端口号:50070) 1>.什么是NameN ...
最新文章
- Python多阶段框架实现虚拟试衣间,超逼真!
- 主题模型(topic models)总结
- big endian and little endian
- Leetcode-5846.周赛 找到数组的中间位置
- JavaScript原生对象属性和方法详解——String对象
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1091:求阶乘的和
- 图像处理之添加图像水印
- Android插件化开发之动态加载的类型
- 单片机与gsm通信c语言,gsm模块如何与单片机通信?
- Redis常见问题及其一些重点知识总结
- linux挂载磁盘阵列
- REVERSE-PRACTICE-BUUCTF-11
- linux同时安装python2和python3_linux-Centos7安装python3并与python2共存
- python—os模块、时间模块
- 有没有五金产品展开计算机软件,拆单软件功能介绍
- 方差分析的SPSS实现
- 一场无名的宿醉,失措了一夜的安然。
- 腾讯QQ空间穿越时光轴3D特效
- 〖Python接口自动化测试实战篇⑥〗- 接口抓包工具 Chrome 的使用
- 百胜图Barsetto智能胶囊咖啡机测评 始于颜值忠于便捷
热门文章
- 取消耳机孔的 4 年后,苹果居然把耳机卖到了四千块
- 用最速下降法求最优解
- python爬取凤凰新闻网_python爬取凤凰网站的新闻,及其链接地址,来源,时间和内容,用selenium自动化和requests处理数据...
- 【强化学习】竞争深度Q网络(Dueling DQN)求解倒立摆问题 + Pytorch代码实战
- mysql查询带序列号
- 阿米洛键盘使用手册2021-02-22
- 从端到云——工业物联网项目全栈快速开发
- 如何通过企业微信便捷访问华为云、阿里云?
- 微信小程序Day2学习笔记
- localtime和localtime_r