Hadoop

1.Hadoop历史版本和发行版公司
  1. Hadoop历史版本
    1.x版本系列:Hadoop版本当中的第二代开源版本,主要修复0.x版本的一些Bug等
    2.x版本系列:架构发生重大变化,引入了yarn平台许多新特性
    3.x版本系列:加入许多namenode新特性
  2. Hadoop三大发行版公司
  • 免费开源版本apache
    http://hadoop.apache.org优点:拥有全世界的开源贡献者,代码更新迭代版本比较快
    缺点:版本的升级,版本的维护,版本的兼容性,版本的补丁都可能考虑的不太周到
    apache所有软件下载地址:
    http://archive.apache.org/dist/
  • 免费开源版本hortonWorks
    https://hortonworks.com主要是雅虎主导Hadoop开发的副总裁,带领二十几个核心成员成立,核心产品HDP。HDF免费开源,并且提供一套web管理界面,供我们可以通过web界面管理我们的集群状态,web管理界面软件HDF网址(http://ambari.apache.org)
  • 软件收费版本ClouderaManager
    https://www.cloudera.com主要是美国的一家大数据公司在apache开源的hadoop的版本上,通过自己公司内部的各种补丁,实现版本间的稳定运行。
2.Hadoop架构模型

1.x版本架构模型

文件系统核心模块

NameNode:集群当中的主节点,管理元数据(文件的大小,文件的位置,文件的权限)主要用于管理集群当中的各种数据。

secondaryNameNode:主要用于Hadoop当中元数据信息的辅助管理

DataNode:集群当中的从节点,主要用于存储集群当中的数据

数据计算核心模块

JobTracker:接收用户的计算请求任务,并分配任务给从节点

TaskTracker:负责执行主节点JobTracker分配的任务

2.x版本架构模型

第一种:NameNode与ResourceManager单节点架构模型

文件系统核心模块

同1.x

数据计算核心模块

ResourceManager:接收用户的计算请求任务,并负责集群的资源分配(1个)

NodeManager:负责执行主节点AppMaster分配的任务

第二种:NameNode单节点与ResourceManager高可用架构模型

多个ResourceManager,Zookeeper实现高可用

第三种:NameNode高可用与ResourceManager单节点架构模型

多个NameNode,ZooKeeper实现高可用

第四种:NameNode与ResourceManager高可用架构模型

3.apache版本的Hadoop重新编译

为什么重新编译?

由于apache给出的Hadoop的安装包没有提供C程序访问的接口,所以在使用本地库(本地库可以用来做压缩,以及支持C程序等等)的时候会出现问题。

3.1 环境准备

准备Linux环境,内存4G以上,64位

虚拟机联网,关闭防火墙,关闭selinux

卸载自带的openjdk

3.2 上传jdk

(Hadoop2.7版本用jdk1.7,以上用jdk1.8),解压,添加环境变量

3.3 安装maven

使用3.x以上的版本,建议3.0.5

上传并解压

[root@node03 ~]# cd /export/softwares/
[root@node03 softwares]# ls
apache-maven-3.0.5-bin.tar.gz  findbugs-1.3.9.tar.gz  protobuf-2.5.0.tar.gz
apache-tomcat-6.0.53.tar.gz    hadoop-2.7.5-src.tar.gz    snappy-1.1.1.tar.gz
[root@node03 softwares]# tar zvxf apache-maven-3.0.5-bin.tar.gz -C ../servers/

添加环境变量

export MAVEN_HOME=/export/servers/apache-maven-3.0.5
export MAVEN_OPTS="-Xms4096m -Xmx4096m"
export PATH=$MAVEN_HOME/bin:$PATH

让配置生效

[root@node03 apache-maven-3.0.5]# source /etc/profile

配置maven仓库地址

[root@node03 servers]# mkdir mvnrepository
[root@node03 servers]# vim apache-maven-3.0.5/conf/settings.xml

添加如下内容

<localRepository>/export/servers/mvnrepository</localRepository>

添加阿里云镜像地址,会使jar包下载更快

在setting.xml中mirrors标签下添加

<mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
</mirror>
3.4 安装findbugs

解压

[root@node03 softwares]# tar zvxf findbugs-1.3.9.tar.gz -C ../servers/

配置环境变量

export FINDBUGS_HOME=/export/servers/findbugs-1.3.9
export PATH=$FINDBUGS_HOME/bin:$PATH
3.5 在线安装一些依赖包
[root@node03 findbugs-1.3.9]# yum -y install autoconf automake libtool cmake
[root@node03 findbugs-1.3.9]# yum -y install ncurses-devel
[root@node03 findbugs-1.3.9]# yum -y install openssl-devel
[root@node03 findbugs-1.3.9]# yum -y install lzo-devel zlib-devel gcc gcc-c++

bzip2压缩所需依赖包

[root@node03 findbugs-1.3.9]# yum -y install bzip2-devel
3.6 安装protobuf

