hadoop学习之hadoop技术内幕—— mapreduce 过程详解

来源:互联网 发布:sql删除重复的数据 编辑:程序博客网 时间:2024/05/19 03:44

荐书:《hadoop技术内幕》

对于MapReduce的工作原理,看视频,看直播,都云里雾里的。没办法,找书吧,找的时候还想着,就算只有那本hadoop权威指南,我也只能硬着头皮去啃了。然后找到这本,终于解惑了,读的停不下来。真是一本好书,不晦涩,连涉及到的基础知识点都解释的非常详细,java基础一般的读起来也没有困难。

PS:书是基于hadoop1.x写的。

在MapReduce计算框架中,一个应用程序被划分成Map和Reduce两个计算阶段,它们分别由一个或者多个Map Task和Reduce Task组成。其中,每个Map Task处理输入集合中的一个数据分片(InputSplit),Reduce Task则从每个Map Task上远程拷贝相应的数据片段,经过分组聚集和规约后,将结果写到hdfs上作为最终结果。

一、自己简单总结一下MapTask过程

1、首先InputFormat处理每个分片的数据,默认是用TextInputFormat,按行将数据处理成key=行偏移量、value=当前行的一串字符,然后传给map()方法。用户可以自定义InputFormat去解析每行数据,自定义复杂的key的类型和value的类型

2、开启线程,调用用户自定义的map()方法,将传入的一个个key/value,经过数据进行过滤、清洗等,再由context.write()输出一个个新的key/value

3、调用用户自定义的partitioner方法,对数据进行分区。在context.write()方法内部,会首先调用用户自定义的partitioner方法,获取partitionno,形成一个三元组<key,value,partitionno>,然后将数据写入内存中的二级索引结构的环形缓冲区。

4、数据溢写。当环形缓冲区中数据达到设定的阈值后,会溢写到本地磁盘上去。

1)排序:溢写时首先要对数据进行排序,先快排,当需要快排的数据小于13个时,变成直接插入排序。排序的元祖是:partitionno,key,这样经过排序后,数据以分区为单位聚集在一起,且同一分区内的所有相同key的数据也聚集在一起。

2)调用用户自定义的combiner,对每个分区中的数据进行一次聚集操作。

3)将数据写入Map任务工作目录下的临时文件output/spillN.out中,其中N是当前是第几次溢写。并将分区数据的元信息(partitionno,spillN,offset)写到内存索引数据结构spillRecord中。

5、合并临时文件。

当Map将所有数据都处理完后,会将所有临时文件合并成一个大文件out/file.out,同时生成索引文件out/file.out.index。合并时,以分区为单位,采用小顶堆,首先对文件大小每进行排序,默认合并最小的100个文件,合并后的文件作为一个新文件,再次参与新的排序,重复这个过程,直到最后生成一个大文件。

如果用户指定Reduce Task数量为0,则直接将文件存储到HDFS上。

6、疑问:每台机器同时能运行多个应用的Map任务否,能?

每个Map任务都会启动一个JVM进程吗,是?

同一个应用的Map任务,有可能能在一台机器上开启多个吗,不能?

对于某台机器上一个正在运行的Map任务内部,InputFormat是多线程并发的吗,不是?

对于某台机器上一个正在运行的Map任务,map是多线程并发的吗,是?

需要将应用程序代码拷贝到每台机器上去吗?

二、Reduce Task过程

1、shuffle:getMapEventsThread线程周期性从Task Tracker上获取已完成的Map Task任务列表,将其保存到映射表中,

为防止后续拷贝时出现网络热点(多个Reduce同时拷贝同一个Map任务的输出数据,同一台主机),会将映射表的顺序打乱,即“混洗”。

2、merge:远程拷贝数据:多线程并发,HTTPGet拷贝多个MapTask的输出,直接存放到内存,如果分片比较大,就会存到磁盘上。

为防止文件过多,会不断对这些数据和文件进行合并,

3、sort reduce:这两个是并发进行的,

Map输出的数据本身已经sort过一次了,只需进行归并排序即可。通过排序聚集了相同的key,直接传给reduce()方法。


三、应用程序优化

根据MapReduce过程分析,可以通过以下方式优化。

1、如果可以,设置Combiner,这样就可以减少Map的输出,减少shuffle阶段拷贝数据的耗时,因为在大数据环境下,网络耗时是最瓶颈。

2、使用压缩,

3、合理合适map Task和ReduceTask 的数量

如果一个job的输入超过1TB,那么久增加blocksize到256或者512,这样能减少task的数量。动态调整已有数据的块大小的命令:

hadoop distcp -Ddfs.block.size=$[256*1024*1024]/path/to/inputdata  /path/to/inputdata-with/largeblocks,命令执行完成后,将原来的/path/to/inputdata目录删掉,然后修改新的目录为原来的目录名自

只要Task的耗时超过30-40s,那么就增加maptask的数量,增加到整个cluster上mapslot总数的几倍。如果你的cluster中有100个mapslot,那就避免运行一个有101个map task的job。

不要调度太多的reduce task,推荐reduce task的数量应当等于或者略小于reduceslot的总数量。并且略小于或者等于map task的数量


4、选择合理的Writeable类型,尽管Text对象看起来很方便,但它在由数值转换到文本或者由UTF-8字符转换到文本时都是低效的,且消耗大量CPU时间。

5、重用writeable,不要使用context.write(new Text(key),new IntWritable(value)),这样会生成成千上万个对象,造成频繁GC?匿名变量也会如此?

而是应该在mapper类内,map方法外定义两个变量:Text key=new Text();IntWriteable value = new IntWriteable(1);






阅读全文
0 0
原创粉丝点击