文章目录
一、Hadoop起源
提到Hadoop,就必须先提到Google的三大论文,因为Hadoop的理论基础就是来自谷歌的三大论文。(PS:一般某个主流框架技术都是先由某一位大佬发表学术论文,然后再有一些计算器大佬根据理论基础进行实现)
GFS(Google File System):发表于2003年,这是一个可扩展的分布式文件系统,用于大型的、分布式的、对大量数据进行访问的应用。它运行于廉价的普通硬件上,提供容错功能。从根本上说:文件被分割成很多块,使用冗余的方式储存于商用机器集群上。
MapReduce:发表于2004年,该论文描述了大数据的分布式计算方式,主要思想是将任务分解然后在多台处理能力较弱的计算节点中同时处理,然后将结果合并从而完成大数据处理。Hadoop的分布式计算主要就是基于该理论基础。
BigTable:发布于2006年,启发了无数的NoSQL数据库,比如:Cassandra、HBase等等。BigTable 是建立在 GFS 和 MapReduce 之上的。每个Table都是一个多维的稀疏图为了管理巨大的Table,把Table根据行分割,这些分割后的数据统称为:Tablets。
关于三大论文非常的经典,我这里只是做一个简单的介绍,有兴趣的小伙可以去查看相关资料,阅读原论文,我这里也有对应的PDF文档。
二、Hadoop简介
2.1、Hadoop的核心思想
分治思想:简单来说就是把一个大的问题分成若干个小的问题进行并行处理,从而提高效率。
比如:一个1T的硬盘,传输速度为100M/S,那么需要2.5小时才能读取完所有的数据,而写入数据就更慢了。那么我们可以使用100个硬盘,每个硬盘存储百分之1的数据,并行读取,不到2分钟就可以读取完所有的数据,然后进行合并就可以得到完成的数据了。这就是分治思想的一个例子。分布式计算也是如此,多端并行计算,然后再在一台或者多台上进行聚合。
2.2、Hadoop 四大模块
Hadoop Common:为其他hadoop模块提供基础设施
Hadoop Distribute File System (HDFS) :一个高可靠、高吞吐量的、易于扩展的分布式文件系统
Hadoop YARN:资源管理框架,负责任务调度与资源管理
Hadoop MapReduce:分布式计算框架
三、HDFS介绍
Hadoop自带一个成为HDFS的分布式文件系统,全名为Hadoop Distribute File System,也可以成为DFS。
3.1、数据块
每个磁盘都有默认的数据块大小,这是磁盘进行数据读/写的最小单位。HDFS也有块(Block)的概念,Hadoop1.x的HDFS默认块大小为64MB;Hadoop2.x的默认块大小为128MB。HDFS上的文件也被分为块大小的多个分块(Chunk),作为独立的存储单元。
注意:HDFS中一个小于块大小的文件,不会占据整个块的空间,例如一个1M的文件不会占用128M的空间。
3.2、namenode和datanode
HDFS集群中有两类节点namenode(管理节点)和datanode(工作节点),这两类节点以管理节点-工作节点模式运行着。
namenode节点:
--整个集群的中心节点
--存储的是元数据信息(block信息、文件的权限、副本数)
--接收datanode的心跳和块报告
datanode节点:
--block为单位存储数据
--每3s报告心跳状态
--每1h报告自己节点上面块的状态
--在线加入或者下线node
3.3、块缓存
通常datanode从磁盘中读取块,但对于访问频繁的文件,其对应的块可能被显示地缓存在datanode的内存中,以堆外缓存(off-heap block cache)的形式存在。
3.4、联邦HDFS
namenode在内存中保存文件系统中每个文件和每个数据块的引用关系,这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。
因此在2.x发行版本中引入了联邦HDFS允许系统通过添加namenode实现扩展,每个namenode管理系统文件命名空间的一部分。例如一个namenode可能管理/user目录下的所有文件,另一个namenode管理/share目录下的所有文件。每个namenode维护一个命名空间卷,由命名空间的元数据和数据块池组成,数据块池包含该命名空间下文件的所有数据块。并且命名空间卷之间是相互独立的。
3.5、HDFS的高可用性
Hadoop针对namenode的单点问题增加了对HDFS高可用(HA)的支持。在这一实现中,配置了一对活动-备用(active-standby)namenode。当active的namenode失效后,standby的namenode就会接管它的任务,并开始服务于来自客户端的请求,不会有任何明显的中断。
四、YARN介绍
Apache YARN(Yet Another Resource Negotiator的缩写)是Hadoop的集群资源管理系统。YARN是Hadoop2.x版本开始被引入的,最初是为了改善MapReduce的实现,但它具有足够的通用性,同样可以支持其他的分布式计算模式。
4.1、YARN的运行机制
YARN通过两类长期运行的守护进程提供自己的核心服务,分别为resource manager和node manager。
resource manager进程:
--处理客户端请求(资源访问入口)
--启动/监控ApplicationMaster
--监控NodeManager
--资源分配与调度
node manager进程:
--管理自己节点的资源,汇报给ResourceManager
--处理来自于ResourceManager的命令
--处理来自ApplicationMaster的命令
下图是来自官方文档的截取,介绍了YARN的运行机制:
PS:图中的Container可以理解为资源的抽象,如内存、CPU、磁盘、网络等。。。
上面这个图总结分为下面几个步骤(序号并非完全对应):
1)客户端向ResourceManager发起请求(资源)
2)ResourceManager会为job任务分配一个ApplicationMaster(job任务的管理者,分配在某个NodeManager节点上)
3)ApplicationMaster再向ResourceManager申请资源,ResourceManager响应ApplicationMaster的资源申请
4)ApplicationMaster与NodeManager通信,进行任务执行与响应
5)对应的NodeManager执行完任务后会向ApplicationMaster报告
6)ApplicationMaster向ResourceManager报告任务完成
五、MapReduce介绍
MapReduce是一种可用于数据处理的编程模型。Hadoop可以运行各种语言版本的MapReduce程序,如Java、Ruby、Python等。最重要的是,MapReduce程序本质上是运行运行的,因此可以将大规模的数据分析任务分发给任何一个拥有足够多机器的数据中心。MapReduce的优势在于处理大规模数据集。
5.1、MapReduce编程模型
MapReduce任务过程分为两个处理阶段:map阶段和reduce阶段。每个阶段都以键-值对作为输入和输出,其类型由程序员来选择,然后程序员还需要写两个函数:map函数和reduce函数。
map阶段:map阶段的输入是原始数据,我们可以选择文本格式作为输入格式,将数据集的每一行作为文本输入。键是某一行起始位置相对于文件起始位置的偏移量。
reduce阶段:map函数的输出即为reduce函数的输入,对数据集做进一步的处理。
5.2、Hadoop的MapReduce介绍
Hadoop的MapReduce就是基于上面的MapReduce实现模型实现的。
需要注意的是,在Hadoop的MapReduce实现中,在map阶段输出和reduce阶段输入之间还存在一个shuffle阶段,对数据进行分区、分组和排序,也是最重要的一个阶段。
下图是Hadoop的MapReduce的Shuffle详细过程,截图自官方文档:
5.3、MapReduce经典实现案例
上面大家对MapReduce有了一个初步的认识和了解,但是大家可能还是不清楚Hadoop中的MapReduce到底是怎么处理数据的,下面列举一个经典案例WordCount来帮助大家理解,也就是统计每个单词出现的次数,一般Hadoop处理离线日志分析的时候就是这样的一个原理。
例如新建一个文本命名为wordcount.txt,文本内容如下:
hello tom
hello jerry
hello tom
map阶段输入:
// 第一个key为0是因为起始位置为0开始,具体见5.1的编程模型
<0,"hello tom">
// 这里的key是10,原因是包括一个空格(hello后面)和一个回车(tom后面)
<10,"hello jerry">
<22,"hello tom">
map函数伪代码:
map(){
// 0
int key = k1;
// "hello tom"
String value = v1;
String[] words = value.split(" ");
for(String w : words){
context.write(w,1);
}
}
map阶段输出:
<hello,1> <tom,1> <jerry,{1}> <hello,1> <hello,1>
经过shuffle阶段之后,也就是reduce阶段的输入的格式如下:
<hello,{1,1,1}>
<jerry,{1}>
<tom,{1,1}>
reduce函数伪代码:
reduce(){
// k2 = hello
String key = k2;
int counter = 0;
// v2 = {1,1,1}
for(int i : v2){
counter += i;
}
context.write(key,counter);
}
reduce阶段输出:
<hello,3>
<jerry,1>
<tom,2>
相信通过上面的例子大家也能大致了解Hadoop中的MapReduce计算到底是如何实现的了。
结束语:上面主要介绍了Hadoop的起源,核心组成部分,最后通过一个小案例帮助大家理解MapReduce的过程。