解压并进行编译

[root@node03 softwares]# tar zvxf protobuf-2.5.0.tar.gz  -C ../servers/
[root@node03 protobuf-2.5.0]# ./configure 
[root@node03 protobuf-2.5.0]# make && make install
3.7 安装snappy
[root@node03 snappy-1.1.1]# cd /export/softwares/
[root@node03 snappy-1.1.1]# tar zvxf snappy-1.1.1.tar.gz -C ../servers/
[root@node03 snappy-1.1.1]# cd ../servers/snasnappy-1.1.1
[root@node03 snappy-1.1.1]# ./configure 
[root@node03 snappy-1.1.1]# make && make install
3.8 编译Hadoop源码
[root@node03 softwares]# cd /export/softwares/
[root@node03 softwares]# tar zvxf hadoop-2.7.5-src.tar.gz -C ../servers/
[root@node03 softwares]# cd /export/servers/hadoop-2.7.5-src/
[root@node03 hadoop-2.7.5-src]# mvn package -DskipTests -Pdist,native -Dtar -Drequire.snappy -e -X

编译后的Hadoop源码(即hadoop-2.7.5.tar.gz,2.9.2编译失败,报错了,说是规则不匹配,估计是其他安装包的版本问题,改成2.7.5成功了)

[root@node03 hadoop-2.7.5-src]# cd hadoop-dist/target/
[root@node03 target]# ls
antrun                    hadoop-2.7.5.tar.gz                 javadoc-bundle-options
classes                   hadoop-dist-2.7.5.jar               maven-archiver
dist-layout-stitching.sh  hadoop-dist-2.7.5-javadoc.jar       maven-shared-archive-resources
dist-tar-stitching.sh     hadoop-dist-2.7.5-sources.jar       test-classes
hadoop-2.7.5              hadoop-dist-2.7.5-test-sources.jar  test-dir
4.Hadoop安装

集群规划

服务器IP

192.168.217.100

192.168.217.110

192.168.217.120

主机名

node01

node02

node03

NameNode




SecondaryNameNode




DataNode




ResourceManager




NodeManager




第一步:上传apache hadoop包并解压
[root@node01 softwares]# rz
[root@node01 softwares]# tar zvxf hadoop-2.7.5-2.tar.gz -C ../servers/

查看本地库支持情况

[root@node01 hadoop-2.7.5]# bin/hadoop checknative
 20/09/21 08:19:58 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
 20/09/21 08:19:58 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
 Native library checking:
 hadoop: true /export/servers/hadoop-2.7.5/lib/native/libhadoop.so.1.0.0
 zlib: true /lib64/libz.so.1
 snappy: true /lib64/libsnappy.so.1
 lz4: true revision:99
 bzip2: true /lib64/libbz2.so.1
 openssl: false Cannot load libcrypto.so (libcrypto.so: cannot open shared object file: No such file or directory)!

可以看到支持snappy、lz4、bzip2等压缩算法,编译前则不支持

第二步:修改配置文件

配置文件较多,直接修改容易出错,采用nodepad++远程连接的方式进行修改,nodepad++安装NppFTP插件即可在菜单栏最后找到NppFTP,点击,在找到settings里的profile settings,输入相关参数即可。连接类型选择SFTP。

修改core-site.xml

<configuration>
    <!-- 指定集群的文件系统类型:分布式文件系统 -->
	<property>
		<name>fs.default.name</name>
		<value>hdfs://192.168.217.100</value>
	</property>
	<!-- 指定临时文件目录 -->
	<property>
		<name>hadoop.tmp.dir</name>
		<value>/export/servers/hadoop-2.7.5/hadoopDatas/tempDatas</value>
	</property>
	<!-- 缓冲区大小,根据工作中服务器性能动态调整 -->
	<property>
		<name>io.file.buffer.size</name>
		<value>4096</value>
	</property>
	<!-- 开启hdfs垃圾桶模式,删除掉的数据可以从垃圾桶回收,单位:分钟 -->
	<property>
		<name>fs.trash.interval</name>
		<value>10080</value>
	</property>
</configuration>

修改hdfs-site.xml

