重新解读 MapReduce

2021-08-12 11:46:15 浏览数 (1)

在没有 MapReduce 编程模型的时候,做分布式系统的大数据量计算都是针对某一问题的开发特定的编程模型,写过代码的都知道这种的开发模式肯定推广不开来,后续的开发和维护都特别麻烦,但是当时也没人想着要弄一个通用的编程模型,直到后面谷歌发表了那篇著名的《MapReduce: Simplified Data Processing on Large Clusters》,大家突然发现原来在编程语言里面常用的编程模型可以用在分布式系统里,而且还能通用。

可以这么理解,原先大家认为各种各样的机器学习、数据挖掘、SQL处理等大数据计算需要不同的模型,MapReduce 一来,发现都可以用 MapReduce 实现了。

因此即使 MapReduce 在诞生之初也遭受了来自数据库领域的诘问和质疑,但是依然没有阻止 MapReduce 成为了分布式系统里大数据处理的标准。

在网上随便找了一个用 Java 语言实现的 MapReduce 的例子:

代码语言:javascript复制
public class WordCount {

  public static class TokenizerMapper
       extends Mapper<Object, Text, Text, IntWritable>{

    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(Object key, Text value, Context context
                    ) throws IOException, InterruptedException {
      StringTokenizer itr = new StringTokenizer(value.toString());
      while (itr.hasMoreTokens()) {
        word.set(itr.nextToken());
        context.write(word, one);
      }
    }
  }

  public static class IntSumReducer
       extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values,
                       Context context
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum  = val.get();
      }
      result.set(sum);
      context.write(key, result);
    }
  }
}

从这个简单的例子,可以发现 MapReduce 可以被简单的分解为:

  1. MapRead:读取输入的数据,并将输入的数据预处理为 Key/Value 形式,准备提供给 Map 阶段。
  2. Map:使用并行的方式或者是重复处理 MapRead 传过来的数据,不输出或者是输出 Key/Value 形式的数据。
  3. MapWrite:将 Map 阶段输出的 Key/Value 形式的数据聚合写入到(临时的)持久化存储上。可以理解为 group-by-key-and-checkpoint 操作
  4. ReduceRead:输入 shuffle 后的数据,并将它转为标准的 Key/Value 形式的数据,提供给 Reduce 流程。
  5. Reduce:根据同一Key,使用并行的方式或者是重复处理 ReduceRead 传过来的数据,不输出或者是输出 Value 数组形式的数据。
  6. ReduceWrite:将数据写入到数据存储系统上。

基本上大数据领域的所有计算模型都可以简单的抽象为这六个步骤的排列组合或者是重复。

简单而又强大。

直到 Dataflow 模型试图整合批处理和流处理,也就是所谓的流批一体。Dataflow 模型能很好地处理的流处理模型,但是对于 MapReduce 应该要如何处理呢?前文我们提到了 Stream and Table Relativity:

流(Stream)和表(Table)本质是数据这枚硬币的正反两面,表(Table)是静态的数据;流(Stream)是动态的数据。

既然是这样,那么传统的 MapReduce 就可以理解:

  1. MapRead:将 Table 变成 Stream
  2. Map:Stream 到 Stream 的转化
  3. MapWrite:将 Stream 转化成 Table
  4. ReduceRead:将 Table 转化成 Stream
  5. Reduce:Stream 到 Stream 的转化
  6. ReduceWrite:Stream 转化成 Table

从这个角度一看,就可以发现 MapReduce 可以再度简单的理解为 Table 和 Stream 之间的互相转换。虽然看起来是 Table 到 Table 的转化,但是实际上内部还是牵扯到了 Table 转出隐式的 Stream,对 Stream 进行计算,最后再将隐式的 Stream 变成 Table。

在 Dataflow 模型中,是从流开始到流或者表,Stream作为显示元素,table作为隐式元素,而 MapReduce是从table到table,table作为显示元素,隐藏了中间的数据流和隐式表。

从 Dataflow 模型中诞生的 Stream and Table Relativity 可以良好的再解释 MapReduce 的处理流程,从某种程度上证明了其理论的简洁和有效性。

Stream and Table Relativity 通过重新审视"数据"这一分布式系统处理中的核心概念,革新了对数据库、业务流程(业务逻辑本质上就是处理数据库表的变化的一系列逻辑)、分布式处理系统的理解,使得数据是否有界、使用批处理还是流处理的讨论变得不再那么重要。

参考链接:

  1. https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/mapreduce-osdi04.pdf

0 人点赞