目录
Hadoop是一个开源的、可靠地、可扩展的分布式并行计算框架, ,可以为海量数据提供存储和计算。Hadoop目前主要包括Hadoop1.x和hadoop2.x,两种版本差距较大,目前常用的是Hadoop2.x版本,所以本节主要基于Hadoop2.x进行讲解。Hadoop 2.x即第二代Hadoop系统,其框架最核心的设计是HDFS、MapReduce和YARN。其中,HDFS是分布式文件存储系统,为海量数据提供存储;MapReduce为并行计算框架,用于分布式计算;YARN用于进行资源管理。由于HDFS在第5节已详细讲述,故本节对HDFS部分略去。
1 Hadoop版本对比
Hadoop 1.0和Hadoop 2.0的结构对比:
![](https://i-blog.csdnimg.cn/blog_migrate/47cb9cab2424fcd5953a6d93f2fae9d1.png)
Hadoop 2.0的主要改进有:
1、通过YARN实现资源的调度与管理,从而使Hadoop 2.0可以运行更多种类的计算框架,如Spark等。
2、实现了NameNode的HA方案,即同时有2个NameNode(一个Active另一个Standby),如果ActiveNameNode挂掉的话,另一个NameNode会转入Active状态提供服务,保证了整个集群的高可用。(详见第5节)
3、实现了HDFS federation,由于元数据放在NameNode的内存当中,内存限制了整个集群的规模,通过HDFS federation使多个NameNode组成一个联邦共同管理DataNode,这样就可以扩大集群规模。(详见第5节)
4、Hadoop RPC序列化扩展性好,通过将数据类型模块从RPC中独立出来,成为一个独立的可插拔模块。
2 MapReduce
MapReduce是由Google公司研究提出的一种面向大规模数据处理的并行计算模型和方法,是Hadoop面向大数据并行处理的计算模型、框架和平台。任务的分解(Map)与结果的汇总(Reduce)是其主要思想。Map就是将一个任务分解成多个任务,Reduce就是将分解后多任务分别处理,并将结果汇总为最终结果。
MapReduce执行流包括input、map、shuffle、reduce和output共5个过程,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/940bacc45259b50d9e3f91ee51ece2f7.png)
Mapreduce的map端将任务分解为多个任务,并将map产生的数据通过分区、排序等过程分配给不同的reduce端,reduce端将任务进行处理。其中将map产生的数据通过分区、排序等过程分配给不同的reduce称为shuffle。Mapreduce的数据处理流程如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/b08fda8994d357aacce3a385601e71e6.png)
Map阶段:
1、每个输入分片会让一个map任务来处理,默认情况下,以HDFS的一个块的大小(默认为64M,可设置)为一个分片。map输出的结果会暂时放在一个环形内存缓冲区中(该缓冲区的大小默认为100M,由io.sort.mb属性控制)。当该缓冲区快要溢出时(默认为缓冲区大小的80%,由io.sort.spill.percent属性控制),会在本地文件系统中创建一个溢出文件,将该缓冲区中的数据写入这个文件。
2、在写入磁盘之前,线程首先根据reduce任务的数目将数据划分为相同数目的分区,也就是一个reduce任务对应一个分区的数据。这样做是为了避免有些reduce任务分配到大量数据,而有些reduce任务却分到很少数据,甚至没有分到数据的尴尬局面。然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行combine操作,这样做可以有效减少磁盘IO和网络IO。
3、当map任务输出最后一个记录时,可能会有很多的溢出文件,这时需要将这些文件合并。合并的过程中会不断地进行排序和combine操作,这样做是为了尽量减少每次写入磁盘的数据量和尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,这里可以将数据压缩,只要将mapred.compress.map.out设置为true就可以了。
4、将分区中的数据拷贝给相对应的reduce任务。那么分区中的数据如何知道它对应的reduce是哪个呢? ApplicationMaster保存了整个作业的宏观信息,只要reduce任务向ApplicationMaster获取对应的map输出位置就可以了。
Reduce阶段:
1、Reduce会接收到不同map任务传来的数据,并且每个map传来的数据都是有序的。如果reduce接受的数据量相当小,则直接存储在内存中,如果数据量超过了该缓冲区大小的一定比例,则对数据合并后溢写到磁盘中。
2、随着溢写文件的增多,后台线程会将它们合并成一个更大的有序文件,这样做是为了给后面的合并节省时间。其实不管在map端还是reduce端,MapReduce都是反复地执行排序、合并操作,所以说排序是hadoop的灵魂。
3、在合并的过程中会产生许多的中间文件(写入磁盘了),但MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数。
3 YARN
3.1 YARN简介
Yarn是Hadoop2.0中的资源管理系统,由于hadoopl.0不能满足多系统集成的背景而产生的。它的基本设计思想是将MRvl(MapReduce l)中的JobTracker拆分成多个独立的实体,从而改善了“经典的”MapReduce面临的扩展瓶颈问题。在“经典的”MapReduce中,Jobtracker负责作业调度和任务进度监视,追踪任务、重启失败或过慢的任务和进行任务登记,例如维护计数器总数。YARN则是将这二种角色划分成二个独立的守护进程:管理集群上资源使用的资源管理器和管理集群上运行任务生命周期的应用管理器。基本思路是:应用服务器与资源管理器协商集群的计算资源,容器。每个容器都有特定的内存上限,在这些容器上运行特定应用程序的进程。容器由集群节点上运行的节点管理器监视,以确保应用程序使用的资源不会超过分配给它的资源。
相关术语解释如下:
● ResourceManager(简写RM),资源管理器,负责管理所有应用程序计算资源的分配
● ApplicationMaster(简写AM),应用管理器,AM与每个具体任务对应,负责管理任务的整个生命周期内的调度和协调
● Containers,客器,YARN为将来的资源隔离而提出的框架,每一个任务对应一个Container且只能在该container中运行
● NodeManager(简写NM),节点管理器,代替了MapReduce中的tasktracker。管理每个节点上的资源和任务,主要有两个作用:定期向RM汇报该节点的资源使用情况和各个container的运行状态;接收并处理AM的任务启动、停止等请求
3.2 YARN框架及组件
下面我们看一下整个Yarn的架构图:
![](https://i-blog.csdnimg.cn/blog_migrate/3372883cf5f9b7350c12181d6d94e228.png)
YARN系统结构类型是将节点分为ResourceManager和NodeManager,ResourceManager和每个节点上的NodeManager形成了数据计算框架。其中,ResourceManager负责将集群的资源分配给各个应用使用,而资源分配和调度的基本单位是container(资源容器),container封装了机器资源,如cpu、磁盘、网络、内存等。NodeManager负责运行作业。每个应用程序都有一个相应ApplicationMaster,运行在NodeManager上,负责为应用程序与ResourceManager协商资源,并且对作业执行和监控。在每个NodeManager上有一个container(资源容器)包括了使用的各种资源比如cpu、磁盘、网络、内存,NodeManager负责监控各个节点上的container,并且向ResourceManager报告。
ResourceManager又有两大组件:Scheduler和ApplicationManager。Scheduler只负责对集群中的资源进行分配,协调各个节点应用程序的资源,并且有多种资源分配策略例如CapacityScheduler和FairScheduler。Application Manager则负责接受提交的作业,为作业执行失败重启提供服务。
Scheduler(资源调度)负责为根据资源容量的限制为各个正在运行的应用程序序列分配资源。这个Scheduler是纯粹的资源调度,他并不对应用程序进行监控和状态跟踪。此外,他也不能重启因为应用失败或者硬件错误而运行失败的任务。Scheduler执行资源调度是基于当前这个应用程序的资源需求。这个资源容器组件包括内存、cpu、磁盘、网络等等,在第一个版本中,仅仅支持内存。
ApplicationManager负责接受提交的作业,通过协商第一容器(container)执行特殊的应用程序ApplicationMaster并且为ApplicationMaster container执行失败后重新启动提供服务。
NodeManager是每台机器上的一个框架代理,负责对container的资源(cpu,内存,磁盘,网络)使用情况进行监控,并且报告给ResourceManager/Scheduler每个应用程序的ApplicationMaster负责与Scheduler协商获取的适当的container资源,并且跟踪程序的状态,监控执行过程。
3.3 YARN工作原理
我们以MapReduce在yarn中的运行流程为例,了解yarn的工作原理。MapReduce在yarn的工作流程如图7-5所示:
![](https://i-blog.csdnimg.cn/blog_migrate/634f59e79f56a51c8fb2eb08c1ed8b9b.png)
我们这里简述yarn的工作流程如下:
步骤1:用户向YARN中提交应用程序,其中包括用户程序、ApplicationMaster程序、ApplicationMaster启动命令等。
步骤2:ResourceManager为应用程序分配第一个Container,并与对应的NodeManager通信,要求它在这个Container中启动应用程序的ApplicationMaster。
步骤3:ApplicationMaster首先向ResourceManager注册,这样用户可以直接通过ResourceManager查看应用程序的运行状态,然后ApplicationMaster为各个任务申请资源,并监控它们的运行状态,直到运行结束,即重复步骤4-7。
步骤4:ApplicationMaster采用轮询的方式通过RPC协议向ResourceManager申请和领取资源。
步骤5:一旦ApplicationMaster成功申请到资源,便开始与对应的NodeManager通信,要求它启动任务。
步骤6:NodeManager为任务设置好运行环境(包括环境变量、JAR包、二进制程序等)后,将任务启动命令写到一个脚本中,并通过运行该脚本启动任务。
步骤7:各个任务通过某个RPC协议向ApplicationMaster汇报自己的状态和进度,使ApplicationMaster能够随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务。在应用程序运行过程中,用户可随时通过RPC向ApplicationMaster查询应用程序的当前运行状态。
步骤8:应用程序运行完成后,ApplicationMaster通过RPC协议向ResourceManager注销并关闭自己。
4 Hadoop部署
Hadoop HA集群搭建依赖于zookeeper,本节不再叙述zookeeper安装。
1 创建用户
在三台机器上分别创建相同的用户。具体命令如下:
(1)useradd -m hadoop -s /bin/bash //添加用户
(2)passwd hadoop //设置用户名密码
(3)visudo //设置用户权限,进入后添加代码:
hadoop ALL=(ALL) ALL
至此,用户创建完毕。
2 配置java环境
① 复制jdk-8u101-linux-x64.tar.gz到/home/Hadoop
② 解压jdk-8u101-linux-x64.tar.gz
tar xvf jdk-8u101-linux-x64.tar.gz
③ root权限打开/etc/profile文件,设置java包环境变量,具体在profile后面添加以下:
export JAVA_HOME=/home/hadoop/jdk1.8.0_101
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/lib:$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
④ 设置生效,在root用户和hadoop用户分别执行下面命令
source /etc/profile
⑤ 进入hadoop用户,设置环境变量
su hadoop
vim ~/.bashrc
添加下述内容:
export JAVA_HOME=/home/hadoop/jdk1.8.0_101
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/lib:$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
保存退出执行:source ~/.bashrc
⑥ 检查是否有效
java –version
如果出现下述字样则表示java环境配置正常。
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode
3 配置hadoop环境
(1)复制hadoop-2.7.3.tar.gz 到/home/hadoop目录
(2)解压hadoop-2.7.3.tar.gz
tar xvf hadoop-2.7.3.tar.gz
mv hadoop-2.7.3 hadoop
(3)root权限打开/etc/profile文件,设置java包环境变量,具体在profile后面添加以下:
export HADOOP_HOME=/home/hadoop/hadoop
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
(4) 设置生效,在root用户和hadoop用户分别执行下面命令
source /etc/profile
(5)进入hadoop用户,设置环境变量
su hadoop
vim ~/.bashrc
添加下述内容:
export HADOOP_HOME=/home/hadoop/hadoop
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin
保存退出执行:source ~/.bashrc
(6)检查hadoop是否配置好
hadoop version
如出现下述字样,则表示正常:
Hadoop 2.7.3
Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r baa91f7c6bc9cb92be5982de4719c1c8af91ccff
Compiled by root on 2016-08-18T01:41Z
Compiled with protoc 2.5.0
From source with checksum 2e4ce5f957ea4db193bce3734ff29ff4
This command was run using /home/hadoop/hadoop/share/hadoop/common/hadoop-common-2.7.3.jar
4 配置hosts映射关系
vim /etc/hosts
追加:
10.66.85.216 Master
10.66.85.217 Slave1
10.66.85.218 Slave2
修改三台机器分别改为:Master,Slave1,Slave2
5 配置免密钥登陆
为了防止出现登陆的错误,配置两两机器免密钥登陆,具体操作如下:
三台机器均进行如下操作:
登陆hadoop用户
cd ~/.ssh
rm ./id_rsa*
ssh-keygen -t rsa
cat id_rsa.pub >> authorized_keys
chmod 600 ./authorized_keys
将id_rsa.pub复制到其他两台机器的/home/hadoop目录下,在hadoop用户下执行
cd ~/.ssh
cat /home/hadoop/id_rsa.pub >> authorized_keys
三台机器均进行此操作,保证两两之间免密钥登陆
三台机器分别验证免密钥是否有效:
ssh Master
ssh Slave1
ssh Slave2
如果均不需要输入密码则表示免密钥配置成功
6 配置hadoop配置文件
① 配置slaves文件
vim /home/hadoop/hadoop/etc/hadoop/slaves
增加下述内容
localhost
Slave1
Slave2
② 配置core-site.xml文件
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://Master:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/home/hadoop/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<!-- 指定zookeeper地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value> Master:2181, Slave1:2181, Slave2:2181</value>
</property>
</configuration>
③ 配置hdfs-site.xml
<configuration>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>Master:50090</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/hadoop/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/hadoop/hadoop/tmp/dfs/data</value>
</property>
<property>
<name>dfs.datanode.max.xcievers</name>
<value>4096</value>
</property>
</configuration>
④ 配置mapred-site.xml文件
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>Master:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>Master:19888</value>
</property>
</configuration>
⑤ 配置yarn-site.xml
<configuration>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>Master</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!-- 指定zookeeper地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value> Master:2181, Slave1:2181, Slave2:2181</value>
</property>
</configuration>
7 压缩分发到其他的机器上
8 Master节点执行
hdfs namenode –format //第一次执行
前提条件是关闭防火墙
9 执行启动命令
start-dfs.sh
start-yarn.sh
mr-jobhistory-daemon.sh start historyserver
10 检查主从节点是否启动成功
jps
Master:有下述进程
DataNode
NameNode
ResourceManager
NodeManager
SecondaryNameNode
Slave:有下述进程
NodeManager
DataNode
则表示hadoop集群启动成功
5 MapReduce实例
5.1 WordCount单词统计
WordCount是非常好的入门示例,相当于helloword,下面就开发一WordCount的MapReduce程序。
1 在maven工程中,pom.xml文件添加以下依赖:
![](https://i-blog.csdnimg.cn/blog_migrate/b38914eed3a772c12f414c387cf8046b.png)
2 mapper程序如下:
![](https://i-blog.csdnimg.cn/blog_migrate/dfbbdd7a2c56e459119e76ce20d69d76.png)
这里定义了一个mapper类,其中有一个map方法。MapReduce框架每读到一行数据,就会调用一次这个map方法。map的处理流程就是接收一个key value对儿,然后进行业务逻辑处理,最后输出一个key value对儿。
Mapper<LongWritable, Text, Text, IntWritable>,其中的4个类型分别是:输入key类型、输入value类型、输出key类型、输出value类型。
MapReduce框架读到一行数据侯以key value形式传进来,key默认情况下是mr框架所读到一行文本的起始偏移量(Long类型),value默认情况下是mr框架所读到的一行的数据内容(String类型)。输出也是key value形式的,是用户自定义逻辑处理完成后定义的key,用户自己决定用什么作为key,value是用户自定义逻辑处理完成后的value,内容和类型也是用户自己决定。此例中,输出key就是word(字符串类型),输出value就是单词数量(整型)。这里的数据类型和我们常用的不一样,因为MapReduce程序的输出数据需要在不同机器间传输,所以必须是可序列化的,例如Long类型,Hadoop中定义了自己的可序列化类型LongWritable,String对应的是Text,int对应的是IntWritable。
3 reduce程序:
![](https://i-blog.csdnimg.cn/blog_migrate/68b6ad80f5f62905be8c707d2c1747d5.png)
这里定义了一个Reducer类和一个reduce方法。当传给reduce方法时,就变为:Reducer<Text, IntWritable, Text, IntWritable>。4个类型分别指:输入key的类型、输入value的类型、输出key的类型、输出value的类型。
需要注意,reduce方法接收的是:一个字符串类型的key、一个可迭代的数据集。因为reduce任务读取到map任务处理结果是这样的:
(good,1)(good,1)(good,1)(good,1)
当传给reduce方法时,就变为:
key:good
value:(1,1,1,1)
所以,reduce方法接收到的是同一个key的一组value。
4主程序
![](https://i-blog.csdnimg.cn/blog_migrate/06e105d9b680f31314d07ccda6bdfc31.png)
这个main方法就是用来组装一个job并提交执行
5 编译打包
在pom.xml所在目录下执行打包命令:
mvn package
6 运行
先把target中的jar上传到Hadoop服务器,然后在Hadoop服务器的HDFS中准备测试文件(把Hadoop所在目录下的txt文件都上传到HDFS)
cd $HADOOP_HOME
hdfs dfs -mkdir -p /wordcount/input
hdfs dfs -put *.txt /wordcount/input
执行wordcount jar
hadoop jar mapreduce-wordcount-0.0.1-SNAPSHOT.jar WordCountMapReduce /wordcount/input /wordcount/output
执行完成后验证
hdfs dfs -cat /wordcount/output/*
可以看到单词数量统计结果。
5.2 自定义分区
统计手机用户流量日志,日志内容实例:
![](https://i-blog.csdnimg.cn/blog_migrate/1233e427c521b3622dfa4379346df507.png)
①把同一个用户的上行流量、下行流量进行累加,并计算出综合
例如上面的13897230503有两条记录,就要对这两条记录进行累加,计算总和,得到:13897230503,500,1600,2100
②按省份统计,不同省份的手机号放到不同的文件里。
例如137表示属于河北,138属于河南,那么在结果输出时,他们分别在不同的文件中。
1 在maven工程中,pom.xml文件添加以下依赖:
![](https://i-blog.csdnimg.cn/blog_migrate/a345275a1284b019678633afdb95996b.png)
2 自定义bean
![](https://i-blog.csdnimg.cn/blog_migrate/e0f58abca4e44b4ace575a2a5d6a1841.png)
3 自定义分区器
![](https://i-blog.csdnimg.cn/blog_migrate/ec43b02761323a26bf48ab91a66cc6d7.png)
这段代码是本示例的重点,其中定义了一个hashmap,假设其是一个数据库,定义了手机号和分区的关系。getPartition取得手机号的前缀,到数据库中获取区号,如果没在数据库中,就指定其为“其它分区”(用4代表)。
4 MapReduce程序
![](https://i-blog.csdnimg.cn/blog_migrate/ebdc140387707b00d8023c856ae11c76.png)
main程序中指定了使用自定义的分区器job.setPartitionerClass(ProvincePartitioner.class)。
5 编译打包
在pom.xml所在目录下执行打包命令:mvn package。
6 运行
先把target中的jar上传到Hadoop服务器,然后执行下面的命令运行:
hadoop jar mapreduce-custompartion-0.0.1-SNAPSHOT.jar FlowCount/flowcount/input /flowcount/output-part
执行完验证:
hdfs dfs -ls /flowcount/output-part
6 Hadoop生态圈
Hadoop生态圈如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/cd2066cc21726eb32d55c266b8a6892f.png)
7 Hadoop小结
Hadoop是大数据环境常用技术,其有成熟的生态圈,Hadoop主要优点有:
1、支持超大文件:一般来说,HDFS存储的文件可以支持TB和PB级别的数据。
2、检测和快速应对硬件故障:在集群环境中,硬件故障是常见性问题。因为有上千台服务器连在一起,故障率高,因此故障检测和自动恢复hdfs文件系统的一个设计目标。
3、流式数据访问:HDFS的数据处理规模比较大,应用一次需要大量的数据,同时这些应用一般都是批量处理,而不是用户交互式处理,应用程序能以流的形式访问数据库。
4、简化的一致性模型:对于外部使用用户,不需要了解hadoop底层细节,比如文件的切块,文件的存储,节点的管理。
5、高容错性:数据自动保存多个副本,副本丢失后自动恢复。可构建在廉价机上,实现线性(横向)扩展,当集群增加新节点之后,namenode也可以感知,将数据分发和备份到相应的节点上。
6、商用硬件:Hadoop并不需要运行在昂贵且高可靠的硬件上,它是设计运行在商用硬件的集群上的,因此至少对于庞大的集群来说,节点故障的几率还是非常高的。HDFS遇到上述故障时,被设计成能够继续运行且不让用户察觉到明显的中断。
主要缺点为:
Hadoop适合做简单的数据查询工作,不能很好的与用户进行交互。后期的开发和维护花费大。对数据的分析性不是很好,性能比较慢。对有大量需求的业务逻辑需要自己手动编写代码。对数据大量流处理和汇总比较好,针对性分析性能较差。