Mapreduce 详解之如何写mr

136 阅读2分钟

1.Mapreduce初识

Mapreduce是一个分布式计算框架,支持少量代码实现海量数据并发处理程序。多个服务器同时进行计算,极大的提高了计算效率。

2.Mapreduce流程

2.1 InputFormat

  • map数据是经过序列化输出的 Writeable类:如intwriteable
    • Write方法序列化了切分输出
    • readFields方法反序列化了输入数据。(reduce读取时进行反序列化,从字节数组转换为int类型

2.1.1 getsplit

切分数据块

2.1.2 RecordReader

2.2 Mpper

  • 将inputformat的kv转换为需要的kv对
  • 继承 org.apache.hadoop.mapreduce. Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>并重写map方法
  • 以WordCount为例:
    • 输入: 偏移量长度为key, 文本值为value
    • 处理:对value按单词进行进一步切割,并对每个单词计数(1),装入<k,v>

2.3 shuffle

  • 将相同key通过hash 映射在同一partition并排序(默认字典序),进行后续的reduce处理

2.4 Reducer

  • 继承 org.apache.hadoop.mapreduce.Reducer<KEYIN, VALUEIN, KEYOUT, VALUEOUT>并重写reduce方法
  • 输入为map输出经过shuffle(sort&(combine))处理后的结果,对每个key/valuelist 调用
  • Reduce的输入中 每种key一定在一个溢写文件中。或者说分区数据中 reduce方法

2.5 outputformat

  • 继承RecordWriter并重写write和close方法来自定义输出格式

粗谈细节

  1. map/reduce数量确定?
    Map数量默认block大小Reduce数量0.95或1.75倍的节点*mapred.tasktracker.tasks.maximum参数值:
  • 0.95:那么所有的reduce任务能够在 map任务的输出传输结束后同时开始运行
  • 1.75: 高速的节点完成第一批reduce任务后 开始计算第二批reduce任务,有利于负载均衡 mapper任务的数量主要根据切分文件大小决定,InputSplit的多少决定了MapTask的数目,因为每个InputSplit会交由一个MapTask处理。

reduce在bulkload中任务数量并非人为设定,region数量获得,为了直接将文件移动到目标hbase中 ,因此需要输出的hfile和region完全一致:

// 根据hbase regionserver(startkay size)数量来确定reducetasks的数量
   List<ImmutableBytesWritable> startKeys = getRegionStartKeys(regionLocators, writeMultipleTables);
   LOG.info("Configuring " + startKeys.size() + " reduce partitions to match current region count for all tables");
   job.setNumReduceTasks(startKeys.size());
  1. Map处理完的数据直接进入环形缓冲区存储键值对,以及对应的partition,此时键值对已经序列化(为了写入磁盘)
    • 进入内存缓冲区的过程中进行分区,此时kv以及partition属性值一起序列化为字节数组 写入缓冲区,到达阈值后溢写到本地临时文件