搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > 写点代码 > 5分钟入门Spark

5分钟入门Spark

写点代码 2020-05-23
Spark 支持 Yarn 和 HDFS,公司迁移到 Spark 上的成本很小,于是很快,越来越多的公司用 Spark 代替 MapReduce。那么我们来了解一下Spark吧。我们主要Spark的编程模型和架构原理来认识Spark。
  • Spark 的编程模型

RDD 是 Spark 的核心概念,是弹性数据集(Resilient Distributed Datasets)的缩写。RDD 既是 Spark 面向开发者的编程模型,又是 Spark 自身架构的核心元素。

从编程模型的角度来看,Spark 则直接针对数据进行编程,将大规模数据集合抽象成一个 RDD 对象,然后在这个 RDD 上进行各种计算处理,得到一个新的 RDD,继续计算处理,直到得到最后的结果数据。我们在进行 Spark 编程的时候,思考的是一个 RDD 对象需要经过什么样的操作,转换成另一个 RDD 对象。RDD 上定义的函数分两种,一种是转换(transformation)函数,这种函数的返回值还是 RDD。其中,转换函数又分为两种,一种是转换操作产生的RDD,不会产生新的RDD,也就是说改写了这个RDD而已,比如map函数或者filter函数,这种也叫做惰性计算。一种是转换操作产生的RDD会产生新的分片,比如reduceByKey函数,来自不同分片的相同 Key 必须聚合在一起进行操作,这样就会产生新的 RDD 分片。另一种是执行(action)函数,这种函数不再返回 RDD。比如 count() 函数,返回 RDD 中数据的元素个数;saveAsTextFile(path),将 RDD 数据存储到 path 路径下。

从spark架构核心元素来看RDDSpark 分布式计算的数据分片、任务调度都是以 RDD 为单位展开的。与MapReduce相同,Spark也是对数据进行分片计算,每一个RDD分片会分配到一个执行进程去处理。需要注意的是,Spark 应用程序代码中的 RDD 和 Spark 执行过程中生成的物理 RDD 不是一一对应的。因为RDD的有些转换操作不会产生新的RDD,比如rdd2 = rdd1.map(func)这样的代码并不会在物理上生成一个新的 RDD。

  • Spark 的架构原理

首先和 MapReduce 一个应用一次只运行一个 map 和一个 reduce 不同,Spark 可以根据应用的复杂程度,分割成更多的计算阶段(stage),这些计算阶段组成一个有向无环图 DAGSpark 任务调度器可以根据 DAG 的依赖关系执行计算阶段。所谓 DAG 也就是有向无环图,就是说不同阶段的依赖关系是有向的,计算过程只能沿着依赖关系方向执行,被依赖的阶段执行完成之前,依赖的阶段不能开始执行,同时,这个依赖关系不能有环形依赖,否则就成为死循环了。

给个栗子:

从图上看,整个应用被切分成 3 个阶段,阶段 3 需要依赖阶段 1 和阶段 2,阶段 1 和阶段 2 互不依赖。Spark 在执行调度的时候,先执行阶段 1 和阶段 2,完成以后,再执行阶段 3。 只要根据程序初始化好 DAG,就建立了依赖关系,然后根据依赖关系顺序执行各个计算阶段,Spark 大数据应用的计算就完成了。
可以看到 Spark 作业调度执行的核心是 DAG ,有了 DAG,整个应用就被切分成哪些阶段,每个阶段的依赖关系也就清楚了。之后再根据每个阶段要处理的数据量生成相应的 任务集合(TaskSet) ,每个任务都分配一个任务进程去处理,Spark 就实现了大数据的分布式计算。具体来看的话,负责 Spark 应用 DAG 生成和管理的组件是 DAGScheduler,DAGScheduler 根据程序代码生成 DAG,然后将程序分发到分布式计算集群,按计算阶段的先后关系调度执行。

那么 Spark 划分计算阶段的依据是什么呢?

当 RDD 之间的转换连接线呈现多对多交叉连接的时候,就会产生新的阶段。一个 RDD 代表一个数据集,图中每个 RDD 里面都包含多个小块,每个小块代表 RDD 的一个分片。一个数据集中的多个数据分片需要进行分区传输,写入到另一个数据集的不同分片中,这种数据分区交叉传输的操作, 我们在 MapReduce 的运行过程中也看到过。

5分钟入门Spark

这就是 shuffle 过程 Spark 也需要通过 shuffle 将数据进行重新组合,相同 Key 的数据放在一起,进行聚合、关联等操作,因而每次 shuffle 都产生新的计算阶段。
如此看来,计算阶段划分的依据是 shuffle,不是转换函数。有些函数就不需要shuffle,比如上面的栗子从RDDA到RDDB,就没有shuffle。RDDB前一个阶段就进行了数据分区,分区数目和分区 Key 不变,就不需要再进行 shuffle。

5分钟入门Spark

这种不需要进行 shuffle 的依赖,在 Spark 里被称作 窄依赖 ;相反的,需要进行 shuffle 的依赖,被称作 宽依赖

既然MapReduce也有shuffle,为什么Spark更加高效呢?

  • Hadoop MapReduce 简单粗暴地根据 shuffle 将大数据计算分成 Map 和 Reduce 两个阶段,但 Spark 将前一个的 Reduce 和后一个的 Map 连接起来,当作一个阶段持续计算,形成一个高效地计算模型,虽然其本质依然是 Map 和 Reduce。这种多个计算阶段依赖执行的方案可以有效减少对 HDFS 的访问,减少作业的调度执行次数,因此执行速度也更快。

  • Hadoop MapReduce 主要使用磁盘存储 shuffle 过程中的数据不同,Spark 优先使用内存进行数据存储,包括 RDD 数据。Spark是遇到了一个好时代,内存的价格和容量都允许使用内存存储。

Spark 的 DAGScheduler 在遇到 shuffle 的时候,会生成一个计算阶段,在遇到 action 函数的时候,会生成一个作业(job)。RDD 里面的每个数据分片,Spark 都会创建一个计算任务去处理,所以一个计算阶段会包含很多个计算任务(task)。 DAGScheduler 根据代码生成 DAG 图以后,Spark 的任务调度就以任务为单位进行分配,将任务分配到分布式集群的不同机器上执行。
具体来说,主要分为以下四步:
  1. Spark 应用程序启动在自己的 JVM 进程里,即 Driver 进程,启动后调用 SparkContext 初始化执行配置和输入数据。SparkContext 启动 DAGScheduler 构造执行的 DAG 图,切分成最小的执行单位也就是计算任务。

  2. Worker 收到任务后,启动 Executor 进程开始执行任务。Executor 先检查自己是否有 Driver 的执行代码,如果没有,从 Driver 下载执行代码,通过 Java 反射加载后开始执行。


  • 小结

Spark 有三个主要特性:RDD 的编程模型更简单,DAG 切分的多阶段计算过程更快速,使用内存存储中间计算结果更高效Spark 也有自己的生态体系,以 Spark 为基础,有支持 SQL 语句的 Spark SQL,有支持流计算的 Spark Streaming,有支持机器学习的 MLlib,还有支持图计算的 GraphX。利用这些产品,Spark 技术栈支撑起大数据分析、大数据机器学习等各种大数据应用场景。


  • 参考资料:

李智慧老师《从0开始学习大数据》专栏模块二,图片都来自专栏。

版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《5分钟入门Spark》的版权归原作者「写点代码」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注写点代码微信公众号

写点代码微信公众号:gh_6ed966414c11

写点代码

手机扫描上方二维码即可关注写点代码微信公众号

写点代码最新文章

精品公众号随机推荐