解释:Spark 是当今大数据领域最活跃、最热门、最高效的大数据通用计算平台之一。
Spark 优势
-
优秀的数据模型和丰富计算抽象(
RDD) -
完善的生态圈
fullstack
Spark 特点
快: 与 Hadoop 的 MapReduce 相比,Spark 基于内存的运算要快 100 倍以上,基于硬盘的运算也要快 10 倍以上。Spark 实现了高效的 DAG 执行引擎,可以通过基于内存来高效处理数据流。
易用: Spark 支持 Java、Python、R 和 Scala 的 API,还支持超过 80 种高级算法,使用户可以快速构建不同的应用。而且 Spark 支持交互式的 Python 和 Scala 的 shell,可以非常方便地在这些 shell 中使用 Spark 集群来验证解决问题的方法。
通用: Spark 提供了统一的解决方案。Spark 可以用于批处理、交互式查询( Spark SQL )、实时流处理( Spark Streaming )、机器学习( Spark MLlib )和图计算( GraphX ),这些不同类型的处理都可以在同一个应用中无缝使用。
兼容性: Spark 可以非常方便地与其他的开源产品进行融合。比如,Spark 可以使用 Hadoop 的 YARN 和 Apache Mesos 作为它的资源管理和调度器,并且可以处理所有 Hadoop 支持的数据,包括 HDFS、HBase 和 Cassandra 等。这对于已经部署 Hadoop 集群的用户特别重要,因为不需要做任何数据迁移就可以使用 Spark 的强大处理能力。
Fullstack
Spark Core: 实现了 Spark 的基本功能,包含 RDD、任务调度、内存管理、错误恢复、与存储系统交互等模块。
Spark SQL: Spark 用来操作结构化数据的程序包。通过 Spark SQL,我们可以使用 SQL 操作数据。
Spark Streaming: Spark 提供的对实时数据进行流式计算的组件。提供了用来操作数据流的 API。
Spark MLlib: 提供常见的机器学习(ML)功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据导入等额外的支持功能。
GraphX(图计算): Spark 中用于图计算的 API,性能良好,拥有丰富的功能和运算符,能在海量数据上自如地运行复杂的图算法。
集群管理器: Spark 设计为可以高效地在一个计算节点到数千个计算节点之间伸缩计算。
Structured Streaming: 处理结构化流,统一了离线和实时的 API。
RDD(弹性分布式数据集)
解释:
RDD ( Resilient Distributed Dataset )叫做弹性分布式数据集,是 Spark 中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算的集合。
-
Resilient :它是弹性的,RDD 里面的中的数据可以保存在内存中或者磁盘里面;
-
Distributed : 它里面的元素是分布式存储的,可以用于分布式计算;
-
Dataset: 它是一个集合,可以存放很多元素。
| 对比维度 | MapReduce | RDD(Spark) |
|---|---|---|
| 数据模型 | 基于键值对的输入/输出模型,中间结果必须写入磁盘 | 弹性分布式数据集(分布式集合),支持多种操作和复杂数据流 |
| 中间数据存储 | 中间结果强制写入稳定文件系统(如 HDFS),产生大量磁盘 I/O 和序列化开销 | 支持将中间结果缓存到内存中,避免重复计算和磁盘 I/O |
| 容错机制 | 通过任务重试和数据复制实现容错 | 基于**血缘关系(Lineage)**重建丢失分区,无需数据复制 |
| 计算模式 | 批处理,仅支持 map → shuffle → reduce 两阶段模型 | 支持**有向无环图(DAG)**执行,可组合多个转换操作 |
| 适用场景 | 适合一次性、非迭代的大规模批处理 | 适合迭代计算 (如机器学习)、交互式查询 、图计算、流处理等复杂场景 |
| 性能 | 磁盘 I/O 多,延迟高,不适合频繁复用中间结果 | 内存计算为主,延迟低,中间结果可复用,性能显著提升(尤其在迭代场景) |
| API 表达能力 | API 较底层,表达复杂逻辑需多轮作业串联 | 提供丰富高层 API(map, filter, reduceByKey, join, groupBy 等),链式操作 |
| 数据复用效率 | 低:每次复用需重新读取 HDFS | 高:通过 persist() 或 cache() 显式缓存,多次使用无需重算 |
| 分区控制 | 分区策略固定,用户控制有限 | 用户可自定义分区策略,优化数据本地性和计算负载均衡 |
| 开发便捷性 | 编程模型较笨重,调试困难 | 类似操作本地集合,开发体验更友好,支持 Scala/Java/Python/SQL 等 |
RDD 的创建方式
- 由外部存储系统的数据集创建,包括本地的文件系统,还有所有
Hadoop支持的数据集,比如HDFS、Cassandra、HBase等
python
val rdd1 = sc.textFile("hdfs://node1:8020/wordcount/input/words.txt")
- 通过已有的 RDD 经过算子转换生成新的 RDD:
python
val rdd2=rdd1.flatMap(_.split(" "))
- 由一个已经存在的 Scala 集合创建:
python
val rdd3 = sc.parallelize(Array(1,2,3,4,5,6,7,8))
或者
val rdd4 = sc.makeRDD(List(1,2,3,4,5,6,7,8))
RDD的操作(算子)
-
Transformation: 将Scala集合或Hadoop输入数据构造一个新RDD、通过已有的RDD产生新的RDD(惰性执行:只记录转换关系,不触发计算)返回值: 返回一个新的 RDD
常见操作:
map、filter、flatmap、union、distinct、sortbykey -
Action: 通过计算得到一个值或一组值返回值: 返回值不是 RDD(无返回值或返回其他的)
常见操作:
first、count注意:
-
RDD不实际存储真正要计算的数据,而是记录了数据的位置在哪里,数据的转换关系(调用了什么方法,传入什么函数)。 -
RDD中的所有转换都是惰性求值/延迟执行的,也就是说并不会直接计算。只有当发生一个要求返回结果给Driver的Action动作时,这些转换才会真正运行。 -
之所以使用惰性求值/延迟执行,是因为这样可以在
Action时对RDD操作形成DAG有向无环图进行Stage的划分和并行优化,这种设计让Spark更加有效率地运行。
-
RDD依赖
窄依赖: 一个父PDD仅被一个子PDD使用,子PDD损坏时,只需要从对应父PDD重新计算恢复
宽依赖: 子PDD分区依赖父PDD的全部分区,子PDD部分损坏时,必须从所有父PDD分区重新计算
Spark调度流程
-
SparkContext向资源管理器注册并向资源管理器申请运行Executor -
资源管理器分配
Executor,然后资源管理器启动Executor -
Executor发送心跳至资源管理器 -
SparkContext构建 DAG 有向无环图 -
将 DAG 分解成 Stage(
TaskSet) -
把
Stage发送给TaskScheduler -
Executor向SparkContext申请Task -
TaskScheduler将Task发送给Executor运行 -
同时
SparkContext将应用程序代码发放给Executor -
Task在Executor上运行,运行完毕释放所有资源