第四次作业

1.用图与自己的话,简要描述Hadoop起源与发展阶段。

Hadoop是道格·卡丁(Doug Cutting)创建的,Hadoop起源于开源网络搜索引擎Apache Nutch,后者本身也是Lucene项目的一部分。Nutch项目面世后,面对数据量巨大的网页显示出了架构的灵活性不够。当时正好借鉴了谷歌分布式文件系统,做出了自己的开源系统NDFS分布式文件系统。第二年谷歌又发表了论文介绍了MapReduce系统,Nutch开发人员也开发出了MapReduce系统。随后NDFS和MapReduce命名为Hadoop,成为了Apache顶级项目。

Hadoop是一个对海量数据存储和海量数据分析计算的分布式系统。

Hadoop 1.x
海量数据存储 ----> HDFS
海量数据分析计算 ----> MapReduce
Hadoop 2.x 增加
资源调度系统 ----> Yarn

从hadoop最初的原型来看,hadoop已经远远超过了本身的批处理。从广义上来说,hadoop现在可以是指更广泛的一个hadoop生态了,而不仅仅是HDFS,MapReduce和Yarn。例如Hive,Hbase,Flume,Sqoop等等项目都属于这个生态。

 

2.用图与自己的话,简要描述名称节点、第二名称节点、数据节点的主要功能及相互关系。

 

 

 

 

名称节点:负责管理分布式文件系统的命名空间,里面包含了两个核心的数据结构,即FsImage和EditLog。FsImage用户文件树以及所有的文件和文件夹的元数据。EfitLog记录的是文件的增删改查。

首次安装format格式化就是在本地生成FsImage。首次安装format格式化就是在本地生成FsImage。

HDFS的更新都会被写入到FsImage中而不是EditLog,因为对于分布式而言,FsImage非常庞大,直接对FsImage速度非常慢。HDFS的更新都会被写入到FsImage中而不是EditLog,因为对于分布式而言,FsImage非常庞大,直接对FsImage速度非常慢。

数据节点(DataNode):定期向名称节点发送自己的存储块的列表。数据节点(DataNode):定期向名称节点发送自己的存储块的列表。

因为HDFS文件会逐渐地变大,不断变大的EditLog文件通常不会对系统文件产生影响,但是当EditLog很大时,使得在HDFS重启时,将EditLog合并到FsImage中的过程十分缓慢,系统长期处于“安全模式”,用户的使用收到影响。

HDFS的第二名称节点(secondary NameNode)的作用:完成EditLog合并到FsImage的过程,缩短合并的重启时间,其次作为“检查点”保存元数据的信息。

 

 

4.梳理HBase的结构与运行流程,以用图与自己的话进行简要描述,图中包括以下内容:

  • Master主服务器的功能
  • Region服务器的功能
  • Zookeeper协同的功能
  • Client客户端的请求流程
  • 四者之间的相系关系
  • 与HDFS的关联

Master 功能:

1、为 RegionServer 分配 Region

2、负责 RegionServer 的负载均衡

3、发现失效的 RegionServer 并重新分配其上的 Region

4、HDFS 上的垃圾文件(HBase)回收

5、处理 Schema 更新请求(表的创建,删除,修改,列簇的增加等等)

RegionServer功能:

1、RegionServer 维护 Master 分配给它的 Region,处理对这些 Region 的 IO 请求

2、RegionServer 负责 Split 在运行过程中变得过大的 Region,负责 Compact 操作

ZooKeeper功能:

1、ZooKeeper 为 HBase 提供 Failover 机制,选举 Master,避免单点 Master 单点故障问题

2、存储所有 Region 的寻址入口:-ROOT-表在哪台服务器上。-ROOT-这张表的位置信息

3、实时监控 RegionServer 的状态,将 RegionServer 的上线和下线信息实时通知给 Master

4、存储 HBase 的 Schema,包括有哪些 Table,每个 Table 有哪些 Column Family

Client请求流程:

Client 访问用户数据前需要首先访问 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然 后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过 client 端会做 cache 缓存。

与HDFS关联:

HBase是一个内存数据库,而hdfs是一个存储空间;是物品和房子的关系。HBase 参考了 Google 公司的 Bigtable 建模,而 Bigtable 是基于 GFS 来完成数据的分布式存储的,因此,HBase 与 HDFS 有非常紧密的关系,它使用 HDFS 作为底层存储系统。

HDFS是GFS的一种实现,他的完整名字是分布式文件系统,类似于FAT32,NTFS,是一种文件格式,是底层的。Hive与Hbase的数据一般都存储在HDFS上。Hadoop HDFS为他们提供了高可靠性的底层存储支持。

 

 5.理解并描述Hbase表与Region与HDFS的关系。

在Hbase中存在一张特殊的meta表,其中存放着HBase的元数据信息,包括,有哪些表,表有哪些HRegion,每个HRegion分布在哪个HRegionServer中。meta表很特殊,永远有且仅有一个HRegion存储meta表,这个HRegion存放在某一个HRegionServer中,并且会将这个持有meta表的Region的HRegionServer的地址存放在Zookeeper中meta-region-server下。

