用 MapReduce 框架,程序员写一个封装有 map 和 reduce 函数的独立代码片段来处 理 HDFS 上的数据集。为取到数据位置,代码打包(jar 格式)分发到数据节点, Map 操作就在这些数据节点上执行,这避免了集群的数据传输导致消耗网络带宽。 对于 Reduce 聚合操作,Map 的结果被传输到多个 Reduce 节点上做 reduce 操作(称 之为 shuffling)。首先,Map 阶段是并行操作的,Hadoop 提供了一个弹性机制,当 一个机器节点或者一个处理过程失败时,计算会在其他机器节点上重启。
MapReduce 编程框架将数据集抽象为流式 key-value 键值对,然后处理这些键 值对并写回到 HDFS。这是一个有局限的范式,但它已被用来解决许多数据并行问题, 用链接在一起的 MapReduce 进行“读-处理-写”操作过程。对于一些简单的任务,上图显示的是比较适合的场景。但是对于一些如机器学习算法中的迭代计算算 法,用这种 MapReduce 范式就很痛苦,这也是选择使用 Spark 的原因。
Spark :内存中的 MapReduce 处理
我们来看另一个可选的分布式处理系统,构建在 Hadoop 基础之上的 Spark。在这一小节你会了解到,在 Spark 处理图数据时扮演重要角色的弹性分 布式数据集(RDD)导致 Hadoop 衰落的两类问题是 :
交互式查询 迭代算法
Hadoop 很适合在一个大的数据集上做单次查询,而在许多实际场景中,一旦有 了一个想要的答案,我们就想再问数据一个问题,这就是交互式查询。使用 Hadoop 的话,就意味着要等待重新从磁盘中加载数据,再次处理数据。我们不得不执行一 组相同的计算作为随后分析的前提,这不符合常理。
迭代算法已经被广泛应用于机器学习任务,如随机梯度下降算法,以及之后 会看到的 PageRank 这类图计算算法。迭代算法是在一个数据集上一遍又一遍地做 一组计算,直到满足一个标准(循环结束条件)才结束迭代。 在 Hadoop 中实现这种算法,一般需要一系列加载数据的 MapReduce 任务,这些 MapReduce 任务要在 每一个迭代过程中重复运行。对于非常大的数据集,每个迭代过程要花费 100 秒或1000 秒,整个迭代过程非常耗时。
下面你会看到 Spark 如何解决这些问题。如 Hadoop 一样,Spark 也是运行在 一个常见的硬件配置的机器集群上。Spark 中的一个核心抽象是弹性分布式数据集(RDD)。RDD 是由 Spark 应用创建的(在Spark Driver上),由集群管理,如下图。
Spark 提供一个弹性分布式数据集,可以认为它是一个分布式的常驻内存的数组。
组成 RDD 分布式数据集的数据分区会被加载到集群的机器上。
基于内存的数据处理
Spark 执行的大部分操作都是在随机访问内存中(RAM)进行。Spark 是基于内 存的,而 Hadoop Map/Reduce 是顺序处理数据,所以 Spark 比 Hadoop 更适合处理 随机访问的图数据。
Spark 的关键好处在于交互式查询和迭代处理过程中在内存中缓存 RDD。缓存 起来的 RDD 可以避免每次重新处理父 RDD 链,而只需要直接返回父 RDD 计算后 的缓存结果。
自然的,这意味着要用到 Spark 的基于内存的计算处理特性,要求集群中的机 器内存要足够大。要是可用内存不够,那么 Spark 就会优雅地溢出数据到磁盘,以 保证 Spark 能继续运行。
当然 Spark 集群也需要一个持久化存储数据的地方,而且还要是分布式存储系 统才行,可选的有 HDFS、Cassandra 和亚马逊的 S3。
本文选自《SparkGraphX实战》。