Apache Spark 是用于大规模数据处理的统一分析引擎。它提供 Java、Scala、Python 和 R 中的高级 API,以及支持通用执行图的优化引擎。它还支持一组丰富的高级工具,包括用于 SQL 和结构化数据处理的 Spark SQL 、用于 pandas 工作负载 的 Spark 上的 pandas API 、用于机器学习的 MLlib 、用于图形处理的GraphX以及 用于增量计算和流处理的结构化流。

一、基础知识
Spark特性:Spark使用简练优雅的Scala语言编写,基于Scala提供了交互式编程体验,同时提供多种方便易用的API。Spark遵循“一个软件栈满足不同应用场景”的设计理念,逐渐形成了一套完整的生态系统(包括 Spark提供内存计算框架、SQL即席查询(Spark SQL)、流式计算(Spark Streaming)、机器学习(MLlib)、图计算(Graph X)等),Spark可以部署在yarn资源管理器上,提供一站式大数据解决方案,可以同时支持批处理、流处理、交互式查询。
MapReduce计算模型延迟高,无法胜任实时、快速计算的需求,因而只适用于离线场景,Spark借鉴MapReduce计算模式,但与之相比有以下几个优势(快、易用、全面):
Spark提供更多种数据集操作类型,编程模型比MapReduce更加灵活;
Spark提供内存计算,将计算结果直接放在内存中,减少了迭代计算的IO开销,有更高效的运算效率。
Spark基于DAG的任务调度执行机制,迭代效率更高;在实际开发中MapReduce需要编写很多底层代码,不够高效,Spark提供了多种高层次、简洁的API实现相同功能的应用程序,实现代码量比MapReduce少很多。
Spark作为计算框架只是取代了Hadoop生态系统中的MapReduce计算框架,它任需要HDFS来实现数据的分布式存储,Hadoop中的其他组件依然在企业大数据系统中发挥着重要作用。
Spark的不足:虽然Spark很快,但现在在生产环境中仍然不尽人意,无论扩展性、稳定性、管理性等方面都需要进一步增强;同时Spark在流处理领域能力有限,如果要实现亚秒级或大容量的数据获取或处理需要其他流处理产品。
Cloudera旨在让Spark流数据技术适用于80%的使用场合,就考虑到这一缺陷,在实时分析(而非简单数据过滤或分发)场景中,很多以前使用S4或Storm等流式处理引擎的实现已经逐渐被Kafka+Spark Streaming代替;Hadoop现在分三块HDFS/MR/YARN,Spark的流行将逐渐让MapReduce、Tez走进博物馆;Spark只是作为一个计算引擎比MR的性能要好,但它的存储和调度框架还是依赖于HDFS/YARN,Spark也有自己的调度框架,但不成熟,基本不可商用
Spark 的核心优势与架构剖析
Spark 之所以能够在大数据领域脱颖而出,得益于其独特的架构设计和诸多优势。Spark 采用了弹性分布式数据集(Resilient Distributed Dataset,RDD)作为核心数据结构,RDD 是一个容错的、并行的数据结构,它允许用户在集群上进行内存计算和迭代式处理。这种设计使得 Spark 在处理迭代算法(如机器学习和图算法)时,性能远超传统的 MapReduce 框架。
从架构层面来看,Spark 主要由 Driver Program、Executor 和 Cluster Manager 组成。Driver Program 负责控制应用程序的执行,它会将任务分解为多个 Task,并分配给 Executor 执行;Executor 是实际执行任务的进程,每个 Executor 会占用一定的内存和 CPU 资源;Cluster Manager 则负责资源的管理和分配,常见的 Cluster Manager 有 Standalone、YARN 和 Mesos。