所以当在进行HBase表的读写操作时,需要先根据表名 和 行键确 定位到HRegion,这个过程就是HRegion的寻址过程。

HRgion的寻址过程首先由客户端开始,访问zookeeper 得到其中meta-region-server的值,根据该值找到唯一持有meta表的HRegion所在的HRegionServer,得到meta表,从中读取真正要查询的表和行键 对应的HRgion的地址,再根据该地址,找到真正的操作的HRegionServer和HRegion,完成HRgion的定位,继续读写操作.

 

6.理解并描述Hbase的三级寻址。

现在假设我们要从Table2里面查询一条RowKey是RK10000的数据。那么我们应该遵循以下步骤:

  1. 从.META.表里面查询哪个Region包含这条数据。

  2. 获取管理这个Region的RegionServer地址。

  3. 连接这个RegionServer, 查到这条数据。

 

7.假设.META.表的每行(一个映射条目)在内存中大约占用1KB,并且每个Region限制为2GB,通过HBase的三级寻址方式,理论上Hbase的数据表最大有多大?

   一个-ROOT-表最多只能有一个Region,也就是最多只能有2GB,按照每行(一个映射条目)占用1KB内存计算,2GB空间可以容纳2GB/1KB=2的21次方行,也就是说,一个-ROOT-表可以寻址2的21次方个.META.表的Region。同理,每个.META.表的 Region可以寻址的用户数据表的Region个数是2GB/1KB=2的21次方。最终,三层结构可以保存的Region数目是(2GB/1KB) × (2GB/1KB) = 2的42次方个Region

 

8.MapReduce的架构,各部分的功能,以及和集群其他组件的关系。

 

 

(1)client客户端
每一个Job都会在用户端通过Client类将应用程序以及参数配置Configuration打包成Jar文件存储在HDFS,并把路径提交到JobTracker的master服务,然后由master创建每一个Task(即MapTask和ReduceTask),将它们分发到各个TaskTracker服务中去执行。

(2)JobTracker
JobTracker负责资源监控和作业调度。JobTracker监控所有的TaskTracker与job的健康状况,一旦发现失败,就将相应的任务转移到其它节点;同时JobTracker会跟踪任务的执行进度,资源使用量等信息,并将这些信息告诉任务调度器,而调度器会在资源出现空闲时,选择合适的任务使用这些资源。在Hadoop中,任务调度器是一个可插拔的模块,用于可以根据自己的需要设计相应的调度器。

(3)TaskTracker
TaskTracker会周期性地通过HeartBeat将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时执行JobTracker发送过来的命令 并执行相应的操作(如启动新任务,杀死任务等)。TaskTracker使用“slot”等量划分本节点上的资源量。“slot”代表计算资源(cpu,内存等) 。一个Task获取到一个slot之后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。slot分为MapSlot和ReduceSlot两种,分别提供MapTask和ReduceTask使用。TaskTracker通过slot数目(可配置参数)限定Task的并发度。

(4)Task
Task分为MapTask和Reduce Task两种,均由TaskTracker启动。HDFS以固定大小的block为基本单位存储数据,而对于MapReduce而言,其处理单位是split。split是一个逻辑概念,它只包含一些元数据信息,比如数据起始位置、数据长度、数据所在节点等。它的划分方法完全由用户自己决定。但需要注意的是,split的多少决定了MapTask的数目,因为每一个split只会交给一个MapTask处理。

9.MapReduce的工作过程,用自己词频统计的例子,将split, map, partition,sort,spill,fetch,merge reduce整个过程梳理并用图形表达出来。

1. 在map task执行时,它的输入数据来源于HDFS的block,当然在MapReduce概念中,map task只读取split。Split与block的对应关系可能是多对一,默认是一对一。在WordCount例子里,假设map的输入数据都是像“aaa”这样的字符串。

2. 在经过mapper的运行后,我们得知mapper的输出是这样一个key/value对: key是“aaa”, value是数值1。因为当前map端只做加1的操作,在reduce task里才去合并结果集。前面我们知道这个job有3个reduce task,到底当前的“aaa”应该交由哪个reduce去做呢,是需要现在决定的。

MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reduce task处理。默认对key hash后再以reduce task数量取模。默认的取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到job上。

在我们的例子中,“aaa”经过Partitioner后返回0,也就是这对值应当交由第一个reducer来处理。接下来,需要将数据写入内存缓冲区中,缓冲区的作用是批量收集map结果,减少磁盘IO的影响。我们的key/value对以及Partition的结果都会被写入缓冲区。当然写入之前,key与value值都会被序列化成字节数组。

整个内存缓冲区就是一个字节数组,它的字节索引及key/value存储结构我没有研究过。如果有朋友对它有研究,那么请大致描述下它的细节吧。

