目录
一、MapReduce运⾏流程简述
⼀个完整的
MapReduce
程序在分布式运⾏时有三类实例进程:
1)
MRAppMaster:负责整个程序的过程调度及状态协调
2)
MapTask:负责
map
阶段的整个数据处理流程
3)
ReduceTask:负责
reduce
阶段的整个数据处理流程
当⼀个作业提交后(mr程序启动),⼤概流程如下:
1)
⼀个
mr
程序启动的时候,会先启动⼀个进程
Application Master,
它的主类是 MRAppMaster
2)
appmaster
启动之后会根据本次
job
的描述信息,计算出
inputSplit
的数据,也就是MapTask
的数量
3)
appmaster
然后向
resourcemanager
来申请对应数量的
container
来执⾏MapTask进程。
4)
MapTask
进程启动之后,根据对应的
inputSplit
来进⾏数据处理,处理流程如下
-
利⽤客户指定的
inputformat
来获取
recordReader
读取数据,形成
kv
键值对。
-
将
kv
传递给客户定义的
mapper
类的
map
⽅法,做逻辑运算,并将
map
⽅法的输出kv收集到缓存。
-
将缓存中的
kv
数据按照
k
分区排序后不断的溢出到磁盘⽂件
5)
appmaster
监控
maptask
进程完成之后,会根据⽤户指定的参数来启动相应的reduceTask进程,并告知
reduceTask
需要处理的数据范围
6)
reducetask
启动之后,根据
appmaster
告知的待处理的未知数据,从若⼲的已经存到磁盘的数据中拿到数据,并在本地进⾏⼀个归并排序,然后,再按照相同的key
的kv为⼀组,调⽤客户⾃定义的
reduce
⽅法,并收集输出结果
kv
,然后按照⽤户指定的outputFormat将结果存储到外部设备。
参考下图:

二、运⾏流程之MapTask
1. maptask
调⽤
FileInputFormat
的
getRecordReader
读取分⽚数据
2.
每⾏数据读取⼀次,返回⼀个
(K,V)
对,
K
是
offset,V
是⼀⾏数据
3.
将
k-v
对交给
MapTask
处理
4.
每对
k-v
调⽤⼀次
map(K,V
,
context)
⽅法,然后
context.write(k,v)
5.
写出的数据交给收集器
OutputCollector.collector()
处理
6.
将数据写⼊环形缓冲区,并记录写⼊的起始偏移量,终⽌偏移量,环形缓冲区默认 ⼤⼩100M
7.
默认写到
80%
的时候要溢写到磁盘,溢写磁盘的过程中数据继续写⼊剩余
20%
8.
溢写磁盘之前要先进⾏分区然后分区内进⾏排序
9.
默认的分区规则是
hashpatitioner
,即
key
的
hash%reduceNum
10.
默认的排序规则是
key
的字典顺序,使⽤的是快速排序
11.
溢写会形成多个⽂件,在
maptask
读取完⼀个分⽚数据后,先将环形缓冲区数据 刷写到磁盘
12.
将数据多个溢写⽂件进⾏合并,分区内排序(外部排序
===
》归并排序)
MapTask的并⾏度决定map阶段的任务处理并发度,进⽽影响到整个job的处理速度.那么,MapTask并⾏实例是否越多越好呢?其并⾏度⼜是如何决定呢?
1)
如果硬件配置为
2*12core + 64G
,恰当的
map
并⾏度是⼤约每个节点
20-100
个map,最好每个
map
的执⾏时间⾄少⼀分钟。
2)
如果
job
的每个
map
或者
reduce task
的运⾏时间都只有
30-40
秒钟,那么就减少该job
的
map
或者
reduce
数,每⼀个
task(map|reduce)
的
setup
和加⼊到调度器中进⾏调度,这个中间的过程可能都要花费⼏秒钟,所以如果每个task
都⾮常快就跑完了, 就会在task
的开始和结束的时候浪费太多的时间。
3)
配置
task
的
JVM
重⽤可以改善该问题:
(mapred.job.reuse.jvm.num.tasks
,默认是
1
,表示⼀个
JVM
上最多可以顺序执⾏的task
数⽬(属于同⼀个
Job
)是
1
。也就是说⼀个
task
启⼀个
JVM
)
4)
如果
input
的⽂件⾮常的⼤,⽐如
1TB
,可以考虑将
hdfs
上的每个
block size
设⼤,⽐如设成256MB
或者
512MB
三、运⾏流程之ReduceTask
1.
数据按照分区规则发送到
reducetask
2. reducetask
将来⾃多个
maptask
的数据进⾏合并,排序(外部排序
===
》归并排序)
3.
按照
key
相同分组()
4.
⼀组数据调⽤⼀次
reduce(k,iterable<v>values,context)
5.
处理后的数据交由
reducetask
6. reducetask
调⽤
FileOutputFormat
组件
7. FileOutputFormat
组件中的
write
⽅法将数据写出
Reduce Task的并⾏度同样影响整个
job
的执⾏并发度和执⾏效率,但与
Map Task
的并发数由切⽚数决定不同,Reduc Task
数量的决定是可以直接⼿动设置:默认值是 1,⼿动设置为
4
设置⽅法 :job.setNumReduceTasks(4);
如果数据分布不均匀,就有可能在
reduce
阶段产⽣数据倾斜
注意:
Reduce Task
数量并不是任意设置,还要考虑业务逻辑需求,有些情况下,需 要计算全局汇总结果,就只能有1
个
Reduce Task ,尽量不要运⾏太多的Reduce Task
。对⼤多数
job
来说,最好
reduce
的个数最多和集 群中的reduce
持平,或者⽐集群的
reduce slots
⼩。这个对于⼩集群⽽⾔,尤其重 要。