Hadoop是Apache软件基金会下一个开源分布式计算平台,以HDFS(Hadoop Distributed File System)、MapReduce(Hadoop2.0加入了YARN,Yarn是资源调度框架,能够细粒度的管理和调度任务,还能够支持其他的计算框架,比如spark)为核心的Hadoop为用户提供了系统底层细节透明的分布式基础架构。hdfs的高容错性、高伸缩性、高效性等优点让用户可以将Hadoop部署在低廉的硬件上,形成分布式系统。目前最新版本已经是3.x了,[官方文档]
HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了很多便利。HDFS 源于 Google 在2003年10月份发表的GFS(Google File System) 论文。 它其实就是 GFS(Google File System) 的一个克隆版本。
之所以选择 HDFS 存储数据,因为 HDFS 具有以下优点:
当然 HDFS 也有它的劣势,并不适合所有的场合:
HDFS 采用Master/Slave的架构来存储数据,这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。下面我们分别介绍这四个组成部分 :
Client就是客户端
文件切分。文件上传 HDFS 的时候,Client 将文件切分成 一个一个的- Block,然后进行存储。与 NameNode 交互,获取文件的位置信息。与 DataNode 交互,读取或者写入数据。Client 提供一些命令来管理 HDFS,比如启动或者关闭HDFS。Client 可以通过一些命令来访问 HDFS。
NameNode就是 master,它是一个主管、管理者。
3、DataNode(DN)
DataNode就是Slave。NameNode 下达命令,DataNode 执行实际的操作。
存储实际的数据块。执行数据块的读/写操作。4、Secondary NameNode(2NN)
Secondary NameNode并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
PS: 1.NN的元数据为了读写速度块是写在内存里的,FsImage只是它的一个镜像保存文件 2.当每输入一个增删改操作,EditLog都会单独生成一个文件,最后EL会生成多个文件 3.2NN不是NN的备份(但可以做备份),它的主要工作是帮助NN合并edits log,减少NN启动时间。 4.拓扑距离:根据节点网络构成的树形结构计算最短路径 5.机架感知:根据拓扑距离得到的节点摆放位置
【第一步】Client调用FileSystem.open()方法
【第二步】Client调用输入流的read()方法
【第三步】关闭FSDataInputStream
【第一步】Client调用FileSystem的create()方法
【第二步】Client调用输出流的write()方法
【第三步】Client调用流的close()方法
Apache Yarn(Yet Another Resource Negotiator的缩写)是hadoop集群资源管理器系统,Yarn从hadoop 2引入,最初是为了改善MapReduce的实现,但是它具有通用性,同样执行其他分布式计算模式。
Yarn特点:
Yarn从整体上还是属于master/slave模型,主要依赖于三个组件来实现功能,第一个就是ResourceManager,是集群资源的仲裁者,它包括两部分:一个是可插拔式的调度Scheduler,一个是ApplicationManager,用于管理集群中的用户作业。第二个是每个节点上的NodeManager,管理该节点上的用户作业和工作流,也会不断发送自己Container使用情况给ResourceManager。第三个组件是ApplicationMaster,用户作业生命周期的管理者它的主要功能就是向ResourceManager(全局的)申请计算资源(Containers)并且和NodeManager交互来执行和监控具体的task。架构图如下:
RM是一个全局的资源管理器,管理整个集群的计算资源,并将这些资源分配给应用程序。包括:
RM关键配置参数:
应用程序级别的,管理运行在YARN上的应用程序。包括:
AM关键配置参数:
YARN中每个节点上的代理,它管理Hadoop集群中单个计算节点。包括:
NM关键配置参数:
Container是YARN中资源的抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等。Container由AM向RM申请的,由RM中的资源调度器异步分配给AM。Container的运行是由AM向资源所在的NM发起。
一个应用程序所需的Container分为两大类:
以上两类Container可能在任意节点上,它们的位置通常而言是随机的,即AM可能与它管理的任务运行在一个节点上。
Application在Yarn中的执行过程如下图所示:
FIFO调度器的优点是简单易懂不需要任何配置,但是不适合共享集群。大型应用会占用集群中的所有资源,所以每个应用必须等待直到轮到自己运行。在一个共享集群中,更适合使用容量调度器或公平调度器。这两种调度器都允许长时间运行的作业能及时完成,同时也允许正在进行较小临时查询的用户能够在合理时间内得到返回结果。
容量调度器允许多个组织共享一个Hadoop集群,每个组织可以分配到全部集群资源的一部分。每个组织被配置一个专门的队列,每个队列被配置为可以使用一定的集群资源。队列可以进一步按层次划分,这样每个组织内的不同用户能够共享该组织队列所分配的资源。在一个队列内,使用FIFO调度策略对应用进行调度。
公平调度是一种对于全局资源,对于所有应用作业来说,都均匀分配的资源分配方法。默认情况,公平调度器FairScheduler基于内存来安排公平调度策略。也可以配置为同时基于内存和CPU来进行调度(Dominant Resource Fairness)。在一个队列内,可以使用FIFO、FAIR、DRF调度策略对应用进行调度。FairScheduler允许保障性的分配最小资源到队列。
MapReduce是一种编程模型(没有集群的概念,会把任务提交到yarn集群上跑),用于大规模数据集(大于1TB)的并行运算。概念"Map(映射)"和"Reduce(归约)",是它们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。(MapReduce在企业里几乎不再使用了,稍微了解即可)
2)MapReduce运行流程
作业的运行过程主要包括如下几个步骤:
1、作业的提交 2、作业的初始化 3、作业任务的分配 4、作业任务的执行 5、作业执行状态更新 6、作业完成
具体作业执行过程的流程图如下图所示:
在MR的代码中调用waitForCompletion()方法,里面封装了Job.submit()方法,而Job.submit()方法里面会创建一个JobSubmmiter对象。当我们在waitForCompletion(true)时,则waitForCompletion方法会每秒轮询作业的执行进度,如果发现与上次查询到的状态有差别,则将详情打印到控制台。如果作业执行成功,就显示作业计数器,否则将导致作业失败的记录输出到控制台。
其中JobSubmmiter实现的大概过程如下:
可以通过参数:
mapreduce.job.ubertask.enable #是否启用uber模式mapreduce.job.ubertask.maxmaps #ubertask的最大map数mapreduce.job.ubertask.maxreduces #ubertask的最大reduce数mapreduce.job.ubertask.maxbytes #ubertask最大作业大小mapreduce.map.memory.mbmapreduce.map.cpu.vcoresmapreduce.reduce.memory.mbmapreduce.reduce.cpu.vcoresapplication master提交申请后,资源管理器为其按需分配资源,这时,application master就与节点管理器通信来启动容器。该任务由主类YarnChild的一个java应用程序执行。在运行任务之前,首先将所需的资源进行本地化,包括作业的配置,jar文件等。接下来就是运行map和reduce任务。YarnChild在单独的JVM中运行。
每个作业和它的每个任务都有一个状态:作业或者任务的状态(运行中,成功,失败等),map和reduce的进度,作业计数器的值,状态消息或描述当作业处于正在运行中的时候,客户端可以直接与application master通信,每秒(可以通过参数mapreduce.client.progressmonitor.pollinterval设置)轮询作业的执行状态,进度等信息。
mapreduce确保每个reduce的输入都是按照键值排序的,系统执行排序,将map的输入作为reduce的输入过程称之为shuffle过程。shuffle也是我们优化的重点部分。shuffle流程图如下图所示:
这里准备三台VM虚拟机 |OS|hostname| ip | 运行角色| |--|--|--|--| |Centos8.x| hadoop-node1 | 192.168.0.113 | namenode,datanode ,resourcemanager,nodemanager| |Centos8.x| hadoop-node2 | 192.168.0.114 | secondarynamedata,datanode,nodemanager | |Centos8.x| hadoop-node3 | 192.168.0.115 | datanode,nodemanager|
下载地址:https://dlcdn.apache.org/hadoop/common/
这里下载源码包安装,默认的编译好的文件不支持snappy压缩,因此我们需要自己重新编译。
$ mkdir -p /opt/bigdata/hadoop && cd /opt/bigdata/hadoop$ wget https://dlcdn.apache.org/hadoop/common/stable/hadoop-3.3.1-src.tar.gz# 解压$ tar -zvxf hadoop-3.3.1-src.tar.gz为什么需要重新编译Hadoop源码?
匹配不同操作系统本地库环境,Hadoop某些操作比如压缩,IO需要调用系统本地库(.so|.dll)
重构源码
源码包目录下有个 BUILDING.txt,因为我这里的操作系统是Centos8,所以选择Centos8的操作步骤,小伙伴们找到自己对应系统的操作步骤执行即可。
$ grep -n -A40 'Building on CentOS 8' BUILDING.txtBuilding on CentOS 8----------------------------------------------------------------------------------* Install development tools such as GCC, autotools, OpenJDK and Maven. $ sudo dnf group install --with-optional 'Development Tools' $ sudo dnf install java-1.8.0-openjdk-devel maven* Install Protocol Buffers v3.7.1. $ git clone https://github.com/protocolbuffers/protobuf $ cd protobuf $ git checkout v3.7.1 $ autoreconf -i $ ./configure --prefix=/usr/local $ make $ sudo make install $ cd ..* Install libraries provided by CentOS 8. $ sudo dnf install libtirpc-devel zlib-devel lz4-devel bzip2-devel openssl-devel cyrus-sasl-devel libpmem-devel* Install optional dependencies (snappy-devel). $ sudo dnf --enablerepo=PowerTools snappy-devel* Install optional dependencies (libzstd-devel). $ sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm $ sudo dnf --enablerepo=epel install libzstd-devel* Install optional dependencies (isa-l). $ sudo dnf --enablerepo=PowerTools install nasm $ git clone https://github.com/intel/isa-l $ cd isa-l/ $ ./autogen.sh $ ./configure $ make $ sudo make install----------------------------------------------------------------------------------将进入Hadoop源码路径,执行maven命令进行Hadoop编译
$ cd /opt/bigdata/hadoop/hadoop-3.3.1-src# 编译$ mvn package -Pdist,native,docs -DskipTests -Dtar【问题】Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.0.0-M1:enforce
[INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 19:49 min [INFO] Finished at: 2021-12-14T09:36:29+08:00 [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.0.0-M1:enforce (enforce-banned-dependencies) on project hadoop-client-check-test-invariants: Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed. -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException [ERROR] [ERROR] After correcting the problems, you can resume the build with the command [ERROR] mvn -rf :hadoop-client-check-test-invariants
【解决】
具体原因目前还不明确,先使用上面两个方案中的方案一跳过,有兴趣的小伙伴,可以打开DEBUG模式(-X)查看具体报错
$ mvn package -Pdist,native,docs,src -DskipTests -Dtar -Denforcer.skip=true所以编译命令
# 当然还有其它选项$ grep -n -A1 '$ mvn package' BUILDING.txt$ mvn package -Pdist -DskipTests -Dtar -Dmaven.javadoc.skip=true$ mvn package -Pdist,native,docs -DskipTests -Dtar$ mvn package -Psrc -DskipTests$ mvn package -Pdist,native,docs,src -DskipTests -Dtar$ mvn package -Pdist,native -DskipTests -Dmaven.javadoc.skip \ -Dopenssl.prefix=/usr/local/opt/openssl至此~Hadoop源码编译完成, 编译后的文件位于源码路径下 hadoop-dist/target/
将编译好的二进制包copy出来
$ cp hadoop-dist/target/hadoop-3.3.1.tar.gz /opt/bigdata/hadoop/$ cd /opt/bigdata/hadoop/$ ll这里也把编译好的包放在百度云上,如果小伙伴不想自己编译,可以直接用我这里的:
链接:https://pan.baidu.com/s/1hmdHY20zSLGyKw1OAVCg7Q 提取码:8888
1、修改主机名
# 192.168.0.113机器上执行$ hostnamectl set-hostname hadoop-node1# 192.168.0.114机器上执行$ hostnamectl set-hostname hadoop-node2# 192.168.0.115机器上执行$ hostnamectl set-hostname hadoop-node32、修改主机名和IP的映射关系(所有节点都执行)
$ echo "192.168.0.113 hadoop-node1" >> /etc/hosts$ echo "192.168.0.114 hadoop-node2" >> /etc/hosts$ echo "192.168.0.115 hadoop-node3" >> /etc/hosts3、关闭防火墙和selinux(所有节点都执行)
$ systemctl stop firewalld$ systemctl disable firewalld# 临时关闭(不用重启机器):$ setenforce 0 ##设置SELinux 成为permissive模式# 永久关闭修改/etc/selinux/config 文件将SELINUX=enforcing改为SELINUX=disabled4、时间同步(所有节点都执行)
$ dnf install chrony -y$ systemctl start chronyd$ systemctl enable chronyd/etc/chrony.conf配置文件内容
# Use public servers from the pool.ntp.org project.# Please consider joining the pool (http://www.pool.ntp.org/join.html).#pool 2.centos.pool.ntp.org iburst (这一行注释掉,增加以下两行)server ntp.aliyun.com iburstserver cn.ntp.org.cn iburst重新加载配置并测试
$ systemctl restart chronyd.service$ chronyc sources -v5、配置ssh免密(在hadoop-node1上执行)
# 1、在hadoop-node1上执行如下命令生成公私密钥:$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_dsa# 2、然后将master公钥id_dsa复制到hadoop-node1|hadoop-node2|hadoop-node3进行公钥认证。$ ssh-copy-id -i /root/.ssh/id_dsa.pub hadoop-node1$ ssh-copy-id -i /root/.ssh/id_dsa.pub hadoop-node2$ ssh-copy-id -i /root/.ssh/id_dsa.pub hadoop-node3$ ssh hadoop-node1$ exit$ ssh hadoop-node2$ exit$ ssh hadoop-node3$ exit6、安装统一工作目录(所有节点都执行)
# 软件安装路径$ mkdir -p /opt/bigdata/hadoop/server# 数据存储路径$ mkdir -p /opt/bigdata/hadoop/data# 安装包存放路径$ mkdir -p /opt/bigdata/hadoop/software7、安装JDK(所有节点都执行) 官网下载:https://www.oracle.com/java/technologies/downloads/ 百度下载
链接:https://pan.baidu.com/s/1-rgW-Z-syv24vU15bmMg1w 提取码:8888
$ cd /opt/bigdata/hadoop/software$ tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/bigdata/hadoop/server/# 在文件加入环境变量/etc/profileexport JAVA_HOME=/opt/bigdata/hadoop/server/jdk1.8.0_212export PATH=$JAVA_HOME/bin:$PATHexport CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar# source加载$ source /etc/profile# 查看jdk版本$ java -version$ cd /opt/bigdata/hadoop/software$ tar -zxvf hadoop-3.3.1.tar.gz -C /opt/bigdata/hadoop/server/$ cd /opt/bigdata/hadoop/server/$ cd hadoop-3.3.1/$ ls -lh|目录| 说明 | |--|--| | bin | hadoop最基本的管理脚本和使用脚本的目录,这些脚本是sbin目录下管理脚本的基础实现,用户可以直接使用这些脚本管理和使用hadoop | | etc | hadoop配置文件所在的目录 | | include | 对外提供的编程库头文件(具体动态库和静态库在lib目录中),这些文件均是用c++定义,通常用于c++程序访问HDFS或者编写MapReduce程序。 | | lib | 该目录包含了hadoop对外提供的编程动态库和静态库,与include目录中的头文件结合使用。 | | libexec | 各个服务队用的shell配置文件所在的免疫力,可用于配置日志输出,启动参数(比如JVM参数)等基本信息。 | | sbin | hadoop管理脚本所在的目录,主要包含HDFS和YARN中各类服务的启动、关闭脚本。 | | share | hadoop 各个模块编译后的jar包所在的目录。官方示例也在其中 |
配置文件目录:/opt/bigdata/hadoop/server/hadoop-3.3.1/etc/hadoop 官方文档:https://hadoop.apache.org/docs/r3.3.1/
# 在hadoop-env.sh文件末尾追加export JAVA_HOME=/opt/bigdata/hadoop/server/jdk1.8.0_212export HDFS_NAMENODE_USER=rootexport HDFS_DATANODE_USER=rootexport HDFS_SECONDARYNAMENODE_USER=rootexport YARN_RESOURCEMANAGER_USER=rootexport YARN_NODEMANAGER_USER=root在\\中间添加如下内容
fs.defaultFS hdfs://hadoop-node1:8082 hadoop.tmp.dir /opt/bigdata/hadoop/data/hadoop-3.3.1 hadoop.http.staticuser.user root hadoop.proxyuser.hosts * hadoop.proxyuser.root.groups * fs.trash.interval 1440 在\\中间添加如下内容
dfs.namenode.secondary.http-address hadoop-node2:9868 dfs.webhdfs.enabled true 在\\中间添加如下内容
mapreduce.framework.name yarn mapreduce.jobhistory.address hadoop-node1:10020 mapreduce.jobhistory.webapp.address hadoop-node1:19888 yarn.app.mapreduce.am.env HADOOP_MAPRED_HOME=${HADOOP_HOME} mapreduce.map.env HADOOP_MAPRED_HOME=${HADOOP_HOME} mapreduce.reduce.env HADOOP_MAPRED_HOME=${HADOOP_HOME} 在\\中间添加如下内容
yarn.resourcemanager.hostname hadoop-node1 yarn.nodemanager.aux-services mapreduce_shuffle yarn.nodemanager.pmem-check-enabled false yarn.nodemanager.vmem-check-enabled false yarn.log-aggregation-enable true yarn.log.server.url http://hadoop-node1:19888/jobhistory/logs yarn.log-aggregation.retain-seconds 604880 hadoop-node1hadoop-node2hadoop-node3$ cd /opt/bigdata/hadoop/server/$ scp -r hadoop-3.3.1 hadoop-node2:/opt/bigdata/hadoop/server/$ scp -r hadoop-3.3.1 hadoop-node3:/opt/bigdata/hadoop/s