<configuration>
	<!-- 访问secondaryNameNode的地址和端口 -->
	<property>
		<name>dfs.namenode.secondary.http-address</name>
		<value>node01:50090</value>
	</property>
	<!-- 访问NameNode的地址和端口 -->
	<property>
		<name>dfs.namenode.http-address</name>
		<value>node01:50070</value>
	</property>
	<!-- 指定NameNode元数据的存放位置 -->
	<property>
		<name>dfs.namenode.name.dir</name>
		<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas,file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2</value>
	</property>
	<!-- 定义DataNode数据存储的节点位置,实际工作中,一般先确定磁盘的挂载目录,然后多个目录用,进行分割 -->
	<property>
		<name>dfs.datanode.data.dir</name>
		<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas,file:///export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas2</value>
	</property>
	<!-- 指定NameNode日志文件的存放目录 -->
	<property>
		<name>dfs.namenode.edits.dir</name>
		<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits</value>
	</property>
	<!-- 检查点 -->
	<property>
		<name>dfs.namenode.checkpoint.dir</name>
		<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/snn/name</value>
	</property>
	<!--  -->
	<property>
		<name>dfs.namenode.checkpoint.edits.dir</name>
		<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/dfs/snn/edits</value>
	</property>
	<!-- 文件切片的副本个数 -->
	<property>
		<name>dfs.replication</name>
		<value>3</value>
	</property>
	<!-- 设置hdfs的文件权限 -->
	<property>
		<name>dfs.permissions</name>
		<value>false</value>
	</property>
	<!-- 设置一个文件切片的大小:128M -->
	<property>
		<name>dfs.blocksize</name>
		<value>134217728</value>
	</property>
</configuration>

修改hadoop-env.sh

export JAVA_HOME=/export/servers/jdk1.8.0_261/

修改mapred.xml

<configuration>
	<!-- 开启MapReduce小任务模式 -->
	<property>
		<name>mapreduce.job.ubertask.enable</name>
		<value>true</value>
	</property>
	<!-- 设置历史任务的主机和端口 -->
	<property>
		<name>mapreduce.jobhistory.address</name>
		<value>node01:10020</value>
	</property>
	<!-- 设置网页访问历史任务的主机和端口 -->
	<property>
		<name>mapreduce.jobhistory.webapp.address</name>
		<value>node01:19888</value>
	</property>
	
</configuration>

修改yarn-site.xml

<configuration>
	<!-- 配置yarn主节点的位置 -->
	<property>
		<name>yarn.resourcemanager.hostname</name>
		<value>node01</value>
	</property>
	<property>
		<name>yarn.nodemanager.aux-services</name>
		<value>mapreduce_shuffle</value>
	</property>
	<!-- 开启日志聚合功能 -->
	<property>
		<name>yarn.log-aggregation-enable</name>
		<value>true</value>
	</property>
	<!-- 设置聚合日志在hdfs的保存时间,单位:秒 -->
	<property>
		<name>yarn.log-aggregation.retain.seconds</name>
		<value>604800</value>
	</property>
	<!-- 设置yarn集群内存分配方案 -->
	<property>
		<name>yarn.nodemanager.resource.memory-mb</name>
		<value>20480</value>
	</property>
	<property>
		<name>yarn.scheduler.minimum-allocation-mb</name>
		<value>2048</value>
	</property>
	<property>
		<name>yarn.nodemanager.vmem-pmem-ratio</name>
		<value>2.1</value>
	</property>
</configuration>

修改mapred-env.sh

export JAVA_HOME=/export/servers/jdk1.8.0_261/

修改slaves

node01
node02
node03

创建相应的目录

mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/tempDatas/
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas2
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/nn/edits/
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/snn/name/
mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/dfs/snn/edits/

安装包的分发

[root@node01 hadoopDatas]# cd /export/servers/
[root@node01 servers]# scp -r hadoop-2.7.5/ node02:$PWD
[root@node01 servers]# scp -r hadoop-2.7.5/ node03:$PWD
第三步:配置hadoop环境变量

三台机器都要进行配置

[root@node03 hadoop-2.7.5]# vim /etc/profile
export HADOOP_HOME=/export/servers/hadoop-2.7.5
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
[root@node03 hadoop-2.7.5]# source /etc/profile
第四步:启动集群

要启动Hadoop集群,需要启动HDFS和YARN两个模块。注意:首次启动HDFS时,必须对其进行格式化操作。本质上是一些清理和准备工作,因为此时的HDFS在物理上还是不存在的

hdfs namenode -format 或

hadoop namenode -format

准备启动

第一台机器上执行

[root@node01 hadoop-2.7.5]# cd /export/servers/hadoop-2.7.5/
[root@node01 hadoop-2.7.5]# bin/hdfs namenode -format
[root@node01 hadoop-2.7.5]# sbin/start-dfs.sh 
Starting namenodes on [node01]
node01: starting namenode, logging to /export/servers/hadoop-2.7.5/logs/hadoop-root-namenode-node01.out
node02: starting datanode, logging to /export/servers/hadoop-2.7.5/logs/hadoop-root-datanode-node02.out
node03: starting datanode, logging to /export/servers/hadoop-2.7.5/logs/hadoop-root-datanode-node03.out
node01: starting datanode, logging to /export/servers/hadoop-2.7.5/logs/hadoop-root-datanode-node01.out
Starting secondary namenodes [node01]
node01: starting secondarynamenode, logging to /export/servers/hadoop-2.7.5/logs/hadoop-root-secondarynamenode-node01.out
[root@node01 hadoop-2.7.5]# sbin/start-yarn.sh 
starting yarn daemons
starting resourcemanager, logging to /export/servers/hadoop-2.7.5/logs/yarn-root-resourcemanager-node01.out
node02: starting nodemanager, logging to /export/servers/hadoop-2.7.5/logs/yarn-root-nodemanager-node02.out
node03: starting nodemanager, logging to /export/servers/hadoop-2.7.5/logs/yarn-root-nodemanager-node03.out
node01: starting nodemanager, logging to /export/servers/hadoop-2.7.5/logs/yarn-root-nodemanager-node01.out
[root@node01 hadoop-2.7.5]# sbin/mr-jobhistory-daemon.sh start historyserver

