大数据计算的核心思路是移动计算比移动数据更划算。既然计算方法跟传统计算方法不一样,那么用传统的编程模型进行大数据计算就会遇到很多困难,因此 Hadoop 大数据计算使用了一种叫作 MapReduce 的分布式计算框架。核心是将一个复杂的数据处理任务分解为两个主要阶段:​​Map(映射)​​ 和 ​​Reduce(归约)​​。

  • Map 阶段(分)​​:负责将输入数据分割成独立的片段,由多个 ​​Map Task​​ 并行处理。每个 Map 任务处理一条输入记录,输出一系列的中间键值对(key-value pairs)。这个过程类似于将一份长长的清单拆分成多个小项,分给不同的人同时清点
  • ​​Reduce 阶段(合)​​:负责对 Map 阶段输出的中间结果进行汇总。框架会将所有 Map 输出中具有相同 key 的值分组在一起,然后每个 ​​Reduce Task​​ 处理一组 key,最终生成汇总结果。这好比将不同人清点的同类物品数量相加,得到总数。

一个 MapReduce 作业的执行包含一系列精细的步骤,下图概括了其核心流程与关键组件交互:

​输入与分片 (Input & Splitting)​​

  • InputFormat类负责验证输入数据的格式,并将输入数据(如 HDFS 上的大文件)逻辑切分成多个 ​​分片 (Splits)​​。默认情况下,分片大小与 HDFS 的块大小一致。
  • RecordReader则负责读取分片,并将其转化为一条条具体的键值对记录,作为 Map 函数的输入

​​Map 阶段​​

  • 每个数据分片会由一个 Map Task 处理。Map 任务的数量通常由分片数决定。
  • 开发者编写的 Mapper函数处理输入的键值对,并输出新的中间键值对。

​​Shuffle 与 Sort(洗牌与排序)​​

  • ​​Shuffle​​,将 Map 任务输出的中间结果按照 key 进行分区(Partitioner),并通过网络传输到对应的 Reduce 任务节点。
  • ​​Sort​​,在数据送达 Reduce 任务之前,框架会对每个分区内的数据按照 key 进行排序。这确保了 Reduce 函数接收到的是已经分组和排序的数据。

​​Reduce 阶段​​

  • 所有具有相同 key 的中间值会被分组,然后传递给同一个 Reduce 任务。
  • 开发者编写的 Reducer函数接收一个 key 和对应的 value 迭代器,进行汇总计算(如求和、求平均等),并输出最终的键值对。

​​输出 (Output)​​

  • OutputFormat类负责将最终的键值对写入指定的存储系统,如 HDFS。

​​Combiner​​:是一个可在 Map 端执行的本地 Reduce 操作。它会对 Map 的本地输出进行初步合并,减少网络传输的数据量。例如,在词频统计中,可以先在 Map 端对同一个单词的出现次数进行局部求和。

​​Partitioner​​:决定了 Map 产生的中间键值对如何被分发给不同的 Reduce 任务。默认的分区策略是对 key 的哈希值取模,确保相同 key 去往同一个 Reduce 任务。

这是MP经典任务词频统计的执行过程

小文件问题

小文件问题是HDFS和MapReduce架构中的经典瓶颈,指的是大量远小于 HDFS 块大小的文件对系统造成的负面影响。它会导致NN和DN负担加重、任务执行低效、HDFS存储浪费等很多问题。

在MapReduce作业执行过程中,有些设置不合理会导致出现小文件问题。

Reduce任务数量过多

  • MapReduce作业的输出文件数量通常由Reduce任务的数量决定。如果设置了过多的Reduce任务(例如,在Hive中通过mapred.reduce.tasks参数设置得过高),每个Reduce任务都会生成一个独立的输出文件。当总数据量不大但Reduce任务很多时,每个任务处理的数据量就很少,从而产生大量小文件

数据严重倾斜

  • 在存在数据倾斜的情况下,大部分数据可能被集中到一个或少数几个Reduce任务中处理,而其他大量的Reduce任务只分配到极少量的数据。这些处理数据量很少的Reduce任务输出的文件就是小文件。

源数据本身小文件

小文件的应对策略,核心思想是 ​​“合并”​​:

  • ​​输出时合并​​:对MapReduce作业而言,最有效的办法是​​在数据写入HDFS前就进行合并​​。在Hive中可以通过设置hive.merge.mapfileshive.merge.mapredfiles等参数来自动合并Reduce阶段的输出文件
  • ​​使用特定文件格式​​:将小文件转换为​​SequenceFile​​或​​AVRO​​等容器型文件格式,可以将多个小文件打包成一个大的序列文件,减少文件数量,同时保持原始文件的边界信息
  • ​​使用归档工具​​:对于已经产生的、访问不频繁的历史小文件,可以使用​​Hadoop Archive (HAR)​​ 工具将其打包存档,减轻NN的压力
  • ​​调整计算引擎​​:使用像​​CombineFileInputFormat​​这样的输入格式,它可以在Map任务启动前,将多个小文件逻辑上合并到一个InputSplit中,从而减少初始化的Map任务数量

更多推荐