MapReduce框架
目标概览
可靠容错的方式并行处理大型集群的数据。
关注的点有:
- 输入
- 输出
- shuffle
- 调度
- 监控
RM负责调度任务,RM监控worker的运行状况。并向Client提供诊断信息。
输入输出
- key value结构
需要序列化
如果要key排序,需要支持比较
提交命令
hadoop jar w.jar wordcount /input /output
除了这些常规的点之外,可以支持一些参数
- libjars
增加map reduce的jar包
- files
这些文件将会出现在工作目录中
- archive
解压到当前工作目录,可以通过#重新建立软连接
- Dmapreduce.map|reduce.env
指定运行时环境变量
整体流程
- map
- combine
运行过程中如果指定了合并器,那么会在排序之后先进行本地聚合.这时之前都是本地的
- reduce
- 客户端
Main方法通过waitForCompletion提交作业并监控作业执行
用户接口
提供细粒度的实现方式,配置和调优
- Mapper
输入key-value映射到mkey-value对
- 中间键值对不一定需要和输入的键值对一样
- 中间键值对可以是0个或者多个
Map的个数由InputSplit决定,每一个InputSplit生成一个MapTask
context.write 收集结果
- 中间值被框架分组,用户可以指定分组的逻辑Job.setGroupingComparatorClass(Class),分组的作用是构造迭代器,一个分组一个迭代器处理。map和reduce端都会出现。
- 中间值可以排序,然后分区。分区的个数和reducer一致。用户可以通过Partitioner指定key->reducer的映射关系。
- 中间值输出的结构简单,kenlen key valuelen value这种方式,可以指定压缩
- Mapper个数
Mapper个数,这里指的是并行度,这个通常是由输入数据量决定的。大约是每个10-100个map tasks,特别轻量级的任务可以指定到300.
split是逻辑划分,block是物理划分,物理划分时可能导致数据跨行,这时候split就需要读取相邻两个block。
- Reducer
Combine的结果继续跨节点合并
用户可以指定reducer的个数
需要处理(key,iterator(valuess))的数据
shuffle
reducer的输入值是mapper的排序输出
http获取所有mapper的相关partition
soft
reduce拉取数据之后,要进行分组
一边shuffle获取数据,一边排序同时进行
Secondary Sort
combine的排序和reduce的排序规则不同,那么可以做到整体combine有序,然后reduce时局部再次排序。
- Reduce
对于每一个(key,list of values)调用reduce方法,结果未排序
- Reducer的个数
总容器*系数
如果没有reduce task,那么reduce 可以设置为0
- Partitioner
map端结果的分区,用来将key分配到不同的reduce task中。个数和reduce个数一致。默认是对key进行hash分区
作业配置
任务配置的主要作用是配置
- mapper
- combiner
- partitioner
- reducer
- InputFormat
FileInputFormat指定输入路径 FileInputFormat.setInputPath(job,String/Path)
FileInputFormat指定输入路径 FileInputFormat.addInputPath(job,String/Path)
- OutputFormat
FileInputFormat指定输出路径setOutputPath
作业配置也指定了一些其他的部分,比如说
- comparator
- DistributedCache
- 是否压缩,如何压缩
- 推测执行(Map和Reduce端)
- 最大重试次数
任务执行环境
MapTask和ReduceTask都是在指定的JVM中运行的线程,因此可以通过指定Java opts参数来进行控制。
- 控制内存
mapreduce.map.java.opts
mapreduce.reduce.java.opts
mapreduce.map.memory.mb
mapreduce.reduce.memory.mb
方式类似如下
<property>
<name>mapreduce.map.java.opts</name>
<value>
-Xmx512M -Djava.library.path=/home/mycompany/lib -verbose:gc -Xloggc:/tmp/@taskid@.gc
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
</value>
</property>
- 指定共享库路径
-Djava.library.path=/home/mycompany/lib
- map参数
map端输出的文件以及元数据进入两个缓冲区,任何一个缓冲区达到阈值,那么就进行磁盘刷写。这个时候如果是任何一个缓冲区满了,那么就终止map线程。结束之后,所有的文件合并成一个单个文件。
- mapreduce.task.io.sort.mb 用来排序的内存
- mapreduce.map.sort.spill.percent 磁盘的软限制,map内存占比多少时进行排序
增加sort内存可以缩小map spill数可以减小map合并时间,但是会增加线程中止时间。
- shuffle和reduce参数
reduce需要通过HTTP获取分配给它的输出,然后(解压)放入到内存中。
mapreduce.task.io.soft.factor 多少个文件可以同时合并,大文件分批合并
mapreduce.reduce.merge.inmem.thresholds 多少个map输出结果可以在内存中合并,一般设置或者非常大1000,或者非常小0。r
mapreduce.reduce.shuffle.merge.percent 在内存合并开始之前,有多少内存可以用来保存map输出
mapreduce.reduce.shuffle.input.buffer.percent 存放map结果内存比例占opts百分比
mapreduce.reduce.input.buffer.percent map结果可以保存在内存中的比例
reduce阶段,如果获取map阶段的输出大于25%的内存,那么直接写磁盘。
任务提交和监控
- 作业提交
检查输入输出
计算inputsplit
设置DistributedCache的账户信息
把Job的配置拷贝到MR系统目录
提交任务到RM,一种是即时返回Job.submit,一种是Job.waitForCompletion
- 跟踪作业进度
- 访问组件任务的报告和日志
- 获取MR集群状态
任务输入
- 检查输入是否有效
- InputSplit文件(逻辑上的),然后每一个指定给一个独立的Mapper
- 提供一个RecordReader(物理上的)从InputSplit中获取输入,输入给Mapper。
RecordReader实际获取InputSplit的视图对应的记录,给Mapper处理实现。所以他要处理边界问题。
要把输入进行逻辑上的划分,物理块大小是上限,下限通过参数指定mapreduce.input.fileinputformat.split.minsize。如果文件是特定格式的,那也不能进行划分了,一个Mapper处理一个不可以拆分的单位。
任务输出
OutputMapper用来处理task output。会在对应在如下情况。
- 初始化时候
需要创建临时目录等,setup任务结束后,job状态从PREP到RUNNING
- 任务完成时清理
- Task临时目录
- 检查Task是否需要提交
- 提交Task
任务结束后,可能需要提交output。
- 丢弃任务
可能Task自己清理,也可能加载一个同attempt_id的任务清理
为了避免推测执行等导致的同名输出,采取的方式是先分别放到临时目录,成功的使用真正的输出目录。
Record Writer
真正将数据写到文件系统
其他的功能
- 指定队列名称
- 计数器
Map/Reduce程序中可以指定计数器,最终MR框架会进行全局聚合。
- 分布式缓存
用来缓存只读文件到node节点上。可以用来提供Map/Reduce运行的库和jar包等。
分布式缓存可以设置权限