Module 03 · Apache Spark
Parallel Programming using Resilient Distributed Datasets并行编程与弹性分布式数据集(RDD)
欢迎观看《并行编程与弹性分布式数据集》视频!在观看完该视频后,您将能够:
- 定义弹性分布式数据集(RDD)
- 定义并行编程
- 解释 Apache Spark 中的弹性特性
- 将 RDD 和并行编程与 Apache Spark 联系起来
弹性分布式数据集(RDD)
弹性分布式数据集(Resilient Distributed Dataset,简称 RDD)是 Spark 的主要数据抽象。RDD 是一组容错的元素,分布在集群的各个节点上,能够接收并行操作。
RDD 的特性
- 容错性:RDD 是容错的,意味着即使集群中的某些节点失败,数据依然能够恢复。
- 不可变性:RDD 一旦创建,就不能被修改。每个操作都会生成一个新的 RDD,而不是改变原有的 RDD。
- 支持多种数据格式:RDD 支持文本文件、序列文件、Avro、Parquet 和 Hadoop 输入格式,还支持本地文件、Cassandra、HBase、HDFS、Amazon S3 等文件格式,以及多种关系型和 NoSQL 数据库。
创建 RDD
有三种方法可以创建 RDD:
- 使用外部文件:通过 Hadoop 支持的文件系统(如 HDFS、Cassandra、HBase 或 Amazon S3)加载外部文件。
- 使用 parallelize 函数:将现有的集合应用于 driver 程序中的 parallelize 函数。这可以在 Python、Java 或 Scala 等高阶 API 中进行。
- 例如,使用 Scala 或 Python 创建一个简单的 RDD。
- 代码片段展示了如何从现有集合(如列表)创建 RDD。
- 应用转换操作:在现有 RDD 上应用转换操作,从而创建一个新的 RDD。
RDD 和分区
当使用 parallelize 函数时,必须指定分区数,通常每个 CPU 使用 2 到 4 个分区。Spark 会自动根据集群大小设置分区数,当然,你也可以手动指定分区数。
并行编程
并行编程是同时使用多个计算资源来解决计算任务。并行编程将任务分解为独立的部分,并使用多个处理器同时解决这些任务。每个处理器访问共享的内存池,并配备控制和协调机制。
RDD 与并行编程
在 Spark 中,创建 RDD 就是将一个数组的对象或一个数据集分割成多个分区,然后将这些分区分配到各个节点上。每个节点负责一个分区,并行执行任务。这使得 RDD 可以本质上支持并行操作。
RDD 在 Spark 中的弹性特性
RDD 的弹性通过不可变性和缓存机制来实现:
- 不可变性:由于 RDD 是不可变的,数据一旦创建,就无法修改,因此具有很强的恢复能力。
- 缓存机制:RDD 可以将数据集保存在内存中,跨多个操作进行持久化。这种缓存是容错的,始终可以恢复,因为 RDD 是不可变的,并且 Hadoop 数据源本身也具有容错能力。
- 当持久化 RDD 时,每个节点会将计算出来的分区存储在内存中,并在后续的操作中重用相同的分区。这可以显著提高后续操作的速度,通常比不缓存的操作快 10 倍以上。
- 持久化是迭代算法和快速交互式应用的关键工具。
总结
在本视频中,您学到了:
- 可以通过外部或本地文件、集合或另一个 RDD 创建 RDD。
- RDD 是不可变的,始终可以恢复。
- 并行编程是同时使用多个计算资源来解决计算任务。
- RDD 可以在内存中持久化或缓存数据集,显著加速迭代操作。
一、RDD(弹性分布式数据集)的本质
RDD是Spark的核心数据抽象,代表一个不可变、可分区的分布式对象集合。
- 关键特性:
- Resilient(弹性):支持容错(通过血缘关系+数据重建机制)。
- Distributed(分布式):数据自动分片(Partition)并在集群节点间分布。
- Dataset(数据集):支持多种数据源(HDFS、S3、数据库等)。
- 架构意义:RDD是Spark实现数据并行和计算并行的基石,抽象了分布式计算的复杂性。
二、RDD的创建方式(与架构设计关联)
- 从外部数据源创建(如HDFS、S3):
- 数据自动分区,分区数影响并行度(默认按块大小或配置决定)。
- 架构启示:支持异构数据源集成,扩展性强。
- 并行化现有集合(
parallelize):
- 将本地集合(如List)转换为分布式RDD,可手动指定分区数(如
sc.parallelize(data, 4))。 - 分区策略:每个分区对应一个并行任务(Task),分区数决定并行粒度。
- 最佳实践:通常为每个CPU核心设置2-4个分区,避免资源空闲或调度开销。
- 通过转换操作生成新RDD(如
map、filter):
- RDD不可变(Immutable),任何转换都生成新RDD,形成血缘关系(Lineage)。
- 容错基础:血缘记录转换步骤,故障时可重新计算丢失的分区。
三、并行编程在Spark中的实现
- 并行本质:
- Spark将RDD数据分片(Partition)分布到集群节点,每个分区独立处理(无共享状态)。
- 任务并行:每个分区对应一个Task,由Executor并行执行(如右图所示)。
- 与传统并行的区别:
- 传统多线程:共享内存,需锁/同步机制(易死锁、竞争)。
- Spark并行:基于数据分区+无状态计算(避免竞争,简化并发设计)。
- 架构优势:
- 线性扩展:增加节点即可处理更大数据(无需改代码)。
- 隐式并行:开发者只需定义转换逻辑(如
rdd.map(f)),Spark自动并行化。
四、容错机制(Resilience)的实现原理
- 血缘关系(Lineage):
- RDD记录其生成依赖链(如
rdd3 = rdd2.map(f)←rdd2 = rdd1.filter(g))。 - 故障时,仅重新计算丢失的分区(而非全部数据),高效恢复。
- 持久化(Persist/Cache):
- 将RDD缓存到内存或磁盘,避免重复计算(尤其迭代算法如机器学习)。
- 容错性:即使缓存数据丢失,仍可通过血缘重新计算。
- 性能提升:缓存后后续操作加速10倍以上(减少I/O和计算开销)。
- 数据源容错:
- 若数据来自HDFS等可靠存储,可直接从源重新读取。
五、与系统架构设计的关联
- 分区策略影响性能:
- 过多分区 → 任务调度开销大;过少分区 → 资源利用不足。
- 需根据数据大小、集群资源动态调整(如
repartition操作)。
- 缓存策略选择:
- 内存充足时优先缓存到内存(
MEMORY_ONLY),否则序列化或落盘(权衡速度与资源)。
- 容错与一致性:
- RDD的不可变性+血缘机制提供最终一致性,适合批处理场景(非实时事务)。
- 扩展性设计:
- RDD模型天然支持横向扩展(增加节点),符合分布式系统设计原则。
六、备考重点总结
| 概念 | 架构意义 | 应用场景 |
|---|---|---|
| RDD不可变性 | 简化并发设计,支持容错和重现计算 | 迭代算法(如机器学习训练) |
| 数据分区 | 决定并行粒度,影响负载均衡和资源利用率 | 大数据ETL、分布式计算 |
| 血缘关系 | 轻量级容错机制,替代数据复制的高开销 | 故障恢复、计算优化 |
| 持久化 | 性能优化关键,减少重复计算和I开销 | 迭代查询、交互式分析 |
核心思想:RDD通过数据分区+转换血缘抽象了分布式计算的并行性和容错性,让开发者聚焦业务逻辑而非底层分布式细节。作为架构师,需理解分区策略、缓存机制和容错原理,以设计高效、可扩展的大数据系统。