看启动时的提示信息,是否与配置的一致,是否正常启动。其他问题可以到logs中查看

通过jps查看运行的java进程

[root@node01 hadoop-2.7.5]# jps
4050 DataNode
4467 ResourceManager
4963 QuorumPeerMain  #zookeeper
5187 Jps
3943 NameNode
4574 NodeManager
5150 JobHistoryServer
4223 SecondaryNameNode
[root@node02 servers]# jps
3555 QuorumPeerMain
3142 DataNode
3686 Jps
3335 NodeManager

三个端口查看界面

http://node01:50070/explorer.html#/ 查看hdfs

http://node01:8088/cluster 查看yarn集群

http://node01:19888/jobhistory 查看历史完成任务

5.Hadoop核心-HDFS
5.1 Hadoop概述

HDFS(Hadoop Distributed File System)是Apache Hadoop项目的一个子项目,Hadoop非常适合存储大型数据,其就是使用HDFS作为存储系统,HDFS使用多台计算机存储文件,并且提供统一的访问接口,像是访问一个普通文件系统一样使用分布式文件系统。

Doug Cutting在做Lucene的时候,需要编写一个爬虫服务,这个爬虫写的并不顺利,遇到了一些问题,诸如:

如何存储大规模数据,如何保证集群的可伸缩性,如何动态容错等。

2013年,Google发布了三篇论文,被称为三驾马车,其中有一篇叫做GFS,描述了GOOGLE内部的GFS分布式大规模文件系统,具有强大的可伸缩性和容错性。

Doug Cutting后来根据GFS的论文,创造了一个新的文件系统,叫做HDFS

5.2 HDFS应用场景

适合的应用场景:

存储非常大的文件

采用流式的数据访问方式,即一次写入,多次读取

运行在商业硬件上

需要高容错性

不适合的应用场景:

低延迟的数据访问

大量小文件

多方读写

5.3 HDFS的架构

hdfs是一个主/从(master/slave)体系结构

hdfs由四部分组成:HDFS Client、NameNode、DataNode和Secondary NameNode

  1. Client:就是客户端
  • 文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后存储
  • 与NameNode交互,获取文件的位置信息
  • 与DataNode交互,读取或写入数据
  • Client提供一些命令管理和访问hdfs,比如启动和关闭hdfs
  1. NameNode:就是master,它是一个主管、管理者
  • 管理hdfs的名称空间
  • 管理数据块的映射信息
  • 配置副本策略
  • 处理客户端读写请求
  1. DataNode:就是Slave,NameNode下达命令,DataNode执行实际操作
  • 存储实际的数据块
  • 执行数据块的读写操作
  1. SecondaryNameNode:并非NameNode的热备。当NameNode挂掉的时候,并不能替换他
  • 辅助NameNode,分担其工作量
  • 定期合并fsimage和fsedits,并推送给NameNode
  • 在紧急情况下可辅助恢复NameNode
5.4 NameNode和DataNode的作用

NameNode作用

  • 在内存中保存者整个文件系统的名称空间和文件数据块的地址映射
  • 整个hdfs可存储的文件数受限于NameNode的内存大小
  1. NameNode元数据信息 文件名,文件目录结构,文件属性(生成时间,副本数,权限),每个文件的块列表,定期持久化到fsimage和edits上
  2. NameNode文件操作 NameNode负责文件元数据的操作 DataNode负责处理文件内容的读写请求,数据流不经过NameNode
  3. NameNode副本 文件数据块到底存放到那些DataNode上,是由NameNode决定的,根据全局的情况
  4. NameNode心跳机制

DataNode的作用

  1. 以数据块的形式存储hdfs文件
  2. 响应客户端读写请求
  3. 周期性向NameNode汇报心跳信息
  4. 周期性汇报数据块信息
  5. 周期性汇报缓存数据块信息
5.5 Hadoop副本机制和机架感知

hdfs副本机制

所有的文件都是以block块的方式存放到hdfs文件系统当中,作用如下

  1. 一个文件的大小可能大于集群中任意一个磁盘,引入块机制,可以很好的解决这个问题
  2. 使用块作为文件存储的逻辑单位可以简化存储子系统
  3. 块非常适合用于数据备份进而提供数据容错能力

Hadoop1.x中block块默认大小为64MHadoop2.x中默认大小是128M,可以通过hdfs-site.xml中指定

