1. 引言

Apache Spark 是一个开源的集群计算框架。它为 Scala、Java、Python 和 R 提供了优雅的开发 API,让开发者能够在 HDFS、Cassandra、HBase、S3 等多种数据源上执行各类数据密集型任务。

历史上,Hadoop 的 MapReduce 在某些迭代式和交互式计算任务中效率低下,这直接催生了 Spark 的诞生。使用 Spark,在内存中运行逻辑可比 Hadoop 快两个数量级,在磁盘上也能快一个数量级——简单粗暴地说,就是性能碾压。

2. Spark 架构

Spark 应用在集群上以独立进程集合运行,如下图所示:

cluster overview

这些进程由主程序(称为驱动程序)中的 SparkContext 对象协调。SparkContext 连接到多种集群管理器(如 Spark 独立集群管理器、Mesos 或 YARN),由它们跨应用分配资源。

连接建立后,Spark 会在集群节点上获取执行器(Executor),这些进程负责运行计算并存储应用数据。接着,Spark 将应用代码(通过传递给 SparkContext 的 JAR 或 Python 文件定义)发送到执行器。最后,SparkContext 向执行器发送任务执行

3. 核心组件

下图清晰展示了 Spark 的不同组件:

Components of Spark

3.1. Spark Core

Spark Core 组件负责所有基础 I/O 功能、集群任务调度与监控、任务分发、与存储系统的网络通信、容错恢复以及高效的内存管理。

与 Hadoop 不同,Spark 通过一种称为 RDD(弹性分布式数据集)的特殊数据结构,避免将共享数据存储在 Amazon S3 或 HDFS 等中间存储中。

弹性分布式数据集(RDD)是不可变的、分区的记录集合,支持并行操作和容错的内存计算

RDD 支持两种操作:

  • 转换(Transformation):从现有 RDD 生成新 RDD 的函数。转换器以 RDD 为输入,输出一个或多个 RDD。转换具有惰性特性,即只有在调用动作(Action)时才会执行
  • 动作(Action):转换操作创建 RDD,但当我们需要处理实际数据集时,就会执行动作。因此,动作是返回非 RDD 值的 Spark RDD 操作。动作结果会存储到驱动程序或外部存储系统

动作是将数据从执行器发送回驱动程序的方式之一。执行器是负责执行任务的代理,而驱动程序则是协调工作节点和任务执行的 JVM 进程。常见的 Spark 动作包括 count()collect()

3.2. Spark SQL

Spark SQL 是用于结构化数据处理的 Spark 模块,主要用于执行 SQL 查询。DataFrame 是 Spark SQL 的核心抽象——在 Spark 中,DataFrame 是按命名列组织的分布式数据集合。

Spark SQL 支持从 Hive、Avro、Parquet、ORC、JSON 和 JDBC 等多种数据源获取数据。借助 Spark 引擎,它还能扩展到数千节点和多小时查询,并提供完整的查询中容错能力。

3.3. Spark Streaming

Spark Streaming 是核心 Spark API 的扩展,支持对实时数据流进行可扩展、高吞吐量、容错的流处理。数据可从 Kafka、Flume、Kinesis 或 TCP 套接字等多种源接入。

处理后的数据可推送到文件系统、数据库和实时仪表板。

3.4. Spark MLlib

MLlib 是 Spark 的机器学习(ML)库,旨在使实用机器学习可扩展且易用。它提供以下高层工具:

  • 机器学习算法:分类、回归、聚类和协同过滤等常见学习算法
  • 特征工程:特征提取、转换、降维和选择
  • 管道工具:构建、评估和调优 ML 管道的工具
  • 持久化:保存和加载算法、模型和管道
  • 实用工具:线性代数、统计、数据处理等

3.5. Spark GraphX

GraphX 是用于图和图并行计算的组件。高层来看,GraphX 通过引入新的图抽象扩展了 Spark RDD:一种附加了顶点和边属性的有向多重图。