3. 这个内存缓冲区是有大小限制的,默认是100MB。当map task的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文可译为溢写,字面意思很直观。这个溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止map的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffer size * spillpercent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Map task的输出结果还可以往剩下的20MB内存中写,互不影响。

当溢写线程启动后,需要对这80MB空间内的key做排序(Sort)。排序是MapReduce模型默认的行为,这里的排序也是对序列化的字节做的排序。

在这里我们可以想想,因为map task的输出是需要发送到不同的reduce端去,而内存缓冲区没有对将发送到相同reduce端的数据做合并,那么这种合并应该是体现是磁盘文件中的。从官方图上也可以看到写到磁盘中的溢写文件是对不同的reduce端的数值做过合并。所以溢写过程一个很重要的细节在于,如果有很多个key/value对需要发送到某个reduce端去,那么需要将这些key/value值拼接到一块,减少与partition相关的索引记录。

在针对每个reduce端而合并数据时,有些数据可能像这样:“aaa”/1, “aaa”/1。对于WordCount例子,就是简单地统计单词出现的次数,如果在同一个map task的结果中有很多个像“aaa”一样出现多次的key,我们就应该把它们的值合并到一块,这个过程叫reduce也叫combine。但MapReduce的术语中,reduce只指reduce端执行从多个maptask取数据做计算的过程。除reduce外,非正式地合并数据只能算做combine了。其实大家知道的,MapReduce中将Combiner等同于Reducer。

如果client设置过Combiner,那么现在就是使用Combiner的时候了。将有相同key的key/value对的value加起来,减少溢写到磁盘的数据量。Combiner会优化MapReduce的中间结果,所以它在整个模型中会多次使用。那哪些场景才能使用Combiner呢?从这里分析,Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。所以从我的想法来看,Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。Combiner的使用一定得慎重,如果用好,它对job执行效率有帮助,反之会影响reduce的最终结果。

4. 每次溢写会在磁盘上生成一个溢写文件,如果map的输出结果真的很大,有多次这样的溢写发生,磁盘上相应的就会有多个溢写文件存在。当maptask真正完成时,内存缓冲区中的数据也全部溢写到磁盘中形成一个溢写文件。最终磁盘中会至少有一个这样的溢写文件存在(如果map的输出结果很少,当map执行完成时,只会产生一个溢写文件),因为最终的文件只有一个,所以需要将这些溢写文件归并到一起,这个过程就叫做Merge。Merge是怎样的?如前面的例子,“aaa”从某个map task读取过来时值是5,从另外一个map 读取时值是8,因为它们有相同的key,所以得merge成group。什么是group。对于“aaa”就是像这样的:{“aaa”, [5, 8, 2, …]},数组中的值就是从不同溢写文件中读取出来的,然后再把这些值加起来。请注意,因为merge是将多个溢写文件合并到一个文件,所以可能也有相同的key存在,在这个过程中如果client设置过Combiner,也会使用Combiner来合并相同的key。

至此,map端的所有工作都已结束,最终生成的这个文件也存放在TaskTracker够得着的某个本地目录内。每个reduce task不断地通过RPC从JobTracker那里获取maptask是否完成的信息,如果reduce task得到通知,获知某台TaskTracker上的map task执行完成,Shuffle的后半段过程开始启动。

简单地说,reduce task在执行之前的工作就是不断地拉取当前job里每个map task的最终结果,然后对从不同地方拉取过来的数据不断地做merge,也最终形成一个文件作为reduce task的输入文件

 

 

 

如map 端的细节图,Shuffle在reduce端的过程也能用图上标明的三点来概括。当前reduce copy数据的前提是它要从JobTracker获得有哪些map task已执行结束,这段过程不表,有兴趣的朋友可以关注下。Reducer真正运行之前,所有的时间都是在拉取数据,做merge,且不断重复地在做。如前面的方式一样,下面我也分段地描述reduce 端的Shuffle细节:

1. Copy过程,简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求map task所在的TaskTracker获取map task的输出文件。因为map task早已结束,这些文件就归TaskTracker管理在本地磁盘中。
2. Merge阶段。这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活,它基于JVM的heapsize设置,因为Shuffle阶段Reducer不运行,所以应该把绝大部分的内存都给Shuffle用。这里需要强调的是,merge有三种形式:1)内存到内存 2)内存到磁盘 3)磁盘到磁盘。默认情况下第一种形式不启用,让人比较困惑,是吧。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge方式生成最终的那个文件。
3. Reducer的输入文件。不断地merge后,最后会生成一个“最终文件”。为什么加引号?因为这个文件可能存在于磁盘上,也可能存在于内存中。对我们来说,当然希望它存放于内存中,直接作为Reducer的输入,但默认情况下,这个文件是存放于磁盘中的。至于怎样才能让这个文件出现在内存中,之后的性能优化篇我再说。当Reducer的输入文件已定,整个Shuffle才最终结束。然后就是Reducer执行,把结果放到HDFS上。

posted @ 2021-10-22 14:38  zhqsb  阅读(26)  评论(0编辑  收藏  举报