
MapReduce 是分而治之的分布式计算模型分为两大阶段Map 阶段映射和Reduce 阶段归约中间由 Shuffle 洗牌过程衔接。整体流程输入分片 → Map任务 → Shuffle分区、排序、合并 → Reduce任务 → 输出结果1. Input 输入阶段把 HDFS 上的输入文件按块切分成InputSplit 输入分片。分片是逻辑划分不等于 HDFS 块。每个分片对应 1 个 Map Task。RecordReader 读取分片解析成key,value键值对传给 map 函数。key通常是偏移量value一行原始数据。2. Map 阶段并行map task用户自定义map()函数处理输入的k1,v1输出中间结果k2,v2。map 输出不会直接写 HDFS先写入内存环形缓冲区。缓冲区满后溢写到本地磁盘生成溢写 spill 文件溢写时执行分区 partition、局部排序 sort。多次溢写会产生多个 spill 文件map 任务结束时执行merge 合并生成 map 最终的本地输出文件。map 输出在本地磁盘不是 HDFS3. Shuffle 洗牌阶段【MR 核心最容易发生数据倾斜】作用把 map 输出数据按照 key 分发到对应 Reduce。分为Map 端 shuffle和Reduce 端 shuffle。Map 端Partition 分区根据 key 计算分区号决定这条数据交给哪个 Reduce。默认 HashPartitionerkey.hashCode() % reduceNum。分区 排序写出 spill 溢写文件最后合并成有序分区文件。Reduce 端Fetch 拉取各个 Reduce Task 通过 HTTP拉取所有 Map 节点上属于自己分区的数据。拉取的数据一部分放内存多了溢写到磁盘。Merge 归并排序把来自不同 map 的多个文件合并成全局有序的数据流。排序完成后相同 key 的所有 value 会聚合在一起交给 reduce 函数。⚠️ 数据倾斜根源hash 分区时某一个 key 数量巨大全部落到同一个 reduce导致单个 reduce 处理量暴涨。4. Reduce 阶段用户自定义reduce(k2, 迭代器v2)接收同一个 key 的全部 value 集合。执行业务逻辑处理。reduce 输出k3,v3写入 HDFS 输出目录。reduce 输出直接写 HDFS写的是最终结果。5. 精简文件切分片分片启 Mapmap 输出写缓冲区溢写磁盘分区排序shuffle 阶段 reduce 拉取各 map 的分区数据归并排序相同 key 聚合执行 reduce 函数结果输出 HDFS。关键要点Map 输出存本地磁盘Reduce 输出存HDFS。Shuffle 包含分区、排序、溢写、合并、拉取。排序是 MR 固有特性shuffle 过程一定会排序。分区规则决定数据去到哪个 reduce分区不合理就会数据倾斜。map task 数量由输入分片数决定reduce task 数量用户指定。简易流程图文字版HDFS输入文件 ↓ 切InputSplit MapTask 并行执行 ↓ map()输出 k2,v2 环形缓冲区 → spill溢写(分区排序) → merge合并本地文件 ↓ Shuffle ReduceTask 远程拉取对应分区数据 → merge归并排序 ↓ reduce(k,values) HDFS输出目录常见问题MapTask 数量由什么决定由输入分片 InputSplit 数量以及文件大小、块大小共同决定。ReduceTask 数量设置有什么影响0没有 reduce 阶段只跑 map。太少少数 reduce 压力大容易倾斜。太多产生大量小输出文件namenode 压力大。Shuffle 一定会排序吗MR 默认 shuffle 一定会对 key 排序如果不需要排序用 Spark 可以避免。数据倾斜发生在哪个阶段Shuffle 阶段分区后大量相同 key 落到同一个 reduce。