<!-- 设置一个文件切片的大小:128M -->
<property>
    <name>dfs.blocksize</name>
    <value>134217728</value>
</property>

机架感知

  1. 第一个副本放在和Client相同机架的节点上(如果Client不在集群范围,第一个Node是随机选取不太满或者不太忙的节点,离上传Client最近的节点(减少网络传输的时间))
  2. 第二个副本放在与第一个机架不同的机架中的任意节点上
  3. 第三个副本放在与第二个节点所在机架的不同的节点.
6.hdfs命令行使用

ls

格式:hdfs dfs -ls

作用:类似于Linux的ls命令

[root@node02 ~]# hdfs dfs -ls /

[root@node02 ~]# hdfs dfs -ls -R /

作用:递归执行ls

mkdir

格式:hdfs dfs -mkdir [-p]

作用:创建目录。-p递归创建

[root@node02 ~]# hdfs dfs -mkdir /hello
[root@node02 ~]# hdfs dfs -mkdir -p /dir1/dir2

put

格式:hdfs dfs -put

作用:将单个源文件src从本地文件系统拷贝到目标文件系统dst。也可以从标准输入中读取输入,写入目标文件系统中

[root@node02 ~]# hdfs dfs -put /root/a.txt /hello

moveFromLocal

格式:hdfs dfs -moveFromLocal

作用:和put类似,但是移动后会删除源文件

[root@node02 ~]# hdfs dfs -moveFromLocal /root/a.txt /dir1

get

格式:hdfs dfs -get [-ignorecrc] [-crc]

作用:将文件拷贝到本地文件系统。CRC校验失败的文件通过-ignorecrc选项拷贝,文件和crc校验和可以通过-crc拷贝

[root@node02 ~]# hdfs dfs -get /hello/a.txt ./

也可以在浏览器中打开,点击download下载,此时必须做域名映射(windows中在C盘windows,system32,drivers下的hosts文件中作域名映射)

mv

格式:hdfs dfs -mv

作用:将hdfs的文件从src移动到dst,不能跨文件系统

rm

格式:hdfs dfs -rm [-r] [-skipTrash] path1 [path2 …]

作用:删除一个或多个文件,只能是文件或非空目录。-r递归删除,-skipTrash选项在有回收站的情况下,跳过回收站直接删除。

[root@node02 ~]# hdfs dfs -rm -r /dir1
20/09/22 02:42:16 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/09/22 02:42:16 INFO fs.TrashPolicyDefault: Moved: 'hdfs://192.168.217.100/dir1' to trash at: hdfs://192.168.217.100/user/root/.Trash/Current/dir1
Moved: 'hdfs://192.168.217.100/dir1' to trash at: hdfs://192.168.217.100/user/root/.Trash/Current

其自动创建了一个目录用来存放删除的文件。

cp

格式:hdfs dfs -cp [src2 …]

作用:将文件拷贝到目标路径中如果dst为目录,可以将多个文件拷贝到该目录

-f 覆盖如果已存在

-p保留文件属性(时间戳,所有权)

cat

格式:hdfs dfs -cat [path2 …]

作用:查看文件内容

chmod

格式:hdfs dfs -chmod [-R] …]

改变文件权限。-R表示递归修改。使用这一命令的用户必须是文件的所属用户或者超级用户

chown

格式:hdfs dfs -chown [-R] : …]

作用:改变文件所属的用户和用户组。-R递归修改,使用这一命令的用户必须是文件的所属用户或者超级用户

appendToFile

格式:hdfs dfs -appendToFile

作用:追加一个或多个文件到hdfs指定文件中,也可以从命令行读取输入

[root@node02 hadoop]# hdfs dfs -appendToFile core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml /config.xml
7 hdfs高级命令的使用命令
7.1 HDFS文件限额配置

在多人使用HDFS的情况下,配置设置非常重要。特别是在Hadoop处理大量资料的环境,如果没有配额管理,很容易把所有的空间用完造成别人无法存取。HDFS的配额设定是针对目录而不是针对账号,可以让每个账号仅操作一个目录,然后对目录设置配置

hdfs文件的限额配置允许我们以文件个数,或者文件大小来限制我们在某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘等限制每个用户允许上传的最大的文件的量

[root@node02 hadoop]# hdfs dfs -mkdir /user/root/dir
[root@node02 hadoop]# hdfs dfs -count -q -h  /user/root/dir  #查看配额信息
        none             inf            none             inf            1            0                  0 /user/root/dir

数量限额

[root@node02 hadoop]# hdfs dfsadmin -setQuota 2 dir #本身就在root下,绝对路径和相对路径均可
[root@node02 hadoop]# hdfs dfs -count -q -h  /user/root/dir #数量限额为2,但只能上传一个文件,目录也算一个
           2               1            none             inf            1            0                  0 /user/root/dir