此架构图清晰展示了 Spark 各组件间的协作关系,Driver Program 作为控制中枢,与负责资源调配的 Cluster Manager 协同,将任务分发给 Executor 执行,帮助我们更好理解 Spark 运行机制。
作。
四、Spark概念/架构设计
RDD:是Resilient Distributed Dataset(弹性分布式数据集)的简称,是分布式内存的一个抽象概念,提供了一种高度受限的共享内存模型;
DAG:是Directed Acyclic Graph(有向无环图)的简称,反映RDD之间的依赖关系;
Executor:是运行在工作节点(WorkerNode)的一个进程,负责运行Task;
应用(Application):用户编写的Spark应用程序;
任务( Task ):运行在Executor上的工作单元 ;
作业( Job ):一个作业包含多个RDD及作用于相应RDD上的各种操作;
阶段( Stage ):是作业的基本调度单位,一个作业会分为多组任务,每组任务被称为阶段,或者也被称为任务集合,代表了一组关联的、相互之间没有Shuffle依赖关系的任务组成的任务集;
Spark运行架构包括集群资源管理器(Cluster Manager)、运行作业任务的工作节点(Worker Node)、每个应用的任务控制节点(Driver)和每个工作节点上负责具体任务的执行进程(Executor),资源管理器可以自带或使用Mesos/YARN;
一个应用由一个Driver和若干个作业构成,一个作业由多个阶段构成,一个阶段由多个没有Shuffle关系的任务组成;
当执行一个应用时,Driver会向集群管理器申请资源,启动Executor,并向Executor发送应用程序代码和文件,然后在Executor上执行任务,运行结束后,执行结果会返回给Driver,或者写到HDFS或者其他数据库中。
RDD的创建方式
-
由外部存储系统的数据集创建,包括本地的文件系统,还有Hadoop支持的文数据集,比如HDFS、HBase等
val rdd1 = sc.textFile("hdfs://node1:8020/wordcount/input/words.txt")
通过已有的RDD经过算子转换生成新的RDD
val rdd2=rdd1.flatMap(_.split(" "))
由一个已经存在的Scala集合创建
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的makeRDD方法底层调用了parallelize方法

RDD算子
RDD的算子分为两类
Transformation转换操作:返回一个新的RDD
Action动作算子:返回值不是RDD(无返回值或者返回其他的)
注意:
RDD不实际存储真正需要计算的数据,而是记录了数据的位置在哪里,数据的转换关系(调用了什么方法,以及传入了什么函数)
RDD中的所有转换都是惰性求值/延迟执行的,也就是说并不会直接进行计算。只有当发生一个要求返回结果给Driver的Action动作时,这些转换才会真正的运行
之所以使用惰性求值/延迟执行,是因为这样可以在Action时对RDD操作形成DAG有向无环图进行stage的划分和并行优化,这种设计可以使Spark更加有效率的运行
RDD的依赖关系
RDD存在两种依赖关系:宽依赖和窄依赖

在上图中我们可以发现:
窄依赖:父RDD的一个分区只会被子RDD的一个分区所继承
宽依赖:父RDD的一个分区会被子RDD的多个分区依赖,其中涉及到shuffle
对于窄依赖:
窄依赖的多个分区可以并行计算
窄依赖的一个分区的数据如果丢失只需要重新计算对应的分区数据就可以
对于宽依赖:
划分阶段(stage)的依据:对于宽依赖,必须等到上一阶段完成才能计算下一个阶段
DAG的生成和stage的划分
DAG
DAG(有向无环图):指的是数据转换执行的过程,有方向,无闭环(其实就是RDD的执行流程)
原始的RDD通过一系列的转换操作就形成了DAG有向无环图,任务执行时,可以按照DAG的描述,执行真正的计算
DAG的边界:
开始:通过SparkContext创建的RDD
结束:触发Action,一旦触发Action就形成了一个完整的DAG
Spark的底层执行原理
Spark的运行流程

具体的执行流程如下:
1.Spark Context向资源管理器注册并向资源管理器申请运行Exector
2.资源管理器分配 Executor,然后资源管理器启动Executor
3.Executor 发送心跳至资源管理器
4.Sparkcontext 构建DAG有向无环图
5.将DAG分解为Stage(TaskSet)
6.把Stage 发送给taskScheduler
7.Executor 向SparkContext 申请task
8.task Scheduler 将Task 发送给Executor 运行
9.TaskScheduler 将应用程序代码发放给 Executor
10.task 在Executor 上运行,运行完毕释放所有的资源
从代码角度来看DAG 图的构建
Val lines1 = sc.textFile(inputPath1).map(...).map(...)
Val lines2 = sc.textFile(inputPath2).map(...)
Val lines3 = sc.textFile(inputPath3)
Val dtinone1 = lines2.union(lines3)
Val dtinone = lines1.join(dtinone1)
dtinone.saveAsTextFile(...)
dtinone.filter(...).foreach(...)
1890

被折叠的 条评论
为什么被折叠?



