hdfs集群如何搭建,怎么避免小文件,怎么往hdfs集群上传文件(关于这类问题都有涉及)
- 官网给出的介绍
The Hadoop Distributed File System (HDFS) is a distributed file system designed to run on commodity hardware. It has many similarities with existing distributed file systems. However, the differences from other distributed file systems are significant. HDFS is highly fault-tolerant and is designed to be deployed on low-cost hardware. HDFS provides high throughput access to application data and is suitable for applications that have large data sets. HDFS relaxes a few POSIX requirements to enable streaming access to file system data. HDFS was originally built as infrastructure for the Apache Nutch web search engine project. HDFS is part of the Apache Hadoop Core project
== Hadoop分布式文件系统(HDFS)是一种旨在在商品硬件上运行的分布式文件系统。它与现有的分布式文件系统有许多相似之处。但是,与其他分布式文件系统的区别很明显。HDFS具有高度的容错能力,旨在部署在低成本硬件上。HDFS提供对应用程序数据的高吞吐量访问,并且适用于具有大数据集的应用程序。HDFS放宽了一些POSIX要求,以实现对文件系统数据的流式访问。HDFS最初是作为Apache Nutch Web搜索引擎项目的基础结构而构建的。
前言
一提起大数据,首先想到的是它海量的数据,数据存的下,不丢失,方便管理是大数据存储组件最基本的要求,本篇基于这些看似基本的要求展开。
假设我们有1T的数据需要存储,那么按照常规手段我们把这整个数据存在一台机器上进行存储,如果我们需要找到某一个文件那么就需要很长的寻址时间,那么按照现在的大数据存储技术,我们将这1T的数据分别放在100台机器上,那么寻址时间大大减少,那么你会想“每台机器只放这一部分的数据肯定是浪费空间了”,那么hdfs将剩余部分也同样存放一整个文件的部分数据,这也就牵扯出hdfs块的概念,这样又牵扯出了一个问题,存放整个数据的节点增加了,那么难免出现一个节点出现故障导致数据丢失的情况等等一些列问题。
本篇先建立一些组件的概念,然后再围绕这些问题展开。本篇文章结构:
1、是什么,有什么特点;(fsimage,edits文件长什么样子)
2、有什么作用,它该怎么用;(配置过程,上传文件)
3、它的核心问题;(HA模式,四大机制,负载均衡,小文件问题)
一、是什么
- 背景
随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。The Hadoop Distributed File System (HDFS);
- 是什么/有什么特点
- 提供对应用程序数据的高吞吐量访问的分布式文件系统。可存储PB级别数据
- HDFS具有很高的容错能力,被设计为部署在低成本的硬件上。HDFS提供了对应用程序数据的高吞吐量访问,适用于具有大型数据集的应用程序。
- HDFS放松了简便操作系统的一些要求,以支持对文件系统数据的流访问。HDFS更多的是为批处理而设计,而不是用户交互使用。重点是数据访问的高吞吐量,而不是低延迟的数据访问。对于批处理的设计而言寻址时间是它的一个瓶颈
- 文件一旦创建、写入和关闭,除了追加和截断之外,不需要更改。支持将内容附加到文件末尾,但不能在任意点更新。这种假设简化了数据一致性问题,并支持高吞吐量数据访问。MapReduce应用程序或网络爬虫应用程序非常适合这个模型。
- 无法高效的对大量小文件进行存储
5.1 存储大量小文件的话,它会占用 NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,因为NameNode的内存总是有限的。(一个文件大概占150字节的内存)
5.2 小文件存储的寻道时间会超过读取时间,它违反了HDFS的设计目标。
- 架构
向hdfs集群上传一个256M大的文件,整个流程
- 文字归纳如下
(1) Client向NameNode节点发出请求;
(2) NameNode向Client返回可以存数据的DataNode列表host1,host2,host3;
(3) clint将该文件分成两块,大小分别为block1,block2;
(4) 客户端向wq1发送block1,发送过程是流式写入,此时默认副本数为2,则host1把block1发送给host2,host2传给host3;
(5) dataNode告诉client自己block1已经传完,同时这三个datanode节点告诉NameNode自己传完了block1;
(6) block2按照同样的方式完成数据的传递.
- 各个部分的含义
-
Client:客户端。如果使用JavaAPI对集群操作那么这台电脑就是客户端。
1.1文件切分。文件上传 HDFS 的时候,Client 将文件切分成一个一个的Block,然后进行存储。
1.2与NameNode交互,获取文件的位置信息。
1.3与DataNode交互,读取或者写入数据。
1.4Client提供一些命令来管理HDFS,比如启动或者关闭HDFS。
1.5Client可以通过一些命令来访问HDFS。 -
NameNode:master,HDFS的管理者。
2.1管理HDFS的名称空间。
2.2管理数据块(Block)映射信息
2.3配置副本策略
2.4处理客户端读写请求。
NameNode 在启动的时候会做哪些操作
从 fsimage 中不停的顺序读取name下的文件和元数据信息,并在内存中构建整个 namespace,同时将每个文件对应的blockid 保存入 BlocksMap 中,此时 BlocksMap 中每个 block 对应的 datanodes 列表暂时为空。
当 fsimage 加载完毕后,整个 HDFS 的目录结构在内存中就已经初始化完毕,所缺的就是每个文件对应的 block 对应的 datanode 列表信息。这些信息需要从 datanode 的 blockReport 中获取,所以加载 fsimage 完毕后,namenode 进程进入 rpc 等待状态,等待所有的 datanodes发送 blockReports
-
DataNode:Slave。NameNode下达命令,DataNode执行实际的操作。
3.1存储实际的数据块。
3.2执行数据块的读/写操作。 -
Secondary NameNode:并非NameNode的热备(当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。)
4.1辅助NameNode,分担其工作量,随着edits文件在操作中会越来越大,所以需要提前合并处理加入内存
4.2定期合并Fsimage和Edits,并推送给NameNode。
4.3在紧急情况下,可辅助恢复NameNode。
#1个小时合并一次
<property>
<name>fs.checkpoint.period</name>
<value>3600</value>
</property>
#当EditsLog文件大小超过64MB合并一次
<property>
<name>fs.checkpoint.size</name>
<value>67108864</value>
</property>
<property>
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >
#回收站
<property>
<name>fs.trash.interval</name>
<value>120</value>
</property>
为什么HDFS文件块(block)大小设定为128M
上传同样大小的文件,可出现以下两种情形。
文件块大,寻址时间短,磁盘传输时间长
文件块小,寻址时间长,磁盘传输时间短
寻址时间为传输时间的1%时,为最佳状态,因为集群在使用过程中是千兆网络传输,则网速大约每秒100M,HDFS的平均寻址时间为10ms,10ms/0.01=1000ms=1s,1sX100M
<property>
<name>dfs.blocksize</name>
<value>30m</value>
</property>
二、怎么用
知道怎么用的先明确下是怎么配置的
配置过程
第一步:安装几台CentOS7系统的主机
第二步:建立主机名与IP地址的映射
[root@wq1 etc]# cat hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
你的IP地址 你想写的主机名
192.168.111.111 myname
第三步:配置SSH免密登录,这步适合在自己虚拟机上搭建操作,生产中免密登陆还是不安全,此步可不用操作
#有几台机器执行几次这几个命令
1、把老的锁和钥匙都扔了
rm -rf /root/.ssh
2、配钥匙
集群中的所有机器执行,输入该命令后点击回车三次
ssh-keygen -t rsa
3、发钥匙
三台机器都要执行下面的命令
# 将钥匙复制给wq1
ssh-copy-id wq1
# 将钥匙复制给wq2
ssh-copy-id wq2
# 将钥匙复制给wq3
ssh-copy-id wq3
如果不做免密设置将会是这种情况(就需要输入多次密码,相对麻烦,因此有了上步的操作)
[root@wq1 ~]# start-dfs.sh
Starting namenodes on [wq1]
root@wq1's password:
wq1: starting namenode, logging to /opt/hadoop-2.7.7/logs/hadoop-root-namenode-wq1.out
root@wq1's password:
wq1: starting datanode, logging to /opt/hadoop-2.7.7/logs/hadoop-root-datanode-wq1.out
Starting secondary namenodes [wq1]
root@wq1's password:
wq1: starting secondarynamenode, logging to /opt/hadoop-2.7.7/logs/hadoop-root-secondarynamenode-wq1.out
[root@wq1 ~]# jps
3316 NameNode
3670 SecondaryNameNode
3464 DataNode
3806 Jps
第四步:配置环境变量(配置JDK环境)
第五步:修改hdfs相关的参数
core-site.xml
(配置确定那台机器是namenode,确定上传文件存储的位置)
hdfs-site.xml
(配置确定那台机器是SecondaryNamenode)
hadoop-env.sh
(导入JDK环境)
slaves
(所有机器名写入,形成主从关系)
vim hadoop-env.sh
#hadoop-env.sh
export JAVA_HOME=/opt/jdk1.8
vim core-site.xml
<property>
<!-- (配置NameNode服务启动的主机和端口) -->
<name>fs.defaultFS</name>
<value>hdfs://wq1:9000/</value>
</property>
<property>
<!-- 配置hdfs文件保存的目录,当前选择放在Hadoop的安装目录下 -->
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop-2.7.7/data</value>
</property>
vim hdfs-site.xml
<property>
<!-- 配置固定的节点启动SecondaryNamenode与namenode不在同一节点即可 -->
<name>dfs.namenode.secondary.http-address</name>
<value>wq2:50090</value>
</property>
#高可用配置
<property>
<name>ha.zookeeper.quorum</name>
<value>wq1:2181,wq2:2181,wq3:2181</value>
</property>
vim slaves
(写入集群中的机器名)
wq1
wq2
第六步:格式化(初始化了新的集群id,命名空间)
[root@wq1 ~]# hdfs namenode -format
第七步:启动
[root@wq1 ~]# start-dfs.sh
第八步:查看是否启动起来(看Java守护进程)
[root@wq1 ~]# jps
7539 DataNode
7431 NameNode
28953 Jps
各个文件下的内容
- 1安装目录下的东西
安装好后并且能运行之后查看自己的安装目录下都有哪些文件
[root@wq2 hadoop-2.7.7]# pwd
/opt/hadoop-2.7.7
[root@wq2 hadoop-2.7.7]# ll
总用量 116
drwxr-xr-x. 2 wuqi2020 ftp 194 7月 19 2018 bin
drwxr-xr-x 4 root root 37 10月 31 18:04 data
drwxr-xr-x. 3 wuqi2020 ftp 20 7月 19 2018 etc
drwxr-xr-x. 2 wuqi2020 ftp 106 7月 19 2018 include
drwxr-xr-x. 3 wuqi2020 ftp 20 7月 19 2018 lib
drwxr-xr-x. 2 wuqi2020 ftp 239 7月 19 2018 libexec
-rw-r--r--. 1 wuqi2020 ftp 86424 7月 19 2018 LICENSE.txt
drwxr-xr-x. 3 root root 4096 11月 1 01:05 logs
-rw-r--r--. 1 wuqi2020 ftp 14978 7月 19 2018 NOTICE.txt
-rw-r--r--. 1 wuqi2020 ftp 1366 7月 19 2018 README.txt
drwxr-xr-x. 2 wuqi2020 ftp 4096 7月 19 2018 sbin
drwxr-xr-x. 4 wuqi2020 ftp 31 7月 19 2018 share
通过上面展示的安装目录下的文件夹,在后面的操作过程中,我们需要关注下面这四个文件夹:
sbin下存储的是自带的脚本想要启动该组件就在该文件下执行
- 1.1-etc文件夹下的内容(存储配置文件,参数调优要在该文件夹下进行)
这些属性都是后期经常要操作的
[root@wq2 etc]# cd hadoop/
[root@wq2 hadoop]# ll
总用量 152
-rw-r--r-- 1 wuqi2020 ftp 1323 11月 1 01:00 core-site.xml
-rw-r--r--. 1 wuqi2020 ftp 4222 8月 31 20:10 hadoop-env.sh
-rw-r--r-- 1 wuqi2020 ftp 1069 10月 31 18:10 hdfs-site.xml
-rw-r--r--. 1 wuqi2020 ftp 11801 7月 19 2018 log4j.properties
-rw-r--r--. 1 wuqi2020 ftp 1383 7月 19 2018 mapred-env.sh
-rw-r--r-- 1 wuqi2020 ftp 1160 11月 4 11:46 mapred-site.xml
-rw-r--r--. 1 wuqi2020 ftp 12 9月 9 01:20 slaves
-rw-r--r--. 1 wuqi2020 ftp 4567 7月 19 2018 yarn-env.sh
-rw-r--r-- 1 wuqi2020 ftp 1527 10月 31 20:42 yarn-site.xml
- 1.2-data目录下存储namenode,DataNode,secondarynamenode相关数据;
drwxr-xr-x. 5 root root 51 4月 5 22:55 dfs
[root@wq1 data]# pwd
/opt/hadoop-2.7.7/data
[root@wq1 data]# cd dfs/
[root@wq1 dfs]# ll
总用量 0
drwx------. 3 root root 40 4月 6 12:04 data
drwxr-xr-x. 3 root root 40 4月 6 12:02 name
drwxr-xr-x. 3 root root 40 4月 6 12:06 namesecondary
1.2.1-data目录下
#存储datanode信息的
[root@wq2 subdir0]# pwd
/opt/hadoop-2.7.7/data/dfs/data/current/BP-1063901513-192.168.236.236-1604118984203/current/finalized/subdir0/subdir0
[root@wq2 subdir0]# ll
总用量 153492
-rw-r--r-- 1 root root 54 11月 1 01:14 blk_1073741826
-rw-r--r-- 1 root root 11 11月 1 01:14 blk_1073741826_1001.meta
[root@wq2 subdir0]# cat blk_1073741826
82 IPDDpvnbs
94 QDTVDbatyc
11 Ubk
- 1.2.2查看name目录下都有哪些文件,这也是执行格式化命令后该初始化的就是该目录下的文件
-rw-r--r--. 1 root root 42 4月 7 10:58 edits_0000000000000000552-0000000000000000553
-rw-r--r--. 1 root root 42 4月 7 11:00 edits_0000000000000000554-0000000000000000555
-rw-r--r--. 1 root root 1048576 4月 7 11:00 edits_inprogress_0000000000000000556
-rw-r--r--. 1 root root 5025 4月 7 10:01 fsimage_0000000000000000551
-rw-r--r--. 1 root root 62 4月 7 10:01 fsimage_0000000000000000551.md5
-rw-r--r--. 1 root root 5025 4月 7 11:01 fsimage_0000000000000000555
-rw-r--r--. 1 root root 62 4月 7 11:01 fsimage_0000000000000000555.md5
-rw-r--r--. 1 root root 4 4月 7 11:00 seen_txid
-rw-r--r--. 1 root root 207 4月 6 11:49 VERSION
[root@wq1 current]# cat seen_txid
556
[root@wq1 current]# cat fsimage_0000000000000000555.md5
4b802aa7b396ee71f7ae2b7d4e317fa2 *fsimage_0000000000000000555
cat VERSION
#Sat Oct 31 18:11:37 CST 2020
namespaceID=356126353
clusterID=CID-45dbc059-efc3-4323-a148-6860e4b4efc1
cTime=0
storageType=NAME_NODE
blockpoolID=BP-1042749061-192.168.236.237-1604139097617
layoutVersion=-63
- 1.3-logs目录下
-rw-r--r--. 1 root root 715 4月 4 11:44 hadoop-root-datanode-wq1.out.5
-rw-r--r--. 1 root root 7080553 4月 7 11:26 hadoop-root-namenode-wq1.log
-rw-r--r--. 1 root root 5007 4月 6 12:19 hadoop-root-namenode-wq1.out
- 1.4 sbin目录下(自带shell命令)
-rwxr-xr-x. 1 wuqi2020 ftp 2752 7月 19 2018 distribute-exclude.sh
-rwxr-xr-x. 1 wuqi2020 ftp 6452 7月 19 2018 hadoop-daemon.sh
-rwxr-xr-x. 1 wuqi2020 ftp 1360 7月 19 2018 hadoop-daemons.sh
Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。 FSImage文件也有两种状态, finalized和checkpoint, finalized表示已经持久化磁盘的文件,文件名形式: fsimage_[end-txid], checkpoint表示合并中的fsimage, 2.x版本checkpoint过程在Standby Namenode(SNN)上进行;
- 查看Fsimage文件
hdfs oiv -p Delimited -i fsimage_0000000000000000551 fsimage_0000000000000000551.xml
形式如下(文件数)
/tmp/hadoop-yarn/staging/root/.staging/job_1617615663836_0025/COMMIT_FAIL 1 2021-04-07 00:17 2021-04-07 00:17 134217728 rw-r--r-- root supergroup
/tmp/hadoop-yarn/staging/history/done/2021/04/07/000000/job_1617615663836_0025-1617725348829-root-insert+into+table+test_bu...test_bucket_tmp1%28Stage-1617725877707-1-4-KILLED-default-1617725358318.jhist 1 2021-04-07 00:17 2021-04-07 00:17 134217728 1 46364 0 rwxrwx--- root supergroup
/tmp/hadoop-yarn/staging/history/done/2021/04/07/000000/job_1617615663836_0025_conf.xml 1 2021-04-07 00:17 2021-04-07 00:17 134217728 1 242647 0 0 rwxrwx--- root supergroup
/tmp/logs/root/logs/application_1617615663836_0025/wq1_33210 1 2021-04-07 00:30 2021-04-07 00:30 134217728 1 349379 0 0 rw-r----- root root
21/04/12 11:25:30 INFO offlineImageViewer.PBImageTextWriter: Outputted 3 INodes.
Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。EditLog
文件有两种状态: inprocess和finalized, inprocess表示正在写的日志文件,文件名形式:editsinprocess[start-txid],finalized表示已经写完的日志文件,文件名形式:edits[start-txid][end-txid]
- 查看edits文件
#将edits文件转为xml文件方便查看
hdfs oev -i edits_inprogress_0000000000000014085 -o edits_inprogress_0000000000000014085.xml
#转回原本的二进制文件
hdfs oev -i edits_inprogress_0000000000000014085.xml -o edits_inprogress_0000000000000014085 -p binary
edits文件经过hdfs自带命令转换后长着下面这个样子
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
<EDITS_VERSION>-63</EDITS_VERSION>
<RECORD>
<OPCODE>OP_RENAME_OLD</OPCODE>
<DATA>
<TXID>14084</TXID>
<LENGTH>0</LENGTH>
<SRC>/logs/MapReduceOnHue-1.0-SNAPSHOT.jar.tmp</SRC>
<DST>/logs/MapReduceOnHue-1.0-SNAPSHOT.jar</DST>
<TIMESTAMP>1617631563000</TIMESTAMP>
<RPC_CLIENTID></RPC_CLIENTID>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
</EDITS>
seen_txid文件保存的是一个数字,就是最后一个edits_的数字每次Namenode启动的时候都会将fsimage文件读入内存,并从00001开始到seen_txid中记录的数字依次执行每个edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成Namenode启动的时候就将fsimage和edits文件进行了合并。seen_txid,保存的是一个事务ID,这个事务ID是EditLog最新的一个结束事务id,当NameNode重启时,会顺序遍历从edits_0000000000000000001到seen_txid所记录的txid所在的日志文件,进行元数据恢复,如果该文件丢失或记录的事务ID有问题,会造成数据块信息的丢失。
[root@wq1 current]# cat seen_txid
6283
namenode: 第一次启动namenode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。客户端对元数据进行增删改的请求namenode记录操作日志,更新滚动日志。namenode在内存中对数据进行增删改。namenode在加载fsimage过程其实⾮常简单,就是从fsimage中不停的顺序读取⽂件和⽬录的元数据信息,并在内存中构建整个namespace,同时将每个⽂件对应的blockid保存⼊BlocksMap中,此时BlocksMap中每个block对应的datanodes列表暂时为空。当fsimage加载完毕后,整个HDFS的⽬录结构在内存中就已经初始化完毕,所缺的就是每个⽂件对应的block对应的datanode列表信息。这些信息需要从datanode的blockReport中获取,所以加载fsimage完毕后,namenode进程进⼊rpc等待状态,等待所有的datanodes发送blockRep
Secondary NameNode:询问namenode是否需要checkpoint。直接带回namenode是否检查结果。namenode滚动正在写的edits日志将滚动前的编辑日志和镜像文件拷贝到Secondary NameNodeSecondary NameNode加载编辑日志和镜像文件到内存,并合并。生成新的镜像文件fsimage.chkpoint拷贝fsimage.chkpoint到namenode将fsimage.chkpoint重新命名成fsimage
datanode:一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。DataNode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有的块信息。
checkpoint
- 集群启动时,加载fsimage镜像文件到内存,如果是第一启动集群或者集群正常关闭之后重启此时nameNode会在硬盘中合并一个fsimage镜像
- seconddaryNameNode定时(1分钟)发送检验给nameNode,查看是否需要进行合并
- 得知nameNode需要进行元数据合并
- seconddaryNameNode向nameNode发送合并请求
- nameNode将edits_inprogress_000095 根据seen_txid进行回滚,并且生成一个新的空的edits_inprogress_000096,继续记录操作日志
- secondaryNameNode将回滚的edits和最新的fsiamge进行本地拉取
- secondaryNameNode将edits和最新的fsiamge进行合并,在内存中根据edits修改fsiamge
- secondaryNameNode将合并后的fsiamge推送回namenode。并在本地保存一份。
触发配置
dfs.namenode.checkpoint.check.period=60 ##检查触发条件是否满足的频率,60 秒
dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary
##以上两个参数做 checkpoint 操作时,secondary namenode 的本地工作目录
dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}
dfs.namenode.checkpoint.max-retries=3 ##最大重试次数
dfs.namenode.checkpoint.period=3600 ##两次 checkpoint 之间的时间间隔 3600 秒
dfs.namenode.checkpoint.txns=1000000 ##两次 checkpoint 之间最大的操作记录
Namenode 和 SecondaryNamenode 的工作目录存储结构完全相同,所以,当 Namenode 故障
退出需要重新恢复时,可以从SecondaryNamenode的工作目录中将fsimage拷贝到Namenode
的工作目录,以恢复 namenode 的元数据.
向hdfs上传文件下载文件
向hdfs上传文件有三种途径:使用Java代码传数据,使用hdfs组件自身的命令上传文件,使用其他组将向hdfs上传文件
使用Java代码向hdfs上传文件
public static void main(String[] args) throws Exception{
boolean flag;
// HDFS 的操作
// HDFS 的API入口类是FileSystem
// FileSystem 有多个实现类
// FileSystem 可以根据URI兼容各种各样不同的文件系统
// 0. 创建配置文件对象
// 这个对象可以在程序运行时临时修改Hadoop的一些配置参数
// 优先级 代码中 > resource的配置文件 > 集群
Configuration conf = new Configuration();
conf.set("dfs.replication", "1");
// 1. 通过FileSystem创建 HDFS文件系统对象
FileSystem fs = FileSystem.get(
URI.create("hdfs://192.168.236.236:9000/"),
conf,
"root"
);
upload(fs);
download(fs)
}
//上传文件 (覆盖)
private static void upload(FileSystem fs) throws IOException {
fs.copyFromLocalFile(
new Path("C:\\Users\\Administrator\\Desktop\\access.log"),
new Path("/java-hdfs/")
);
}
//下载文件
private static void download(FileSystem fs) throws IOException {
fs.copyToLocalFile(
new Path("/up1/log.txt"),
new Path("C:\\Users\\Administrator\\Desktop\\access.log")
);
}
使用hdfs命令上传文件
- 把hdfs上的多个目录下的文件合并为一个文件
hdfs dfs -cat files | hdfs dfs -copyFromLocal - newfile
- 升副本数
hdfs dfs -setrep -R -w 3 hdfs://192.168.236.236:50070//hdfs-hive
- 降副本数
hdfs dfs -setrep -R -w 2 hdfs://192.168.236.236:50070///hdfs-hive
- 上传文件
hdfs dfs -put /root/oldfile /newfile
- 删除文件/文件夹
hdfs dfs -rm /user/hive/warehouse/文件的名
hdfs dfs -rm -r /user/hive/warehouse/文件夹的名
- 汇总
[root@wq1 etc]# hdfs dfs -help
-help:输出这个命令参数
-ls: 显示目录信息
-mkdir:在hdfs上创建目录
-moveFromLocal从本地剪切粘贴到hdfs
-appendToFile :追加一个文件到已经存在的文件末尾
-cat :显示文件内容
-tail:显示一个文件的末尾
-chgrp 、-chmod、-chown:linux文件系统中的用法一样,修改文件所属权限
-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去
-copyToLocal:从hdfs拷贝到本地
-cp :从hdfs的一个路径拷贝到hdfs的另一个路径
-mv:在hdfs目录中移动文件
-get:等同于copyToLocal,就是从hdfs下载文件到本地
-getmerge :合并下载多个文件,比如hdfs的目录 /hj/下有多个文件:log.1, log.2,log.3,...
-put:等同于copyFromLocal
-rm:删除文件或文件夹
-rmdir:删除空目录
-df :统计文件系统的可用空间信息
-du统计文件夹的大小信息
-setrep:设置hdfs中文件的副本数量
使用其他组件
其他组件不止我下面写的flume,hive,sqoop
使用sqoop上传文件
- 上传全量数据
sqoop import \
--connect jdbc:mysql://192.168.xxx.xxx:3316/testdb \
--username root \
--password 123456 \
--query “select * from test_table where \$CONDITIONS” \
--target-dir /user/root/person_all \
--fields-terminated-by “,” \
--hive-drop-import-delims \
--null-string “\\N” \
--null-non-string “\\N” \
--split-by id \
-m 6 \
- 上传增量数据
此方式要求原有表中有time字段,它能指定一个时间戳,让Sqoop把该时间戳之后的数据导入至Hadoop(这里为HDFS)。因为后续订单可能状态会变化,变化后time字段时间戳也会变化,此时Sqoop依然会将相同状态更改后的订单导入HDFS,当然我们可以指定merge-key参数为orser_id,表示将后续新的记录与原有记录合并
# 将时间列大于等于阈值的数据增量导入HDFS
sqoop import \
--connect jdbc:mysql://192.168.xxx.xxx:3316/testdb \
--username root \
--password transwarp \
--query “select order_id, name from order_table where \$CONDITIONS” \
--target-dir /user/root/order_all \
--split-by id \
-m 4 \
--incremental lastmodified \
--merge-key order_id \
--check-column time \
# remember this date !!!
--last-value “2014-11-09 21:00:00”
使用flume向hdfs上传文件
使用flume向hdfs上传文件可分为两步,第一步写flume脚本(脚本名随意,后缀为.conf就行),第二步执行脚本。
该脚本名为flume-hdfs.conf
# Name the components on this agent
a2.sources = r2
a2.sinks = k2
a2.channels = c2
# Describe/configure the source
a2.sources.r2.type = exec
a2.sources.r2.command = tail -F /opt/hive/logs/hive.log
a2.sources.r2.shell = /bin/bash -c
# Describe the sink
a2.sinks.k2.type = hdfs
a2.sinks.k2.hdfs.path = hdfs://test01:9000/flume/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k2.hdfs.filePrefix = logs-
#是否按照时间滚动文件夹
a2.sinks.k2.hdfs.round = true
#多少时间单位创建一个新的文件夹
a2.sinks.k2.hdfs.roundValue = 1
#重新定义时间单位
a2.sinks.k2.hdfs.roundUnit = hour
#是否使用本地时间戳
a2.sinks.k2.hdfs.useLocalTimeStamp = true
#积攒多少个Event 才 flush 到 HDFS 一次
a2.sinks.k2.hdfs.batchSize = 1000
#设置文件类型,可支持压缩
a2.sinks.k2.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k2.hdfs.rollInterval = 600
#设置每个文件的滚动大小
a2.sinks.k2.hdfs.rollSize = 134217700
#文件的滚动与 Event 数量无关
a2.sinks.k2.hdfs.rollCount = 0
#最小冗余数
a2.sinks.k2.hdfs.minBlockReplicas = 1
# Use a channel which buffers events in memory
a2.channels.c2.type = memory
a2.channels.c2.capacity = 1000
a2.channels.c2.transactionCapacity = 100
# Bind the source and sink to the channel
a2.sources.r2.channels = c2
a2.sinks.k2.channel = c2
在flume的bin下执行该脚本(如果配置了环境变量)
flume-ng agent\
--conf /opt/flume-1.9.0/conf/ \
--name a2 \
--conf-file /root/flume_conf/flume-hdfs.conf \
-Dflume.root.logger=INFO,console
使用hive将数据导到hdfs上
insert overwrite directory '/user/hive/testhive'
select * from test ;
三、hdfs核心问题
hdfs单点故障和内存受限问题
HDFS HA
:通过主备NameNode解决 一个集群中只能有一个NameNode处于工作状态 当主NameNode发送故障 则切换到备NameNode上,edits文件在客户端对hdfs进行操作时产生,当有元数据的增删改查日志产生时 它会直接保存到一个内部的集群中称之为JournalNode,向多数JournalNode上传成功才算成功,同时fsimage文件和edits文件的合并工作也由JournalNode完成,主NameNode(Active)挂了之后,备NameNode(Standby)接管后,会同样会把日志保存到JournalNode中。JournalNode在合并fsimage和edits文件以更新fsimage文件时 需要同时合并两个NameNode的fsimage 从而保证瞬间实现接管。此时就不再需要secondarynamenode了,因为会出现报错。
HDFS Federation(联邦)
:它可以水平扩展 支持多个NameNode 每个NameNode分管一部分目录,所有DataNode共享所有NameNode的资源。Federation使用了多个独立的Namenode/NameSpace。这些Namenode之间是联合的,也就是说,他们之间相互独立且不需要互相协调,各自分工,管理自己的区域。分布式的datanode被用作通用的数据块存储存储设备。每个DataNode要向集群中所有的namenode注册,且周期性的向所有namenode发送心跳和块报告,并执行来自所有namenode的命令。
怎么解决数据倾斜的问题
首先我们明确一点,什么是数据倾斜,在webUI上可以看到datanoded的磁盘占用情况,那么数据倾斜就是个别节点磁盘占用率远远高于其他节点,那么导致这种情况发生有二种:1,增加了新的节点,2,某几个节点挂载了新的磁盘,就是输新盘上存的数据还不多,那么这会牵扯出三个问题,hdfs怎么做负载均衡,什么样情况下触发rebalance,mapreduce计算过程中某个节点计算压力增加影响性能。
1、提高dfs.datanode.du.reserved的值;也就意味着即将超过这个预留值的时候就会往别的节点上写数据
#100MB
<property>
<name>dfs.datanode.du.reserved</name>
<value>104857600</value>
</property>
2、关闭高磁盘节点的nodemanager;如果在该节点上进行计算的话,数据存储首先会往本地写一份,这样更加加重了本地节点的负担
3、降低副本数;
[root@wq1 opt]# hadoop dfs -setrep -w 2 /logs
DEPRECATED: Use of this script to execute hdfs command is deprecated.
Instead use the hdfs command for it.
Replication 2 set: /logs/Different.java
Replication 2 set: /logs/GenericArrayList.java
Waiting for /logs/Different.java ...............
4、启动hadoop自带的balance;
查看使用帮助
[root@wq1 ~]# hdfs balancer -help
Usage: hdfs balancer
[-policy <policy>] the balancing policy: datanode or blockpool
[-threshold <threshold>] Percentage of disk capacity
[-exclude [-f <hosts-file> | <comma-separated list of hosts>]] Excludes the specified datanodes.
[-include [-f <hosts-file> | <comma-separated list of hosts>]] Includes only the specified datanodes.
[-idleiterations <idleiterations>] Number of consecutive idle iterations (-1 for Infinite) before exit.
[-runDuringUpgrade] Whether to run the balancer during an ongoing HDFS upgrade.This is usually not desired since it will not affect used space on over-utilized machines.
执行
[root@wq1 ~]# start-balancer.sh -threshold 20
starting balancer, logging to /opt/hadoop-2.7.7/logs/hadoop-root-balancer-wq1.out
调整带宽
hdfs dfsadmin -fs hdfs: //wq1 :9000 -setBalancerBandwidth 104857600
hdfs四大机制
- 心跳机制
dataNode会定时的向nameNode发送心跳报告,从而nameNode获取到datanode存活状态、存储的block列表信息
#心跳报告周期
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value> //单位秒
</property>
#nameNode在接收不到dataNode的心跳时,此时会向dataNode主动发送检查
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value> //单位毫秒
</property>
- 安全机制
hdfs在启动的时候,首先会进入的安全模式中,当达到规定的要求时,会退出安全模式。在安全模式中,不能执行任何修改元数据信息的操作。
hdfs的元数据
1.抽象目录树
2.数据与块的对应关系(文件被切分成多少个块)
3.block块存放的位置信息
元数据的存储位置:
内存:内存中存储了一份完整的元数据信息(抽象目录树、数据与块的对应关系、block块存放的位置信息)
硬盘:抽象目录树、数据与块的对应关系。
其中内存中的元数据的block块存放的位置信息,是通过dataNode向nameNode汇报心跳时获取的. 硬盘中的元数据,是因为内存中的元数据在机器宕机时就自动消失,所以需要将内存中的元数据持久化到硬盘 而硬盘中的元数据只有抽象目录树、数据与块的对应关系,没有block块存放的位置信息
集群启动时dfs.namenode.safemode.min.datanodes(启动的dataNode个数)为0时,并且,数据块的最小副本数dfs.namenode.replication.min为1时,此时会退出安全模式,也就是说,集群达到了最小副本数,并且能运行的datanode节点也达到了要求,此时退出安全模式
启动的dataNode个数为0时,并且所有的数据块的存货率达到0.999f时,集群退出安全模式(副本数达到要求)
手动退出安全模式命令hdfs dfsadmin -safemode leave
- 副本存放策略
第一个副本,放置在离客户端最近的那个机架的任意节点,如果客户端是本机,那就存放在本机(保证有一个副本数)
第二个副本,放置在跟第一个副本不同机架的任意节点上
第三个副本,放置在跟第二个副本相同机架的不同节点上
vim hdfs-site.xml
#设置副本数
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
- 负载均衡
当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值。当数据不平衡时,Map任务可能会分配到没有存储数据的机器,这将导致网络带宽的消耗,也无法很好的进行本地计算。
当HDFS负载不均衡时,需要对HDFS进行数据的负载均衡调整,即对各节点机器上数据的存储分布进行调整。从而,让数据均匀的分布在各个DataNode上,均衡IO性能。下面的rebalance命令就可以实现负载均衡
负载均衡步骤
- 数据均衡服务(Rebalancing Server)首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况
- Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图。数据块迁移路线图,确保网络内最短路径
- 开始数据块迁移任务,Proxy Source Data Node复制一块需要移动数据块
- 将复制的数据块复制到目标DataNode上
- 删除原始数据块
- 目标DataNode向Proxy Source Data Node确认该数据块迁移完成
- Proxy Source Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准
hdfs自带有脚本
#节点最大占用率与节点的最小的占用率之间的差值
bin/start-balancer.sh –threshold
-threshold
默认设置:10,参数取值范围:0-100;百分比
参数含义:判断集群是否平衡的阈值。理论上,该参数设置的越小,整个集群就越平衡
查看集群上各个datanode上磁盘之间占用情况
迁移数据时所用网络带宽
#1M
<property>
<name>dfs.balance.bandwidthPerSec</name>
<value>1048576</value>
<description> Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second. </description>
</property>
HDFS HA模式(高可用模式)
- HDFS集群中只有一个Namenode,如果Namenode故障,那么这个集群将不可用,直到Namenode重启或者其他Namenode接入。
HDFS HA特性即解决这个问题,它通过在集群中同时运行2个(redundant)Namenodes,并让active和standby之间热备(hot standby)。当Active Namenode故障失效后,即可快速故障转移到新的Namenode上(standby Namenode);
举个可能不恰当的例子来说:这就好比你有一步手机,如果你只插了一张SIM卡,你到某一区域后没有信号后,那么你就不能上网了;但是如果你分别有移动联通两张卡,如果到某一地区,移动没信号就换联通,但是你想上网就只能同时用一个运营商,手机还要做的就是你要切换这两个运营商的时候还要特别的快,不然影响你的体验;hdfs的高可用模式就要保证两件事,怎么保证同一时刻只有一个namenode在控制着集群,以及主namenode挂掉之后备namenode快速接替主namenode。
hdfs HA模式各组件关系图
共享存储系统QJM(一个namenode 挂掉后另一个namenode怎么快速获得它的信息)
- 向jn写edits文件过程
写本地由配置中参数dfs.namenode.name.dir
控制,写JN由参数dfs.namenode.shared.edits.dir
控制,在写EditLog时会由两个不同的输出流来控制日志的写过程,分别为:EditLogFileOutputStream(本地输出流)和QuorumOutputStream(JN输出流)。写EditLog也不是直接写到磁盘中,为保证高吞吐,NameNode会分别为EditLogFileOutputStream和QuorumOutputStream定义两个同等大小的Buffer,大小大概是512KB,一个写Buffer(buffCurrent),一个同步Buffer(buffReady),这样可以一边写一边同步,所以EditLog是一个异步写过程,同时也是一个批量同步的过程,避免每写一笔就同步一次日志。
这个是怎么实现边写边同步的呢,这中间其实是有一个缓冲区交换的过程,即bufferCurrent和buffReady在达到条件时会触发交换,如bufferCurrent在达到阈值同时bufferReady的数据又同步完时,bufferReady数据会清空,同时会将bufferCurrent指针指向bufferReady以满足继续写,另外会将bufferReady指针指向bufferCurrent以提供继续同步EditLog
- 保证jn节点上文件的一致性
2.1隔离双写
这样就能保证主备NN发生切换时,就算同时向JN同步日志,也能保证日志不会写乱,因为发生切换后,原ANN的EpochNumber肯定是小于新ANN的EpochNumber,所以原ANN向JN的发起的所有同步请求都会拒绝,实现隔离功能,防止了脑裂
。
在ANN每次同步EditLog到JN时,先要保证不会有两个NN同时向JN同步日志。这个隔离是怎么做的。这里面涉及一个很重要的概念Epoch Numbers,很多分布式系统都会用到。Epoch有如下几个特性:
当NN成为活动结点时,其会被赋予一个EpochNumber
每个EpochNumber是惟一的,不会有相同的EpochNumber出现
EpochNumber有严格顺序保证,每次NN切换后其EpochNumber都会自增1,后面生成的EpochNumber都会大于前面的EpochNumber,QJM是怎么保证上面特性的呢,主要有以下几点:
- 第一步,在对EditLog作任何修改前,QuorumJournalManager(NameNode上)必须被赋予一个EpochNumber
- 第二步, QJM把自己的EpochNumber通过newEpoch(N)的方式发送给所有JN结点
- 第三步, 当JN收到newEpoch请求后,会把QJM的EpochNumber保存到一个lastPromisedEpoch变量中并持久化到本地磁盘
- 第四步, ANN同步日志到JN的任何RPC请求(如logEdits(),startLogSegment()等),都必须包含ANN的EpochNumber
- 第五步,JN在收到RPC请求后,会将之与lastPromisedEpoch对比,如果请求的EpochNumber小于lastPromisedEpoch,将会拒绝同步请求,反之,会接受同步请求并将请求的EpochNumber保存在lastPromisedEpoch
2.2恢复in-process日志
如果在写过程中写失败了,可能各个JN上的EditLog的长度都不一样,需要在开始写之前将不一致的部分恢复
- 从jn读取文件对过程
在SNN上先检查前置条件,前置条件包括两个方面:距离上次Checkpointing的时间间隔和EditLog中事务条数限制。前置条件任何一个满足都会触发Checkpointing,然后SNN会将最新的NameSpace数据即SNN内存中当前状态的元数据保存到一个临时的fsimage文件( fsimage.ckpt)然后比对从JN上拉到的最新EditLog的事务ID,将fsimage.ckpt_中没有,EditLog中有的所有元数据修改记录合并一起并重命名成新的fsimage文件,同时生成一个md5文件。将最新的fsimage再通过HTTP请求传回ANN。
选举出leader
1)HealthMonitor初始化完成后通过内部线程调用NameNode的RPC接口对其进行健康检查
2)如果检查到NameNode状态异常,会回调ZKFailoverContorller注册的回调函数进行相应的处理
3)如果ZKFailoverController发现集群需要进行主备选举,会使用ActiveStanbyElector和zookeeper集群通信完成主备切换
4)ActiveStanbyElector在完成主备切换后,回调ZKFailoverController注册的方法使NameNode变成active或者stanby状态
在故障切换期间,ZooKeeper主要是发挥什么作用呢,有以下几点:
-
失败保护:集群中每一个NameNode都会在ZooKeeper维护一个持久的session,机器一旦挂掉,session就会过期,故障迁移就会触发
-
Active NameNode选择:ZooKeeper有一个选择ActiveNN的机制,一旦现有的ANN宕机,其他NameNode可以向ZooKeeper申请排他成为下一个Active节点
-
防脑裂: ZK本身是强一致和高可用的,可以用它来保证同一时刻只有一个活动节点
那在哪些场景会触发自动切换呢,从HDFS-2185中归纳了以下几个场景: -
ActiveNN JVM奔溃:ANN上HealthMonitor状态上报会有连接超时异常,HealthMonitor会触发状态迁移至SERVICE_NOT_RESPONDING, 然后ANN上的ZKFC会退出选举,SNN上的ZKFC会获得Active Lock, 作相应隔离后成为Active结点。
-
ActiveNN JVM冻结:这个是JVM没奔溃,但也无法响应,同奔溃一样,会触发自动切换。
-
ActiveNN 机器宕机:此时ActiveStandbyElector会失去同ZK的心跳,会话超时,SNN上的ZKFC会通知ZK删除ANN的活动锁,作相应隔离后完成主备切换。
-
ActiveNN 健康状态异常: 此时HealthMonitor会收到一个HealthCheckFailedException,并触发自动切换。
-
Active ZKFC奔溃:虽然ZKFC是一个独立的进程,但因设计简单也容易出问题,一旦ZKFC进程挂掉,虽然此时NameNode是OK的,但系统也认为需要切换,此时SNN会发一个请求到ANN要求ANN放弃主结点位置,ANN收到请求后,会触发完成自动切换。
-
ZooKeeper奔溃:如果ZK奔溃了,主备NN上的ZKFC都会感知断连,此时主备NN会进入一个NeutralMode模式,同时不改变主备NN的状态,继续发挥作用,只不过此时,如果ANN也故障了,那集群无法发挥Failover, 也就不可用了,所以对于此种场景,ZK一般是不允许挂掉到多台,至少要有N/2+1台保持服务才算是安全的。
为了构建HA集群架构,你需要准备如下资源:
Namenode机器:两台配置对等的物理机器,它们分别运行Active和Standby Node。
JouralNode机器:运行JouralNodes的机器。JouralNode守护进程相当的轻量级,它们可以和hadoop的其他进程部署在一起,比如Namenodes、jobTracker、ResourceManager等。不过为了形成多数派(majority),至少需要3个JouralNodes,因为edits操作必须在多数派上写入成功。当然JNS的个数可以 > 3,且通常为奇数(3,5,7),这样可以更好的容错和形成多数派。如果你运行了N个JNS,那么它可以允许(N-1)/2个JNS进程失效并且不影响工作。
此外,在HA集群中,standby namenode还会对namespace进行checkpoint操作(继承Backup Namenode的特性),因此,就不需要在HA集群中运行SecondaryNamenode、CheckpointNode或者BackupNode。事实上,HA架构中运行上述节点,将会出错(不允许)。
Hadoop集群中Hadoop都分别需要启动哪些进程,它们的作用分别是什么?
1)NameNode它是hadoop中的主服务器,管理文件系统名称空间和对集群中存储的文件的访问,保存有metadate。
2)SecondaryNameNode它不是namenode的冗余守护进程,而是提供周期检查点和清理任务。帮助NN合并editslog,减少NN启动时间。
3)DataNode它负责管理连接到节点的存储(一个集群中可以有多个节点)。每个存储数据的节点运行一个datanode守护进程。
4)ResourceManager(JobTracker)JobTracker负责调度DataNode上的工作。每个DataNode有一个TaskTracker,它们执行实际工作。
5)NodeManager(TaskTracker)执行任务
6)DFSZKFailoverController高可用时它负责监控NN的状态,并及时的把状态信息写入ZK。它通过一个独立线程周期性的调用NN上的一个特定接口来获取NN的健康状态。FC也有选择谁作为Active NN的权利,因为最多只有两个节点,目前选择策略还比较简单(先到先得,轮换)。
7)JournalNode 高可用情况下存放namenode的editlog文件.
把集群上的配置文件发送到其他节点上的shell脚本
#根据自己的机器名修改后再使用
#!/bin/bash
HOSTS='wq1 wq2 wq3'
for HOST in ${HOSTS}
do
echo "++正在复制$1到$HOST的$2中..."
scp -rq ${1} ${HOST}:${2}
echo "--发送完成!"
done
什么样的情况下触发rebalance
在hdfs集群运行过程中,会有多种情况下导致不同机器上存储的数据量大小差别较大,运行过程中进行增加或减少的副本,或增加datanode节点
前提
:rebalance 是一个非自动的管理功能
为什么要Rebalance
:各个节点间的数据不均衡
需要Rebalance的几种情形
:增加datanode,增加磁盘数量,二者都有。
#该命令用于针对节点磁盘都不发生变动的情况进行
hdfs balancer -include wq1,wq2,wq3
hadoop balancer 无法侦查到这种 单个DataNode 的 disk 之间数据不平衡
- hadoop 2.x 也是可以可以迂回实现 disk 级别的rebalance
在 hdfs-site.xml中设置 每块磁盘的预留空间,局限性在于如果一个DataNode 挂载的好几款不同大小的磁盘,有50G 500G 1T 2T 3T,设置 30G,显然对50G影响是最大的
<property>
<name>dfs.datanode.du.reserved</name>
<value>82212254720</value>
</property>
#下面这个配置在hadoop 2.x不会生效,但在3.x有效
<property>
<name>dfs.disk.balancer.enabled</name>
<value>true</value>
</property>
- 让hdfs 优先往新盘 写入数据 ,改变 hdfs 的默认写入策略,监控 各个磁盘写入差额 启动自平衡
<property>
<name>dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold</name>
<value>20737418240</value> <!-- 20 GB -->
</property>
<property>
<name>dfs.datanode.available-space-volume-choosing-policy.balanced-space-preference-fraction</name>
<value>1.0f</value>
</property>
怎么处理大量的小文件
为什么:大量小文件带给namenode内存的压力,访问大量小文件速度远远小于访问几个大文件
hadoop自带的解决小文件问题的方案
首先明确小文件的来源,如果是从flume采集过来的,那么完全可以设置参数使其文件采集量达到块大小再传到hdfs上;
- Hadoop Archive
特点
:Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。
限制因素
:使用HAR时需要两点,第一,对小文件进行存档后,原文件并不会自动被删除,需要用户自己删除;第二,创建HAR文件的过程实际上是在运行一个mapreduce作业,因而需要有一个hadoop集群运行此命令。
此外,HAR还有一些缺陷:第一,一旦创建,Archives便不可改变。要增加或移除里面的文件,必须重新创建归档文件。第二,要归档的文件名中不能有空格,否则会抛出异常,可以将空格用其他符号替换(使用-Dhar.space.replacement.enable=true 和-Dhar.space.replacement参数)
- Sequence file
sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件
flume在向hdfs写文件时小文件解决办法
a1.sinks.k1.hdfs.path = hdfs://nameservice1/tmp/flume/jbw/%y-%m-%d/%H%M%S
#该属性可以设置为false
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 60
a1.sinks.k1.hdfs.roundUnit = minute
rollSize
默认值:1024,当临时文件达到该大小(单位:bytes)时,滚动成目标文件。如果设置成0,则表示不根据临时文件大小来滚动文件。
rollCount
默认值:10,当events数据达到该数量时候,将临时文件滚动成目标文件,如果设置成0,则表示不根据events数据来滚动文件。
利用secondarynamenode手动恢复namenode
通过观察datanode,namenode,secondary namenode下的VERSION这个文件你会注意到scondarynamenode的与namenode一致
#/opt/hadoop-2.7.7/data/dfs/data/current
#Sun Apr 04 00:38:37 CST 2021
storageID=DS-50ab0fb0-0f16-4b66-8c33-eab6b8c3ea62
clusterID=CID-9f9898aa-a9cf-4fc9-9aa9-4774e0393ded
cTime=0
datanodeUuid=bb12d0e9-8929-4980-8f51-23a2ca482ae8
storageType=DATA_NODE
layoutVersion=-56
/opt/hadoop-2.7.7/data/dfs/name/current
#Mon Mar 29 16:52:02 CST 2021
namespaceID=562029888
clusterID=CID-9f9898aa-a9cf-4fc9-9aa9-4774e0393ded
cTime=0
storageType=NAME_NODE
blockpoolID=BP-1164465073-192.168.236.236-1598873871309
layoutVersion=-63
/opt/hadoop-2.7.7/data/dfs/namesecondary/current
#Sun Apr 04 02:40:16 CST 2021
namespaceID=562029888
clusterID=CID-9f9898aa-a9cf-4fc9-9aa9-4774e0393ded
cTime=0
storageType=NAME_NODE
blockpoolID=BP-1164465073-192.168.236.236-1598873871309
layoutVersion=-63
把namenodesecondary拷贝这个dfs文件夹下重命名为name即可
- 如果一台机器的datanode挂掉之后或者说是要加入进来
执行下面这个命令前,把datanode的VERSION的clusterID的值换成想要加入的那个集群的clusterID
hadoop-daemon.sh start datanode