[root@node02 ~]# hdfs dfs -put a.txt dir
[root@node02 ~]# vim b.txt
[root@node02 ~]# hdfs dfs -put b.txt dir
put: The NameSpace quota (directories and files) of directory /user/root/dir is exceeded: quota=2 file count=3
[root@node02 ~]# hdfs dfsadmin -clrQuota dir #清除限额

空间大小限额

在设置空间配额时,设置的空间至少是文件占用的block_size*3大小,否则上传失败

[root@node02 ~]# hdfs dfsadmin -setSpaceQuota 4K /user/root/dir
[root@node02 ~]# hdfs dfs -put b.txt dir
20/09/22 07:25:10 WARN hdfs.DFSClient: DataStreamer Exception
org.apache.hadoop.hdfs.protocol.DSQuotaExceededException: The DiskSpace quota of /user/root/dir is exceeded: quota = 4096 B = 4 KB but diskspace consumed = 402653196 B = 384.00 MB

清除空间配额

[root@node02 ~]# hdfs dfsadmin -clrSpaceQuota dir

生成任意大小的文件

dd if=/dev/zero of=1.txt bs=1M count=2 #生成2M的文件
7.2 hdfs的安全模式

安全模式是Hadoop的一种保护机制,用于保证集群中数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式的时候会检查数据块的完整性。

假设设置的副本数为3,只存在两个副本,则副本率为2/3=0.666,hdfs默认的副本率为0.999,因此系统会自动复制副本到其他datanode。如果系统中有5个副本,那么系统也会自动删除多余的两个副本

安全模式下,文件系统只接受读数据请求,而不接收删除、修改等变更请求。当整个系统达到安全标准时,HDFS自动离开安全模式

安全模式操作命令

[root@node02 ~]# hdfs dfsadmin -safemode get    #获取安全模式状态
[root@node02 ~]# hdfs dfsadmin -safemode enter  #进入安全模式
[root@node02 ~]# hdfs dfsadmin -safemode leave  #离开安全模式
8.HDFS基准测试

实际生产环境中,hadoop集群搭建完成之后,第一件事情就是进行压力测试,测试我们的hadoop集群的读取和写入速度,测试网络带宽是否足够等一些基准测试

8.1 测试写入速度

向hdfs文件系统写入数据,10个文件,每个文件10M,文件存放到/benchmarks/TestDFSIO中

[root@node02 ~]# hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -write -nrFiles 10 -fileSize 10MB

完成后查看结果

[root@node02 ~]# hdfs dfs -text /benchmarks/TestDFSIO/io_write/part-00000
f:rate	122378.766
f:sqrate	1586157.0
l:size	104857600
l:tasks	10
l:time	8880
[root@node02 ~]# cat TestDFSIO_results.log 
----- TestDFSIO ----- : write
            Date & time: Tue Sep 22 08:00:18 PDT 2020
        Number of files: 10
 Total MBytes processed: 100
      Throughput mb/sec: 11.26
 Average IO rate mb/sec: 12.24
  IO rate std deviation: 2.97
     Test exec time sec: 14.19
8.2 测试读取速度

测试hdfs读取文件性能

在HDFS文件系统中读入10个文件,每个文件10M

[root@node02 hadoop-2.7.5]# hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB

查看读取结果

[root@node02 hadoop-2.7.5]# cat TestDFSIO_results.log 
----- TestDFSIO ----- : read
            Date & time: Thu Sep 24 05:53:43 PDT 2020
        Number of files: 10
 Total MBytes processed: 100
      Throughput mb/sec: 19.92
 Average IO rate mb/sec: 23.62
  IO rate std deviation: 10.71
     Test exec time sec: 15.84
8.3 清除测试数据
[root@node02 hadoop-2.7.5]# hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
9.HDFS写入和读取过程

写入过程

  1. 请求上传a.txt->NameNode
  2. NameNode:检测上传权限
  3. NameNode:可以上传
  4. 请求上传block1->NameNode
  5. 根据集群中dn的block信息和机架感知,选出可以上传的三个主机
  6. 返回DataNode列表:dn1,dn2,dn3
  7. Client与DataNode之间建立pipeline
  8. Client向DN传送数据,传递的单位:packet(64K)
  9. DataNode将packet信息进行缓存并传给下一个DataNode
  10. 最后一个DataNode收到数据,向前发送应答ack

读取过程

  1. 向name请求,下载/a.txt
  2. 权限检查,文件block列表权限,选出每一个block对应的主机列表
  3. 返回block主机列表
  4. 和每一个block所在的主机建立pipeline
  5. 开始数据的读取,读取的单位:packet(64K)
  6. 将block进行合并,合并成一个完整的文件
10 Hadoop的元数据辅助管理

Hadoop集群中NameNode的所有元数据信息都保存在了fsimage和edits文件当中,这两个文件记录了所有数据的元数据信息,元数据信息的保存目录配置在了hdfs-site.xml中