为支持图计算,GraphX 暴露了一组基础操作符(如 subgraphjoinVerticesaggregateMessages)。此外,GraphX 还包含不断增长的图算法和构建器集合,以简化图分析任务。

4. Spark "Hello World" 示例

理解核心组件后,我们来实现一个简单的基于 Maven 的 Spark 项目——词频统计。我们将以本地模式运行 Spark,所有组件(主节点、执行节点或独立集群管理器)都在同一台机器上运行。

4.1. Maven 配置

pom.xml 中添加 Spark 相关依赖:

<dependencies>
    <dependency>
        <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.10</artifactId>
    <version>1.6.0</version>
    </dependency>
</dependencies>

⚠️ 注意:版本需与 Spark 安装版本匹配,否则可能踩坑。

4.2. 词频统计——Spark 任务

编写 Spark 任务处理文本文件,输出单词及其出现次数:

public static void main(String[] args) throws Exception {
    if (args.length < 1) {
        System.err.println("Usage: JavaWordCount <file>");
        System.exit(1);
    }
    SparkConf sparkConf = new SparkConf().setAppName("JavaWordCount");
    JavaSparkContext ctx = new JavaSparkContext(sparkConf);
    JavaRDD<String> lines = ctx.textFile(args[0], 1);

    JavaRDD<String> words 
      = lines.flatMap(s -> Arrays.asList(SPACE.split(s)).iterator());
    JavaPairRDD<String, Integer> ones 
      = words.mapToPair(word -> new Tuple2<>(word, 1));
    JavaPairRDD<String, Integer> counts 
      = ones.reduceByKey((Integer i1, Integer i2) -> i1 + i2);

    List<Tuple2<String, Integer>> output = counts.collect();
    for (Tuple2<?, ?> tuple : output) {
        System.out.println(tuple._1() + ": " + tuple._2());
    }
    ctx.stop();
}

核心步骤解析:

  1. 将本地文本文件路径作为参数传递给 Spark 任务
  2. SparkContext 是 Spark 的主入口点,通过 SparkConf 描述应用配置
  3. 使用 textFile 将文本文件读取为 JavaRDD
  4. 通过 flatMap 将每行拆分为单词并扁平化
  5. mapToPair 将每个单词映射为 (单词, 1) 的元组
  6. 通过 reduceByKey 聚合相同单词的计数
  7. 最后执行 collect 动作获取结果并打印

4.3. 执行 Spark 任务

用 Maven 构建项目,在 target 目录生成 apache-spark-1.0-SNAPSHOT.jar。提交词频统计任务:

${spark-install-dir}/bin/spark-submit --class com.baeldung.WordCount 
  --master local ${WordCount-MavenProject}/target/apache-spark-1.0-SNAPSHOT.jar
  ${WordCount-MavenProject}/src/main/resources/spark_example.txt

✅ 替换路径:

  • ${spark-install-dir}:Spark 安装目录
  • ${WordCount-MavenProject}:Maven 项目目录

提交后后台执行流程:

  1. 驱动程序中的 SparkContext 连接到集群管理器(本地独立模式)
  2. 集群管理器分配资源
  3. Spark 在集群节点上获取执行器进程
  4. 应用代码(JAR 文件)发送到执行器
  5. SparkContext 向执行器发送任务

最终结果返回驱动程序,输出词频统计:

Hello 1
from 2
Baeldung 2  # 原文中的 Baledung 应为 Baeldung
Keep 1
Learning 1
Spark 1
Bye 1

5. 总结

本文介绍了 Apache Spark 的架构和核心组件,并通过词频统计示例演示了 Spark 任务的开发与执行。Spark 的高性能和统一数据处理能力使其成为大数据领域的利器。

完整源码可在 GitHub 获取,如有问题可联系 spark-dev@example.com


原始标题:Introduction to Apache Spark