概述
HDFS (Hadoop Distributed File System), 它是一个文件系统, 用于存储文件, 通过目录树来定位文件 ; 其次, 它是分布式的, 由很多服务器联合起来实现其功能, 集群中的服务器有各自的角色。
使用场景 : 适合一次写入, 多次读出的场景, 且不支持文件的修改。
优点
高容错性
适合处理大数据
可构建在廉价机器之上
缺点
不适合低延时数据访问
无法高效的对大量小文件进行存储
不支持高并发写入、文件随机修改
组成架构
NameNode : 就是Master, 是一个管理者。
1. 管理HDFS的名称空间 ;
2. 配置副本策略 ;
3. 管理数据块 (Block) 映射信息 ;
4. 处理客户端读写请求。
DataNode : 就是Slave, NameNode下达命令, DataNode执行实际的操作。
1. 存储实际的数据块 ;
2. 执行数据块的读写操作。
Client : 就是客户端。
1. 文件切分。文件上传HDFS时, Client将文件切分成一个一个的Block, 然后进行上传 ;
2. 与NameNode交互, 获取文件的位置信息 ;
3. 与DataNode交互, 读取或者写入数据 ;
4. Client提供一些命令来管理HDFS, 比如NameNode格式化 ;
5. Client通过一些命令来访问HDFS, 比如对HDFS增删改操作。
SecondaryNameNode : 并非NameNode的热备。当NameNode挂掉时, 它并不能替换NameNode。
1. 辅助NameNode, 分担其工作量, 比如定期合并Fsimage和Edits, 并推送给NameNode ;
2. 在紧急情况下, 可辅助恢复NameNode。
文件块大小
HDFS中的文件在物理上是分块存储 (Block), 块的大小可以通过配置参数(dfs.blocksize)来规定, 默认Hadoop1.x版本中是64M ; Hadoop2.x版本中是128M。
如果HDFS的块设置太小, 则会增加寻址时间, 降低效率。
如果HDFS的块设置太大, 则从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间, 导致程序在处理该块数据时, 会非常慢。
HDFS块大小的设置主要取决于磁盘传输速率。
HDFS的Shell操作
基本语法 : bin/hadoop fs 具体命令 或 bin/hdfs dfs 具体命令
- 启动Hadoop集群 在hadoop安装目录下执行
[user01@node01 hadoop-3.1.3]$ sbin/start-dfs.sh [user01@node02 hadoop-3.1.3]$ sbin/start-yarn.sh
- 输出该命令参数 -help
[user01@node01 hadoop-3.1.3]$ hdfs dfs -help rm
- 显示目录信息 -ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> …]
[user01@node01 hadoop-3.1.3]$ hdfs dfs -ls /
- 创建目录 -mkdir [-p] <path> …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -mkdir -p /test
- 从本地剪切到HDFS -moveFromLocal <localsrc> … <dst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -moveFromLocal ./test.txt /test/test.txt
- 从本地拷贝到HDFS -copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> … <dst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -copyFromLocal ./test2.txt /test/test2.txt
- 从本地拷贝到HDFS -put [-f] [-p] [-l] [-d] <localsrc> … <dst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -put ./test4.txt /test/
- 从HDFS下载文件到本地 -get [-f] [-p] [-ignoreCrc] [-crc] <src> … <localdst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -get /test/test.txt ./
- 合并下载多个文件 -getmerge [-nl] [-skip-empty-file] <src> <localdst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -getmerge /test/* ./test3.txt
- 从HDFS拷贝到本地 -copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> … <localdst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -copyToLocal /test/test2.txt ./
- 在HDFS中, 从一个路径拷贝到另一个路径 -cp [-f] [-p | -p[topax]] [-d] <src> … <dst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -cp /test/test2.txt /test2/test3.txt
- 在HDFS中, 移动文件 -mv …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -mv /test/test.txt /test2/
- 追加一个文件到HDFS已经存在的文件末尾 -appendToFile <localsrc> … <dst>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -appendToFile ./test.txt /test/test.txt
- 显示文件内容 -cat [-ignoreCrc] <src> …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -cat /test/test.txt
- 修改文件所属权限 -chgrp -chmod -chown
[user01@node01 hadoop-3.1.3]$ hdfs dfs -chmod 777 /test/test.txt [user01@node01 hadoop-3.1.3]$ hfds dfs -chown user02:user02 /test/test.txt [user01@node01 hadoop-3.1.3]$ hdfs dfs -chgrp group01 /test/test.txt
- 显示一个文件的末尾 -tail [-f] [-s ] <file>
[user01@node01 hadoop-3.1.3]$ hdfs dfs -tail /test/test4.txt
- 删除文件或文件夹 -rm [-f] [-r|-R] [-skipTrash] [-safely] <src> …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -rm /test/test.txt
- 删除空目录 -rmdir [–ignore-fail-on-non-empty] <dir> …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -rmdir /test3
- 统计文件夹的大小信息 -du [-s] [-h] [-v] [-x] <path> …
-s 显示所有总大小 -h 以人类可读的方式格式化文件的大小,而不是字节数 -v 选项显示标题行 -x 不包括快照
[user01@node01 hadoop-3.1.3]$ hdfs dfs -du -s -h /test
- 设置HDFS中文件的副本数(最终取决于节点数量) -setrep [-R] [-w] <rep> <path> …
[user01@node01 hadoop-3.1.3]$ hdfs dfs -setrep 5 /test/test.txt
HDFS客户端操作
首先, 需在Windows中配置Hadoop的环境变量
- 创建一个Maven工程
- 导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
- 添加日志 : 在src/main/resources目录下, 新建一个文件, 命名为 “log4j2.xml” , 在文件中填入 ↓
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
<Appenders>
<!-- 类型名为Console,名称为必须属性 -->
<Appender type="Console" name="STDOUT">
<!-- 布局为PatternLayout的方式,
输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
<Layout type="PatternLayout"
pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
</Appender>
</Appenders>
<Loggers>
<!-- 可加性为false -->
<Logger name="test" level="info" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<!-- root loggerConfig设置 -->
<Root level="info">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
HDFS文件下载
@Test
public void testCopyToLocal() throws URISyntaxException, IOException, InterruptedException {
//1. 获取文件系统
URI uri = new URI("hdfs://LIFE:9820");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf, "atguigu");
//2. 下载操作
// boolean delSrc 指是否将原文件删除
// Path src 指要下载的文件路径
// Path dst 指将文件下载到的路径
// boolean useRawLocalFileSystem 是否开启文件校验
fileSystem.copyToLocalFile(false, new Path("/test.txt"),
new Path("e:/test.txt"), true);
//3. 关闭资源
fileSystem.close();
}
HDFS文件夹删除
@Test
public void testDelete() throws URISyntaxException, IOException, InterruptedException {
//1. 获取文件系统
URI uri = new URI("hdfs://LIFE:9820");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf, "atguigu");
//2. 删除操作
fileSystem.delete(new Path("/test/test.txt"), true);
//3. 关闭资源
fileSystem.close();
}
HDFS文件名更改/移动
@Test
public void testRename() throws URISyntaxException, IOException, InterruptedException {
//1. 获取文件系统
URI uri = new URI("hdfs://LIFE:9820");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf, "atguigu");
//2. 修改文件名
fileSystem.rename(new Path("/test/test.txt"), new Path("/test/test4.txt"));
//3. 关闭资源
fileSystem.close();
}
HDFS文件详情查看
@Test
public void testListFiles() throws URISyntaxException, IOException, InterruptedException {
//1. 获取文件系统
URI uri = new URI("hdfs://LIFE:9820");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf, "atguigu");
//2. 获取文件详情
RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true);
// 输出详情
while (listFiles.hasNext()) {
LocatedFileStatus status = listFiles.next();
// 文件名
System.out.println(status.getPath().getName());
// 长度
System.out.println(status.getLen());
// 权限
System.out.println(status.getPermission());
// 分组
System.out.println(status.getGroup());
// 获取存储的块信息
BlockLocation[] blockLocations = status.getBlockLocations();
for (BlockLocation blockLocation : blockLocations) {
// 获取块存储的主机节点
String[] hosts = blockLocation.getHosts();
for (String host : hosts) {
System.out.println(host);
}
}
System.out.println("------------- 分割线 ---------------");
}
//3. 关闭资源
fileSystem.close();
}
HDFS文件和文件夹判断
@Test
public void testListStatus() throws URISyntaxException, IOException, InterruptedException {
//1. 获取文件系统
URI uri = new URI("hdfs://LIFE:9820");
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(uri, conf, "atguigu");
//2. 判断是文件还是文件夹
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
for (FileStatus fileStatus : fileStatuses) {
// 如果是文件
if(fileStatus.isFile()){
System.out.println("file:" + fileStatus.getPath().getName());
}else{
System.out.println("dire:" + fileStatus.getPath().getName());
}
}
//3. 关闭资源
fileSystem.close();
}
HDFS的数据流
HDFS写数据流程
- 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
- NameNode返回是否可以上传。
- 客户端请求第一个 Block上传到哪几个DataNode服务器上。
- NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
- 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
- dn1、dn2、dn3逐级应答客户端。
- 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
- 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
网络拓扑 - 节点距离计算
- 在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。这个最近距离为 :
两个节点到达最近的共同祖先的距离总和。
机架感知
For the common case, when the replication factor is three, HDFS’s
placement policy is to put one replica on the local machine if the
writer is on a datanode, otherwise on a random datanode, another
replica on a node in a different (remote) rack, and the last on a
different node in the same remote rack.对于常见情况,当副本数为3时,HDFS的放置策略是,如果writer位于datanode上,则将一个副本放在本地机器上,否则将另一个副本放在另一个(远程)机架上的节点上。
- Hadoop3.1.3副本节点选择
第一个副本在Client所处的节点上。如果客户端在集群外, 则随机选择一个。
第二个副本在另一个机架的随机一个节点。
第三个副本在第二个副本所在机架的随机节点。
HDFS的读数据流程
- 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
- 挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
- DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
- 客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
NameNode和SecondaryNameNode工作机制
由于NameNode的元数据是存储在内存中的, 故存在元数据丢失的风险, 因此会在磁盘中备份元数据的FsImage(镜像文件)。当内存中的元数据更新时, 如果同时更新FsImage, 就会导致效率过低, 但如果不更新, 就会发生数据一致性问题, 一旦NameNode节点断电, 就会产生数据丢失。因此, 引入Edits(编辑日志)文件 (只作追加操作, 效率很高) , 每当元数据有更新或者添加元数据时, 修改内存中的元数据并追加到Edits中。但是随着时间延长, 会导致Edits文件数据过大, 效率降低, 而且一旦断电, 恢复元数据需要的时间过长。因此, 需要定期进行FsImage和Edits的合并, 如果这个操作由NameNode节点完成, 则会导致NameNode节点压力过大, 工作效率降低, 因此, 引入一个新的节点SecondaryNameNode, 专门用于对FsImage和Edits的合并。
- 第一阶段 : NameNode启动
- 第一次启动NameNode格式化后, 创建FsImage和Edits文件。如果不是第一次启动, 直接加载编辑日志和镜像文件到内存并生成一个空的edits.inprogress文件。
- 客户端对元数据进行增删改的请求。
- NameNode记录操作日志, 并更新滚动Edits。
- NameNode在内存中对元数据进行增删改。
- 第二阶段 : SecondaryNameNode工作
- SecondaryNameNode询问NameNode是否需要CheckPoint。带回NameNode是否检查的结果。
– 触发CheckPoint需要满足两个条件中的任意一个, 到大定时时间 或 Edits中数据量到达指定峰值。 - SecondaryNameNode请求执行CheckPoint。
- NameNode滚动正在写的Edits日志。
- 将滚动前的编辑日志和镜像文件拷贝到SecondaryNameNode。
- SecondaryNameNode加载 编辑日志和镜像文件到内存, 并合并。
- 生成新的镜像文件fsimage.chkpoint。
- 拷贝fsimage.chkpoint到NameNode。
- NameNode将fsimage.chkpoint重命名为fsimage。
- SecondaryNameNode询问NameNode是否需要CheckPoint。带回NameNode是否检查的结果。
NameNode被格式化后, 将在$HADOOP_HOME/data/tmp/dfs/name/current目录下产生如下文件
fsimage_00000000000000000000
fsimage_00000000000000000000.md5
seen_txid
VERSION
- FsImage : HDFS文件系统元数据的一个永久性检查点, 其中包含HDFS文件系统的所有目录文件iNode的序列化信息。
- Edits : 存放HDFS文件系统的所有的增删改操作。
- seen_txid文件保存的是一个数字, 就是最后一个edits_的数字。
- oiv 查看FsImage文件
hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径
hdfs oiv -p XML -i $HADOOP_HOME/data/tmp/dfs/name/current/fsimage_000000000000000025 -o $HADOOP_HOME/fsimage.xml
- oev 查看Edits文件
hdfs oev -p 文件类型 -i 编制日志 -o 转换后文件输出路径
hdfs oev -p XML -i $HADOOP_HOME/data/tmp/dfs/name/current/edits_000000000000000000012_00000000000000000013 -o $HADOOP_HOME/edits.xml
- CheckPoint时间设置
通常情况下, SecondaryNameNode每一小时执行一次。
[hdfs-default.xml]
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
一分钟检查一次操作次数, 当操作次数达到1百万时, SecondaryNameNode执行一次。
<property>
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
<description>操作动作次数</description>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >
集群安全模式
1、NameNode启动
NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的Fsimage文件和一个空的编辑日志。此时,NameNode开始监听DataNode请求。这个过程期间,NameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。
2、DataNode启动
系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统的正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,即可高效运行文件系统。
3、安全模式退出判断
如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。
查看安全模式状态 bin/hdfs dfsadmin -safemode get
进入安全模式状态 bin/hdfs dfsadmin -safemode enter
离开安全模式状态 bin/hdfs dfsadmin -safemode leave
等待安全模式状态 bin/hdfs dfsadmin -safemode wait
NameNode多目录配置
- NameNode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性
- 具体配置如下
(1)在hdfs-site.xml文件中修改如下内容
(2)停止集群,删除data和logs中所有数据。<property> <name>dfs.namenode.name.dir</name> <value>file:///${hadoop.tmp.dir}/name1,file:///${hadoop.tmp.dir}/name2</value> </property>
(3)格式化集群并启动。[user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/ [user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/ [user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/
[user01@node01 hadoop-3.1.3]$ bin/hdfs namenode –format [user01@node01 hadoop-3.1.3]$ sbin/start-dfs.sh
DataNode工作机制
- 一个数据块在DataNode上以文件形式存储在磁盘上, 包括两个文件, 一个是数据本身, 一个是元数据, 包括数据块的长度, 块数据的校验和, 以及时间戳。
- DataNode启动后会想NameNode注册, 通过后, 周期性(1小时)的向NameNode上报所有块信息。
- 每3秒钟心跳一次, 心跳返回结果带有NameNode的命令。如果超过10分钟NameNode没有收到某个DataNode的心跳, 则认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器。
DataNode节点保证数据完整性的方法 ---- 校验和 - 当DataNode读取Block时, 它会计算CheckSum(校验和)。
- 如果计算后的CheckSum, 与Block创建时的值不一样, 说明Block已经损坏。
- Client读取其他DataNode上的Block。
- 常见的校验和算法crc(32)、md5(128)、sha1(160)
- DataNode在其文件创建后周期性验证CheckSum。
DataNode掉线时限参数设置
1、DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信
2、NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
3、HDFS默认的超时时长为10分钟+30秒。
4、如果定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut = 2 × dfs.namenode.heartbeat.recheck-interval + 10 × dfs.heartbeat.interval。
而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。<property> <name>dfs.namenode.heartbeat.recheck-interval</name> <value>300000</value> </property> <property> <name>dfs.heartbeat.interval</name> <value>3</value> </property>
服役新DataNode节点
- 首先准备新DataNode节点。
在当前DataNode基础上克隆一台新节点, 修改IP地址和主机名称。
删除原来HDFS文件系统留存的文件($HADOOP_HOME/data和log)
source /etc/profile - 在新节点启动DataNode, 即可关联到集群
如果数据不均衡, 可以用命令实现集群的再平衡。[user01@node04 hadoop-3.1.3]$ hdfs --daemon start datanode [user01@node04 hadoop-3.1.3]$ yarn --daemon start nodemanager
[user01@node01 hadoop-3.1.3]$ sbin/start-balancer.sh
退役旧DataNode节点
白名单用于确定允许访问NameNode的DataNode节点,内容配置一般与workers文件内容一致。 黑名单用于在集群运行过程中退役DataNode节点。
- 添加白名单 和 黑名单
添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被直接退出。
添加到黑名单的主机节点,不允许访问NameNode,会在数据迁移后退出。
(1) 在NameNode的$HADOOP_HOME/etc/hadoop目录下创建whitelist和blacklist
(2) 在whitelist中添加当前集群正常工作的节点, 黑名单暂时为空。
(3) 在NameNode的hdfs-site.xml配置文件中增加dfs.hosts配置node01 node02 node03 node04
(4) 将hdfs-site.xml配置文件分发至所有DataNode节点<property> <name>dfs.hosts</name> <value>/opt/module/hadoop-3.1.3/etc/hadoop/whitelist</value> </property> <property> <name>dfs.hosts.exclude</name> <value>/opt/module/hadoop-3.1.3/etc/hadoop/blacklist</value> </property>
(5) 重新启动集群 - 黑名单退役 : 会有数据迁移 [推荐]
(1) 编辑blacklist文件, 添加要退役的DataNode节点。
(2) 刷新NameNode和NodeManager状态node04
hdfs dfsadmin -refreshNodes yarn dfsadmin -refreshNodes
- 白名单退役 : 直接抛弃节点, 没有数据迁移[不推荐]
(1) 编译whitelist文件, 将node04删除, 保留正常节点。
(2) 刷新NameNodehdfs dfsadmin -refreshNodes
DataNode多目录配置
- DataNode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本
- 具体配置如下
(1)在hdfs-site.xml中修改如下内容:
(2)停止集群,删除data和logs中所有数据。<property> <name>dfs.datanode.data.dir</name> <value>file:///${hadoop.tmp.dir}/data1,file:///${hadoop.tmp.dir}/data2</value> </property>
(3)格式化集群并启动。[user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/ [user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/ [user01@node01 hadoop-3.1.3]$ rm -rf data/ logs/
[user01@node01 hadoop-3.1.3]$ bin/hdfs namenode –format [user01@node01 hadoop-3.1.3]$ sbin/start-dfs.sh
HDFS小文件存档
一个文件块会占用NameNode150字节的内存。当HDFS中存入大量小文件时, 磁盘存储效率降低, 且会耗尽NameNode大量内存。
解决方法一 : 采用har归档方式,将小文件归档
HDFS存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少NameNode内存使用的同时,允许对文件进行透明的访问。具体说来,HDFS存档文件对内还是一个一个独立文件,对NameNode而言却是一个整体,减少了NameNode的内存。
- 需要启动yarn进程
- 归档文件
把/user/atguigu/input目录里面的所有文件归档成一个叫input.har的归档文件,并把归档后文件存储到/user/atguigu/output路径下。
[use01@node01 hadoop-3.1.3]$ bin/hadoop archive -archiveName input.har –p /user/input /user/output - 查看归档文件
[use01@node01 hadoop-3.1.3]$ hadoop fs -lsr /user/output/input.har
[use01@node01 hadoop-3.1.3]$ hadoop fs -lsr har:///user/output/input.har - 解归档文件
[use01@node01 hadoop-3.1.3]$ hadoop fs -cp har:/// user/output/input.har/* /user/test
解决方法二 : 采用CombineTextInputFormat
未完…
解决方法三 : 开启JVM重用
如果没有小文件,不要开启JVM重用,因为会一直占用使用到的task卡槽,直到任务完成才释放。
JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间
未完…<property> <name>mapreduce.job.jvm.numtasks</name> <value>10</value> <description>How many tasks to run per jvm,if set to -1 ,there is no limit</description> </property>