<!-- 指定NameNode元数据的存放位置 -->
<property>
    <name>dfs.namenode.name.dir</name>
    <value>file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas,file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2</value>
</property>
<!-- 指定NameNode日志文件的存放目录 -->
<property>
    <name>dfs.namenode.edits.dir</name>
    <value>file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits</value>
</property>
1.fsimage和edits详解
  • edits
  • edits存放了客户端最近一段时间的操作日志
  • 客户端对HDFS写文件时首先被记录在edits文件中
  • edits修改时元数据也会更新
  • fsimage
  • NameNode中关于元数据的镜像,一般为检查点,fsimage存放了一份比较完整的元数据信息
  • 随着edits内容增大,就需要在一定时间点和fsimage合并
2.fsimage中的文件信息查看

使用命令hdfs oiv

[root@node01 namenodeDatas]# cp current/fsimage_0000000000000000212 /root/
[root@node01 ~]# hdfs oiv -i fsimage_0000000000000000212 -p XML -o my_fsimage.xml
3.edits中文件信息查看

使用命令hdfs oev

[root@node01 current]# cp edits_0000000000000000213-0000000000000000213 /root/
[root@node01 current]# cd 
[root@node01 ~]# hdfs oev -i edits_0000000000000000213-0000000000000000213 -p XML -o myedits.xml
4.SecondaryNameNode辅助管理fsimage和edits文件

SecondaryNameNode定期合并fsimage和edits,把edits控制在一个范围内

配置SecondaryNameNode

hdfs-site.xml

<!-- 访问secondaryNameNode的地址和端口 -->
<property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>node01:50090</value>
</property>

core-site.xml(不配置,保持默认也可)

<!-- 多久记录一次hdfs镜像,默认1小时 -->
<property>
    <name>fs.checkpoint.period</name>
    <value>3600</value>
</property>
<!-- 一次记录多大,默认64M -->
<property>
    <name>fs.checkpoint.size</name>
    <value>67108864</value>
</property>
11.HDFS的API操作
11.1 配置windows下的Hadoop环境

在Windows系统需要配置Hadoop运行环境,否则直接运行代码会出现以下问题

缺少winutils.exe

Could not locate executable null \bin\winutils.exe in the hadoop binaries

缺少hadoop.dll

Unable to load native-hadoop library for your platform…using buildin-Javaclasser where applicable

步骤:

  1. 将Hadoop2.7.5文件夹拷贝到一个没有中文没有空格的路径下
  2. 配置环境变量HADOOP_HOME,并将%HADOOP_HOME%\bin添加到path中
  3. 将winutils.exe和hadoop.dll文件拷贝到hadoop的bin目录下
11.2 导入Maven依赖
<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-mapreduce-client-core</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
11.3 使用URL访问数据(了解)
package com.wangbin;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class hdfs_api {
    @Test
    public void urlUtils() throws IOException {
        //1.注册url
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
        //2.获取hdfs文件输入流
        InputStream inputStream = new URL("hdfs://node01:8020/a.txt").openStream();
        //3.获取本地文件的输出流
        FileOutputStream outputStream = new FileOutputStream(new File("D:\\hello.txt"));
        //4.实现文件的拷贝
        IOUtils.copy(inputStream,outputStream);
        //5.关流
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
    }

}
11.4 使用文件系统访问数据(掌握)

涉及的主要类

  • Configuration
  • 该类的对象封装了客户端或者服务器的配置
  • FileSystem
  • 该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法

获取FileSystem的几种方式

  • 第一种方式
public void getFileSystem1() throws IOException {
    //1.创建Configuration对象
    Configuration configuration = new Configuration();
    //2.设置文件系统的类型
    configuration.set("fs.defaultFS","hdfs://node01:8020");
    //3.获取指定的文件系统
    FileSystem fileSystem = FileSystem.get(configuration);
    //4.输出
    System.out.println(fileSystem);
}
  • 第二种方式
@Test
public void getFileSystem2() throws IOException, URISyntaxException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration());
    System.out.println(fileSystem);
}
  • 第三种方式
@Test
public void getFileSystem3() throws IOException {
    Configuration configuration = new Configuration();
    configuration.set("fs.defaultFS","hdfs://node01:8020");
    FileSystem fileSystem = FileSystem.newInstance(configuration);
    System.out.println(fileSystem);
}
  • 第四种方式
@Test
public void getFileSystem4() throws IOException, URISyntaxException {
    FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://node01:8020"),new Configuration());
    System.out.println(fileSystem);
}

遍历HDFS中所有文件

public void listFiles() throws URISyntaxException, IOException {
    //1.获取FileSystem实例
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration());
    //2.调用方法listFiles获取/目录下所有的文件信息
    RemoteIterator<LocatedFileStatus> iterator = fileSystem.listFiles(new Path("/"), true);
    //3.遍历迭代器
    while (iterator.hasNext()){
        LocatedFileStatus fileStatus = iterator.next();
        //获取文件的绝对路径hdfs://node01:8020/xxx
        System.out.println(fileStatus.getPath() + "----" + fileStatus.getPath().getName());
        //文件的block信息
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
        System.out.println("block数:"+blockLocations.length);
    }
}

HDFS上创建文件夹

@Test
public void mkdirsTest() throws URISyntaxException, IOException {
    //获取FileSystem实例
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
    //创建文件夹
    boolean b = fileSystem.mkdirs(new Path("/aaa/bbb/ccc"));
    //创建文件
    fileSystem.mkdirs(new Path("/aaa/bbb/ccc/a.txt"));
    System.out.println(b);
    //关闭FileSystem
    fileSystem.close();
}

下载文件

//方式1
@Test
public void getFileToLocal()throws Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration());
    FSDataInputStream inputStream = fileSystem.open(new Path("/a.txt"));
    FileOutputStream outputStream = new FileOutputStream(new File("D://a.txt"));
    IOUtils.copy(inputStream,outputStream);
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);
}
//方式2
@Test
public void getFileToLocal2()throws Exception{
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration());
    fileSystem.copyToLocalFile(new Path("/a.txt"),new Path("D://b.txt"));
    fileSystem.close();
}

文件上传

@Test
public void uploadFile() throws IOException, URISyntaxException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration());
    fileSystem.copyFromLocalFile(new Path("D:\\1.jpg"),new Path("/"));
}
11.5 HDFS访问权限控制

停止运行hadoop,修改hdfs-site.xml

<!-- 设置hdfs的文件权限 -->
<property>
    <name>dfs.permissions</name>
    <value>true</value>
</property>

远程拷贝到node01和node02

[root@node01 hadoop]# scp hdfs-site.xml node02:$PWD    
[root@node01 hadoop]# scp hdfs-site.xml node03:$PWD

再次运行hadoop即可

修改/a.txt权限:

[root@node01 hadoop]# hdfs dfs -chmod 600 /a.txt

再次从Windows中下载,发现报错:

org.apache.hadoop.security.AccessControlException: Permission denied: user=18295, access=READ, inode="/a.txt":root:supergroup

通过伪装用户进行下载

FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration(),"root");
11.6 小文件合并

由于hadoop擅长存储大文件,因为大文件的元数据信息比较少如果hadoop集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大增加集群管理元数据的内存压力,所以实际工作当中,如果有必要一定要将小文件合并为大文件进行一起处理。

在HDFS的shell命令模式下,可以通过命令行将许多的hdfs文件合并成一个大文件下载到本地

hdfs dfs -put core-site.xml yarn-site.xml mapred-site.xml / 
hdfs dfs -getmerge /*.xml ./big.xml

上传文件时,将小文件合并成一个大文件:

@Test
public void mergeFile() throws URISyntaxException, IOException, InterruptedException {
    //1、获取FileSystem
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"),new Configuration(),"root");
    //2、获取hdfs大文件输出流
    FSDataOutputStream outputStream = fileSystem.create(new Path("/big.txt"));
    //3、获取一个本地文件系统
    LocalFileSystem localFileSystem = FileSystem.getLocal(new Configuration());
    //4、获取本地文件夹下所有文件的详情
    FileStatus[] fileStatuses = localFileSystem.listStatus(new Path("D:\\input"));
    //5、遍历每个文件,获取每个文件的输入流
    for(FileStatus fileStatus:fileStatuses){
        FSDataInputStream inputStream = localFileSystem.open(fileStatus.getPath());
        //6、将小文件的数据复制到大文件
        IOUtils.copy(inputStream,outputStream);
        IOUtils.closeQuietly(inputStream);
    }
    //7、关闭流
    IOUtils.closeQuietly(outputStream);
    localFileSystem.close();
    fileSystem.close();
}
12.HDFS的高可用机制

在Hadoop中,NameNode所处位置是非常重要的,整个HDFS文件系统的元数据信息都由NameNode来管理,NameNode的可用性直接决定了Hadoop的可用性,一旦NameNode进程不能工作了。就会影响整个集群的正常使用。

在典型的Hadoop集群中,两台独立的机器被配置为NameNode。在工作集群中,NameNode机器中的一个处于Active状态,另一个处于,Standby状态。Active的NameNode负责集群中所有客户端操作,而standby充当服务器。Standby机器保持足够的状态以提供快速故障切换。

13.HDFS的联邦机制

单NameNode的架构使得HDFS在集群扩展性和性能上都有潜在的问题,当集群达到一定规模的时候,NameNode进程使用的内存可能达到上百G,NameNode成为性能的瓶颈。因而提出了NameNode水平扩展方案-Federation

Federation是NameNode的联邦,也就是会有多个NameNode。多个NameNode的情况意味着有多个namespace,区别于HA模式下的多NameNode,他们是拥有着同一个namespace。